중첩 클래스(Nested Class)
- 클래스 내에서 정의한 클래스
- 중첩 클래스를 사용하면 두 클래스의 멤버들을 서로 쉽게 접근할 수 있고, 외부에서는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있는 장점
- 독립적인 일반 클래스 형태로 작성할 필요는 없지만 나름대로 클래스 형태(멤버변수, 메서드, 생성자)를 갖춰야 할 때 사용
- 보통, 자신의 클래스 내에서만 접근 가능하도록 전용 클래스로 정의할 때 사용
=> 주로, GUI 구현 시 이벤트 처리를 위한 핸들러 클래스 정의 시 사용
- 외부클래스(Outer Class)와 내부클래스(Inner Class) 구분됨
- 내부클래스는 클래스 정의 위치에 따라 구분되며 클래스의 멤버로써 선언되는 중첩 클래스를 [멤버 클래스]라고 하며, 생성자 또는 메서드 내부에서 선언되는 중첩 클래스를 [로컬 클래스]라고 함
- 다시 멤버 클래스는 객체를 생성해야만 하는 1) 인스턴스 멤버 클래스와 클래스로 바로 접근할 수 있는 2) 정적 멤버 클래스로 구분할 수 있음
1) 인스턴스 멤버(내부) 클래스
- 멤버변수 및 메서드와 동일한 레벨에 정의한 클래스
- static 키워드를 지정하지 않은 클래스
- 인스턴스 멤버 변수(필드)와 메서드만 선언이 가능하고 정적 변수(필드)와 정적 메서드는 선언 불가
- 반드시 외부 클래스 인스턴스 생성 후 접근 가능
2) 정적 멤버(내부) 클래스
- 멤버변수 및 메서드와 동일한 레벨에 정의한 클래스
- static 키워드를 지정한 클래스
- 모든 종류의 필드와 메서드를 선언 가능
- 외부 클래스명만으로 접근 가능
3) 로컬 멤버(내부) 클래스 (=로컬 클래스)
- 클래스 내의 메서드 내에서 정의한 클래스
- 멤버 클래스의 경우 [바깥클래스$멤버클래스.class] 파일 생성
로컬 클래스의 경우 [바깥클래스$1로컬클래스.class] 파일 생성
< 중첩 클래스 기본 문법 >
class 바깥클래스명 {
class 안쪽클래스명 {
}
}
class Outer { // 바깥쪽 클래스(= 외부클래스, Outer Class)
private int num = 10; // 인스턴스 멤버변수
int num2 = 20; // 인스턴스 멤버변수
static int num3 = 30; // 정적 멤버변수
public void method() { // 인스턴스 멤버메서드
// 인스턴스 멤버메서드 내에서는 인스턴스 멤버변수 및 메서드에 대해
// 자유롭게 접근이 가능하다!
System.out.println("인스턴스 멤버변수 num = " + num);
method2();
}
public void method2() {
System.out.println("인스턴스 메서드 method2()");
}
public static void method3() { // 정적 메서드
// 정적 메서드 내에서는 인스턴스 멤버에 대한 접근 불가
// System.out.println("인스턴스 멤버변수 num = " + num); // 접근 불가
System.out.println("정적 멤버변수 num3 = " + num3); // 정적 멤버 접근 가능
}
1. 인스턴스 내부 클래스에 접근
=> 반드시 외부클래스의 인스턴스 생성 후 참조변수를 통해 내부클래스에 접근해야 한다!
// 인스턴스 멤버 내부클래스 정의
class Inner { // 중첩클래스(인스턴스 멤버(내부) 클래스)
int innerNum = 100;
// static int innerNum2 = 200;
// => The field innerNum2 cannot be declared static in a non-static inner type,
// unless initialized with a constant expression
// => 인스턴스 멤버 내부클래스에서는 static 변수를 선언할 수 없다!
public void innerMethod() {
System.out.println("외부클래스의 인스턴스 멤버변수 num = " + num);
method2();
// => 인스턴스 멤버 내부클래스에서는 외부클래스의 멤버에 자유롭게 접근 가능
// = 인스턴스 멤버 메서드에서의 접근 범위와 동일함
}
// public static void innerStaticMethod() {}
// => static 메서드도 선언 불가!
Outer outer = new Outer();
// 외부클래스를 통해 내부클래스의 인스턴스 생성할 경우
// 반드시 외부클래스명.내부클래스명 타입으로 변수를 지정
// 외부클래스참조변수명.new 내부클래스명() 형태로 인스턴스 생성
// Inner inner = new Inner();
// => 내부클래스명만으로는 접근을 할 수 없다!
Outer.Inner inner = outer.new Inner();
// => 참조변수 선언 시 패키지명을 생략하고 내부클래스타입으로도 선언이 가능
inner.innerMethod();
System.out.println(inner.innerNum);
2. 정적 멤버 내부 클래스 접근
=> 정적 내부 클래스는 static 키워드가 적용되어 있으므로 클래스가 메모리에 로딩될 때 정적 내부 클래스도 함께 로딩됨
따라서, 내부 클래스 접근 문법은 외부클래스 인스턴스 생성 없이 외부 클래스 명만으로 접근 가능
// 정적 멤버 내부클래스 정의
static class StaticInner {
int innerNum = 10;
static int innerStaticNum = 20;
public void innerMethod() {
// System.out.println("외부클래스의 인스턴스 멤버변수 num = " + num);
// => 외부클래스의 멤버변수 접근 불가능
// => 정적 멤버 내부클래스에서는 외부클래스의 인스턴스 멤버에 접근 불가!
// (메모리 로딩 시점이 다르기 때문(= 정적 메서드와 규칭 동일)
// method2();
System.out.println("외부클래스의 정적 멤버변수 num3 = " + num3);
}
public static void innerStaticMethod() {
// System.out.println("내부클래스의 인스턴스 멤버변수 innerNum = " + innerNum);
System.out.println(
"내부클래스의 인스턴스 멤버변수 innerStaticNum = " + innerStaticNum);
}
// => 외부클래스명.내부클래스명 참조변수명 = new 외부클래스명.내부클래스명();
Outer.StaticInner staticInner = new Outer.StaticInner();
System.out.println(staticInner.innerNum);
중첩 인터페이스(Nested Interface)
- 클래스의 멤버로 선언된 인터페이스
- 클래스 내부에 인터페이스를 선언하는 이유는 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위함
- 인스턴스 멤버 인터페이스와 정적(static) 멤버 인터페이스 모두 구현 가능
- 인스턴스 멤버 인터페이스는 바깥 클래스 객체가 있어야 사용 가능하며 정적 멤버 인터페이스는 바깥 클래스의 객체 없이 바깥 클래스명만으로 접근 가능
- 주로 정적 멤버 인터페이스를 많이 사용하는데 UI 프로그래밍에서 이벤트를 처리하는 목적으로 많이 활용됨
< 중첩 인터페이스 기본 문법 >
class 바깥쪽클래스명 {
[static] interface 안쪽인터페이스명 {
}
}
// 클릭 시 이벤트를 처리하는 클래스 Button 정의
class Button { // 바깥쪽 클래스(Outer Class)
static interface OnClickListener { // 중첩 인터페이스 정의(Inner Interface)
void onClick(); // 추상메서드
}
OnClickListener listener; // 인터페이스 타입 변수(필드) 선언
public void setOnClickListener(OnClickListener listener) {
// 다형성을 위한 OnClickListener 매개 변수 선언
this.listener = listener;
}
public void touch() {
listener.onClick();
}
}
// OnClickListener 인터페이스를 구현(implements) 하는 구현 클래스 정의
// => 전화걸기 버튼 터치의 경우
class CallListener implements Button.OnClickListener {
@Override
public void onClick() {
System.out.println("전화를 겁니다!");
}
}
// OnClickListener 인터페이스를 구현(implements) 하는 구현 클래스 정의
// => 문자보내기 버튼 터치의 경우
class MessageListener implements Button.OnClickListener {
@Override
public void onClick() {
System.out.println("문자를 보냅니다!");
}
}
Button btn = new Button(); // 바깥쪽 클래스의 인스턴스 생성
// 다형성을 통한 객체 변경
btn.setOnClickListener(new CallListener());
btn.touch();
btn.setOnClickListener(new MessageListener());
btn.touch();
'⛏️ > JAVA' 카테고리의 다른 글
[JAVA] 42. 람다식(Lambda Expressions) (0) | 2023.11.24 |
---|---|
[JAVA] 41. 익명(anonymous) 객체 (0) | 2023.11.24 |
[JAVA] 39. Scanner (0) | 2023.11.07 |
[JAVA] 38. 예외(Execption) (1) | 2023.11.07 |
[JAVA] 37. Collection Framework(컬렉션 프레임워크) (0) | 2023.10.31 |