inner class
이너 클래스
Inner 클래스를 만드는 이유
● 은닉 - 클래스는 default나 public만 가능한데 이너클래스는 private으로 만들 수 있다. 그래서 자기 패키지 안의 자기 클래스에서만 볼 수 있다.
중첩 클래스와 중첩 인터페이스
클래스가 여러 클래스와 관계를 맺는 경우에는 독립적으로 선언하는 것이 좋으나, 특정 클래스와 관계를 맺을 경우에는 관계 클래스를 클래스 내부에 선언하는 것이 좋다.
중첩 클래스가 바로 그 경우인데 중첩 클래스를 사용하면 두 클래스의 멤버들을 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다.
인터페이스도 클래스 안에 들어갈 수 있는데 이를 중첩 인터페이스라고 한다.
중첩 인터페이스
중첩 클래스는 클래스 내부에 선언되는 위치에 따라서 두 가지로 분류된다.
-
클래스의 멤버로서 선언되는 중첩 클래스를
멤버 클래스
- 클래스나 객체가 사용중이라면 언제든지 재사용 가능하다.
- 바이트 코드의 이름은
A(바깥 클래스 이름) $ B(멤버 클래스 이름).class
- 인스턴스 멤버 클래스(그냥)는 바깥 클래스의 객체를 생성해야만 접근할 수 있고, 정적 멤버 클래스(static) 바깥 클래스로 바로 접근할 수 있는 중첩 클래스다.
class A{
class B{
B() {} //생성자
int field1;
}
static class C{
C() {}
int field2;
static int field3;
}
//인스턴스 객체를 생성하려면
A a = new A();
A.B b = a.new B();
b.field1 = 3;
//정적 멤버 클래스 객체를 생성하려면
A.C c = new A.C();
c.field2 = 4;
A.C.field3 = 4;
-
메소드 내부에서 선언되는 중첩 클래스를
로컬 클래스
- 메소드 실행 시에만 사용, 메소드가 종료되면 없어진다.
- 바이트 코드의 이름은
A(바깥 클래스 이름) $1 B(로컬 클래스 이름).class
- 메소드 내에서 객체를 생성(
D d = new D();
)하고 할당해주면 된다.
당연하게 중첩 클래스에는 접근 제한이 있는데 이는 static이 먼저 메모리에 올라가서 인스턴스가 static에 접근할 수 없다는 것만 이해하면 쉽게 이해할 수 있다.
중첩 인터페이스
Button을 클릭했을 때 이벤트를 처리하는 객체를 받고 싶다고 가정해보자. 그렇다고 아무 객체나 받으면 안 되고, Button 내부에 선언된 중첩 인터페이스를 구현한 객체만 받아야 한다면 아래와 같이 Button 클래스를 선언하면 된다.
public class Button{
//중첩 인터페이스 타입으로 필드를 선언
OnClickListener listener;
//setter 메소드로 구현 객체를 받아 필드에 대입.
//Button btn = new Button();
//btn.setOnClickListener(new MessageListener()); 같이 호출.
void setOnClickListener(OnClickListener listener){
this.listener = listener;
}
//touch 메소드가 실행되었을 때 onClick() 메소드 호출
void touch(){
listener.onClick();
}
//중첩 인터페이스.
interface OnClickListener {
void onClick();
}
}
#