[JAVA] 중첩 클래스와 중첩 인터페이스
자바의 중첩 클래스와 인터페이스에 관한 스터디 메모
[JAVA] 중첩 클래스와 중첩 인터페이스
✏️ 중첩 클래스
중첩 클래스란, 클래스 내부에 선언한 클래스이다.
- 중첩 클래스를 사용하면 두 클래스의 멤버들을 쉽게 접근할 수 있다.
- 여러 클래스와 관계를 맺는 경우는 독립적인 클래스를 선언하는 것이 좋지만, 특정 클래스와 관계를 맺는 경우 중첩 클래스가 좋다.
- 중첩 클래스는 멤버 클래스와 로컬 클래스로 나뉜다.
1. 멤버 클래스
멤버 클래스는 클래스의 멤버로서 선언된 중첩 클래스이다.
멤버 클래스는 인스턴스 멤버 클래스와 정적 멤버 클래스로 나뉜다.
인스턴스 멤버 클래스
- static 키워드 없이 선언된 중첩 클래스
- 인스턴스 필드, 메소드만 선언 가능
- Why? 정적 필드와 메소드는 객체 생성 없이도 실행 가능해야하기 때문
1
2
3
4
5
6
7
8
9
10
11
12
Class A{
Class B{
B(){} // 생성자
int fieldB; // 인스턴스 필드
void methodB() { }; // 인스턴스 메소드
/*
static int field;
static void method() { }; 는 정적 필드와 메소드이므로 선언 불가능
*/
}
}
A 클래스 내부에서 B 클래스를 사용하는 경우, 일반 클래스처럼 B 객체를 생성해서 사용한다.
1
2
3
4
5
6
7
8
9
10
Class A{
Class B{
...
}
void methodA(){
B b = new B();
b.fieldB = 3;
b.methodB();
}
}
A 클래스 외부에서 B 클래스를 사용하고 싶은 경우, A 객체 생성 후 B 객체를 생성해야 한다. 하지만, 일반적으로 A 클래스 외부에서 B 클래스를 사용하는 경우는 없다.
1
2
3
4
// A 클래스 외부
A a = new A();
A.B b = a.new B();
//
정적 멤버 클래스
- static 키워드로 선언된 클래스
- 모든 종류의 필드와 메소드 선언 가능
1
2
3
4
5
6
7
8
9
10
11
Class A{
Class C{
C(){} // 생성자
int fieldC; // 인스턴스 필드
void methodC; // 인스턴스 메소드
static int field; // 정적 필드
static void method() { }; // 정적 메소드
}
}
A 클래스 외부에서 C 클래스를 사용하는 경우
1
2
3
4
5
6
A.C c = new A.C();
c.fieldC = 3;
c.method();
A.C.field = 3;
A.C.method() { }
2. 로컬 클래스
로컬 클래스는 생성자 또는 메소드 내부에서 선언된 중첩 클래스이다.
- 로컬 클래스는 접근 제한자 및 static을 붙일 수 없다. –> 메소드 내부에서만 사용되기 때문
- 정적 필드와 메소드는 선언할 수 없다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void method(){
// 생성자 또는 메소드 내부에서
class D{
D(){ }
int fieldD;
void methodD() { }
/*
static int field
static void method() { } 는 정적 필드와 메소드이므로 선언 불가
*/
}
D d = new D();
d.fieldD = 3;
d.mehtodD();
}
✏️ 중첩 클래스의 사용 제한
[바깥쪽 –> 안쪽]
1. Outter 클래스 –> 인스턴스 멤버 클래스
- 인스턴스 멤버 객체를 정적 필드로 선언 불간능
- 정적 메소드에서 인스턴스 멤버 객체를 사용 불가능
- Outter 클래스의 인스턴스가 없으면 인스턴스 멤버 클래스의 인스턴스도 생성할 수 없기 때문
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public class A{ class B{ } // 인스턴스 멤버 클래스 B field = new B(); void methodA(){ B var = new B(); } /* static B field = new B(); static void methodSt(){ B var = new B(); } B의 객체를 정적 필드나 정적 메소드의 변수로는 사용 못함 */ }
2. Outter 클래스 –> 정적 멤버 클래스
- 인스턴스 멤버 객체를 정적 필드로 선언 가능
- 정적 메소드에서 인스턴스 멤버 객체를 사용 가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class A{
static class C{ } // 정적 멤버 클래스
C field = new C();
void methodA(){
C var = new C();
}
static C field2 = new C();
static void methodSt(){
C var2 = new C();
}
}
3. Outter 클래스–> 로컬 클래스
- 접근 불가능
[ 안쪽 –> 바깥쪽]
1. 인스턴스 멤버 클래스–> Outter 클래스
- 제한 없음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A{
int fieldA;
void methodA() {}
static int fieldAS;
static void methodAS() {}
// Inner --> Outter 접근
class B{
void methodB(){
fieldA = 3;
methodA();
fieldAS = 3;
methodAS();
}
}
}
2. 정적 멤버 클래스–> Outter 클래스
- Outter 클래스의 정적 멤버에만 접근 가능
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
class A{ int fieldA; void methodA() {} static int fieldAS; static void methodAS() {} // Inner --> Outter 접근 static class C{ void methodB(){ /* fieldA = 3; methodA(); 인스턴스 필드와 메소드에는 접근 불가 static class C는 A 객체 생성 없이도 사용 가능해야 하기 때문이다. */ fieldAS = 3; methodAS(); } } }
3. 로컬 클래스–> Outter 클래스
- 로컬 클래스는 메소드 실행이 종료되면 없어져야 함.
- ⚠️ BUT!! 메소드가 종료되어도 존재하는 경우가 있음 - 로컬 스레드 객체
- 위의 문제를 해결하기 위해, 컴파일 시 로컬 클래스의 변수를 로컬 클래스 내부에 복사해 둔다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Outter{
public void method(int arg){
int localVaribale = 1;
class Inner{
public void methodI(){
int result = arg + localVariable;
/*
로컬 클래스에서 사용하는 Outter 클래스의 변수 arg, localVariable
두 변수의 값은 로컬 클래스 내부에 복사됨
복사된 값과 Outter의 변수 값이 달라지면 안되므로, 변수의 값 수정 불가능
*/
}
}
}
}
arg, localvariable 변수는 값이 달라져서는 안된다. –> final로 선언해야 한다.
하지만, Java 8부터는 final 키워드를 붙이지 않아도 자동으로 final 특성이 부여된다.
✏️ 중첩 인터페이스
중첩 인터페이스란, 클래스의 멤버로 선언된 인터페이스이다.
- 클래스 내부에 선언하는 이유는, 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해서다.
- 중첩 인터페이스의 종류로는 인스턴스 멤버 인터페이스와 정적 멤버 인터페이스가 있다.
- 주로 정적 멤버 인터페이스를 사용하여 UI 프로그래밍에서 이벤트를 처리한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Button{
// 중첩 인터페이스 OnClickListener
static interface OnClickListener{
void onClick(); // 구현 클래스는 반드시 onClick을 구현해야 한다.
}
OnClickListener listener;
void setOnClickListener(OnClickListener listener){
this.listener = listener;
}
void touch(){
listener.onClick();
}
}
1
2
3
4
5
6
7
// 구현 클래스
public class CallListener implements Button.OnClickListener{
@Override
public void onClick(){
System.out.println("calling");
}
}
1
2
3
4
5
6
7
8
9
10
// 실행 클래스
public class Execute{
public static void main(String[] args){
Button btn = new Button();
btn.setOnClickListener(new CallListener());
// 중첩 인터페이스 OnClickListener를 구현한 객체만 인수로 쓸 수 있음
btn.touch();
}
}
REFERENCE
혼자 공부하는 자바
This post is licensed under
CC BY 4.0
by the author.