OOP(4) : 내부 클래스

부트캠프(END)/Java|2022. 6. 3. 21:41

갈수록 정리하는 데 시간이 오래 걸리는군...

객체 지향 프로그래밍(OOP: Object-Oriented Programming)

1. 데이터 보호

패키지 / 접근제어자 / 캡슐화

2. 재사용

변경해서 사용(상속 : is-a) / 그대로 사용(포함 : has-a)

3. 다형성

오버라이딩 / 오버로딩 

4. 형변환

5. 추상 클래스 / 인터페이스 

+5 내부 클래스 ← 오늘은 여기! 

6. 예외처리


내부 클래스

아래와 같이 클래스 내에 선언되는 클래스이다. 대신 객체 생성이 번거로워짐.

class A { //외부 클래스
	...
	class b{ //내부 클래스
		...
	}
}

 

두 클래스가 서로 관계가 있을 때 서로 쉽게 접근할 수 있도록 하고, 외부에는 불필요한 클래스를 감추는 데 이용한다.

static클래스만 static 멤버를 정의할 수 있다.

⇢ 단, final static은 상수이므로 모든 내부 클래스에서 허용된다.

 

변수처럼 선언 위치에 따라 내부 클래스의 종류가 나눠진다.

내부 클래스의 종류와 특징
인스턴스 클래스
(instance class)
외부 클래스의 멤버 변수 선언 위치에 선언 /  외부 클래스의 인스턴스멤버처럼 쓰임
주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 이용
스태틱 클래스
(static class)
외부 클래스의 멤버 변수 선언 위치에 static으로 선언 / 외부 클래스의 static 멤버처럼 쓰임
주로 외부 클래스의 static멤버, 특히 static 메서드에서 사용
지역 클래스
(local class)
외부 클래스의 메서드나 초기화 블록 안에 선언 / 선언된 영역 내에서만 사용
익명 클래스
(anonymous class)
클래스의 선언과 객체의 생성을 동시에 하는 이름 없는 클래스(1회용)

 

인스턴스 클래스(멤버 클래스)

외부 클래스와 스태틱 클래스의 인스턴스 멤버를 객체 생성 없이 바로 사용할 수 있다.

Outer1과 Inner1이 서로 변수와 메서드를 자유롭게 사용할 수 있다.

private 멤버도 접근이 가능하다! ↓ 외부 클래스의 private String name에 접근한 걸 볼 수 있음.

class Outer1 {
    private String name = "kimdoodoo";
    class Inner1 {
        int a = 10;
        public void print() {
            System.out.println("Inner:print() Call..:name=" + name);
        }
    }
}
public class Ex1 {
    public static void main(String[] args) {
        Outer1 o1 = new Outer1();
        Outer1.Inner1 i1 = o1.new Inner1();
        System.out.println(i1.a); //10
        i1.print(); //Inner:print() Call..name=kimdoodoo
    }
}
class Outer{
	int value = 10;
	public void display() {
		Inner i = new Inner(); 
		i.method();
	}
	//Inner 클래스는 Outer의 메서드를 제어
	class Inner{
		int value = 20;
		public void method() {
			int value = 30;
			System.out.println("value="+value);
			//지역변수 우선순위=>30
			System.out.println("this.value="+this.value); //20
			System.out.println("Outer.value="+Outer.this.value);//10
		}
	}
}
public class Ex3 {
	public static void main(String[] args) {
		Outer o = new Outer();
		Outer.Inner i = o.new Inner();
		i.method();
	}
}

스테틱 클래스(멤버 클래스)

외부 클래스와 인스턴스 클래스의 인스턴스 멤버를 객체 생성 없이 사용할 수 없다.

인스턴스 클래스와 달리 Outer2의 생성자 사용 없이 내부 클래스의 객체를 생성할 수 있음.

*Outer1.Inner1 i1 = new Outer1.Inner1() < 에러 난다.

class Outer2 {
    static class Inner2 {
        public void print() {
            System.out.println("Inner:print() Call..");
        }
    }
}
public class Ex1 {
    public static void main(String[] args) {
        Outer2.Inner2 i2 = new Outer2.Inner2();
        i2.print();//Inner:print() Call..
    }
}

지역 클래스

외부 클래스의 메서드나 초기화 블록 안에 선언하여 선언된 영역 내에서만 사용 가능하다.

지역 클래스는 외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있다.

+ 지역 클래스가 포함된 메서드에 정의된 지역 변수도 final에 한해 사용 가능하다.

→ 메서드가 수행을 마치고 지역 변수가 소멸된 시점에도 지역 클래스의 인스턴스가

소멸된 지역 변수를 참조하려는 경우가 발생할 수 있기 때문이다.

class Outer3 {
    public void print() {
        class Inner3 {
            public void print() {
                System.out.println("지역 클래스:Inner:print() Call..");
            }
        }
        Inner3 i = new Inner3();
        i.print();
    }
}
public class Ex1 {
    public static void main(String[] args) {
        Outer3 o3 = new Outer3();
        o3.print(); //지역 클래스:Inner:print() Call..
    }
}

익명 클래스

클래스의 선언과 객체의 생성을 동시에 해서 이름이 없다.

딱 한 번만 사용될 수 있고, 하나의 객체만을 생성할 수 있는 1회용 클래스.

이름이 없다 = 생성자를 가질 수 없다.

class Outer4 {
    Inner4 in = new Inner4() { //익명 클래스
        public void print() {
            System.out.println("Outer4:print() Overrriding..");
        }
    };
}
class Inner4 {
    public void print() {
        System.out.println("Inner4:print() Call..");
    }
}
public class Ex1 {
    public static void main(String[] args) {
        Inner4 i4 = new Inner4();
        i4.print(); //Inner4:print() Call..
        Outer4 o4 = new Outer4();
        o4.in.print(); //Outer4:print() Overrriding..
    }
}

 

실습예제

Server.class

package day24.server;

import java.net.*;
import java.util.*;
import java.io.*;

public class Server implements Runnable {
    private ServerSocket ss;
    private final int PORT = 3355;
    private Vector < Client > waitVc = new Vector < Client > ();

    //Server (접속 담당)
    public Server() {
        try {
            ss = new ServerSocket(PORT);
            System.out.println("Server Start...");
        } catch (Exception ex) {}
    }

    @Override
    public void run() {
        while (true) {
            try {
                Socket s = ss.accept();
                //클라이언트가 접속하면 아이피를 받아오는 메서드 
                Client client = new Client(s);
                System.out.println(s.getPort());
                System.out.println(s.getInetAddress().getHostAddress());
                waitVc.add(client);
                client.start();
            } catch (Exception ex) {}
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        new Thread(server).start();
        //		s.run();
    }

    //Client (통신 담당) 내부 클래스!
    class Client extends Thread {
        Socket s;
        OutputStream out;
        BufferedReader in ;
        public Client(Socket s) {
            try {
                this.s = s;
                out = s.getOutputStream(); in = new BufferedReader(
                new InputStreamReader(s.getInputStream()));
            } catch (Exception ex) {}
        }
        public void run() {
            while (true) {
                try {
                    String msg = in .readLine();
                    for (Client c: waitVc) {
                        //인스턴스 내부클래스 
                        c.out.write((msg + "\n").getBytes());
                    }
                } catch (Exception ex) {}
            }
        }
    }

}

Client.class

package day24.client;
import java.util.*;
import java.net.*;

public class Client {
	public static void main(String[] args) {
		try {
			Socket s = new Socket("localhost",3355);
		}catch(Exception ex) {}
	}
}

댓글()