중첩 클래스 (Nested Class)
중첩 클래스 장점
중첩 클래스 종류
선언 위치에 따른 분류 | 선언 위치 | 객체 생성 조건 |
---|---|---|
멤버 클래스 - 인스턴스 멤버 클래스 | class A { | A 객체를 생성해야만 B 객체를 생성할 수 있음 |
멤버 클래스 - 정적 멤버 클래스 | class A { | A 객체를 생성하지 않아도 B 객체를 생성할 수 있음 |
로컬 클래스 | class A { | method가 실행해야만 B 객체를 생성할 수 있음 |
중첩 클래스의 바이트코드 파일
A $ B .class
A $1 B .class
인스턴스 멤버 클래스
[public] class A {
//B는 인스턴스 멤버 클래스
[public | private] class B {
}
}
A a = new A();
A.B b = a.new B();
접근 범위
public class B {}
: 다른 패키지에서 B 사용 가능class B {}
: 같은 패키지에서만 B 사용 가능private class B {}
: A 클래스 내부에서만 B 사용 가능인스턴스 멤버 클래스 예시
public class A {
//인스턴스 멤버 클래스
class B {
//인스턴스 필드
int filed1 = 1;
//정적 필드(Java17~)
static int field2 = 2;
//생성자
B() {
System.out.println("B 생성자");
}
//인스턴스 메소드
void method1() {
System.out.println("B method1")
}
//정적 메소드(Java17~)
void static method2() {
System.out.println("B method2")
}
}
//여기부터는 A
//인스턴스 필드 값으로 B 객체 대입
B field = new B();
//A 생성자
A() {
B b = new B();
}
//인스턴스 메소드
void useB() {
//B 객체 생성 및 인스턴스 필드 및 메소드 사용
B b = new B();
System.out.printIn(b.field1);
b.method1();
//B 클래스의 정적 필드 및 메소드 사용
System.out.println(B.filed2);
B.method2();
}
}
정적 멤버 클래스
[public] class A {
[public | private] static class B {
}
}
//A a = new A(); 없어도 됨
A.B b = new A.B();
접근 범위
public static class B {}
: 다른 패키지에서 B 사용 가능static class B {}
: 같은 패키지에서만 B 사용 가능private static class B {}
: A 클래스 내부에서만 B 사용 가능정적 멤버 클래스 예시
public class A {
//정적 멤버 클래스
static class B {
//인스턴스 필드
int filed1 = 1;
//정적 필드(Java17~)
static int field2 = 2;
//생성자
B() {
System.out.println("B 생성자");
}
//인스턴스 메소드
void method1() {
System.out.println("B method1")
}
//정적 메소드(Java17~)
void static method2() {
System.out.println("B method2")
}
}
//여기부터는 A
//인스턴스 필드 값으로 B 객체 대입
B field = new B();
//정적 필드 값으로 B 객체 대입
static B field2 = new B();
//A 생성자
A() {
B b = new B();
}
//인스턴스 메소드
void useB() {
//B 객체 생성 및 인스턴스 필드 및 메소드 사용
B b = new B();
System.out.printIn(b.field1);
b.method1();
//B 클래스의 정적 필드 및 메소드 사용
System.out.println(B.filed2);
B.method2();
}
//정적 메소드
static void useB2() {
B b = new B();
}
}
로컬 클래스 (Local class)
//A 내부에서 B 사용
public class A {
//생성자
public A() {
// 로컬 클래스 선언
class B { ... }
//로컬 객체 생성
B b = new B();
}
//메소드
void method() {
//로컬 클래스 선언
class B { ... }
//로컬 객체 생성
B b = new B();
}
}
//A의 메소드 내부에 있으니 A 객체 필요
A a = new A();
a.method();
로컬 변수를 로컬 클래스에서 사용할 경우
public class A {
//매개변수에 선언된 변수 arg (로컬 변수)
public void method1(int arg) {
//내부에서 선언된 변수 (로컬 변수)
int var = 1;
//로컬 클래스
class B {
void method2() {
//로컬 변수 읽기 가능
System.out.println(arg);
System.out.println(var);
//로컬 변수 수정 불가
//arg = 2;
//var = 2;
}
}
B.b = new B();
b.method();
//로컬 변수 수정 불가
//arg = 2;
//var = 2;
}
}
바깥 클래스의 멤버 접근 제한
바깥 클래스의 객체 접근
바깥클래스이름.this
public class A {
int field1;
int field2;
void method1() {}
void method2() {}
class B {
int field2;
void method2() {}
void example() {
//동일하지 않은 이름
field1 = 10;
method1();
//동일한 이름
//B의 필드와 메소드 사용
System.out.println(this.field2);
this.method2();
//A의 필드와 메소드 사용
System.out.println(A.this.field2);
A.this.method2();
}
}
}
중첩 인터페이스
class A {
[public | private] [static] interface B {
//상수 필드
//추상 메소드
//디폴트 메소드
//정적 메소드
}
}
예시
public class Button {
//정적 멤버 인터페이스
public static interface ClickListener {
//추상 메소드
void onClick();
}
//필드
private ClickListener clickListener;
//메소드
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public void click() {
this.clickListener.onClick();
}
}
public class ButtonExample {
public static void main(String[] args) {
//ok버튼 객체 생성
Button btnOk = new Button();
//Ok 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
class OkListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("Ok 버튼 클릭")
}
}
//Ok 버튼 객체에 ClickListener 구현 객체 주입
btnOk.setClickListener(new OkListener());
btnOk.click(); //Ok 버튼 클릭 출력
//---------------------------------
//Cancel버튼 객체 생성
Button btnCancel = new Button();
//Ok 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
class CancelListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("Cancel 버튼 클릭")
}
}
//Cancel 버튼 객체에 ClickListener 구현 객체 주입
btnCancel.setClickListener(new CancelListener());
btnCancel.click(); //Ok 버튼 클릭 출력
}
}
익명 객체
익명 자식 객체
=> 따로 자식 객체를 여러 개 만들지 않고 부모 객체 안에서 다 정의
new 부모생성자(매개값, ... ) {
//필드
//메소드
}
익명 구현 객체
=> 구현 객체를 따로 만들지 않고, 인터페이스 구현을 통해 정의
new 인터페이스() {
//필드
//메소드
}