열한번째날 [중첩 클래스와 중첩 인터페이스]
중첩클래스 = 내부클래스 : 클래스 안의 클래스
목차
1. 중첩 클래스와 중첩 인터페이스란?
2. 중첩 클래스
3. 중첩 클래스의 접근 제한
4. 중첩 인터페이스
5. 익명 객체
1. 중첩 클래스와 중첩 인터페이스란?
* 중첩 클래스(Nested Class)
- 클래스가 여러 클래스와 관계를 맺을 경우 : 독립적 선언
- But 특정 클래스와 관계를 맺을 경우 : 관계 클래스를 클래스 내부에 선언 ➡️ 중첩 클래스(Nested Class)
*클래스가 다른 클래스에서 가져다 쓰려면 상속, 객체 생성 등 필요한데,
중첩 클래스에선 그 클래스 안에 있는 모든 것들을 마음대로 가져다 쓸 수 있기 때문에 중첩 클래스를 사용한다.
* 장점
- 두 클래스의 멤버들을 서로 쉽게 접근할 수 있음
- 외부에 불필요한 관계 클래스를 감추며 코드의 복잡성을 줄일 수 있음
* 중첩 클래스 : 클래스 블록 안에 들어간 클래스
class A{
class B{ ... }
}
* 중첩 인터페이스 : 클래스 블록 안에 들어간 인터페이스
- 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해서
- UI 컴포넌트 내부 이벤트 처리에 많이 활용
class A{
interface B{...}
}
2. 중첩 클래스
* 중첩 클래스의 분류
선언 위치에 따른 분류 | 선언 위치 | 설명 | |
멤버 클래스 | 인스턴스 멤버 클래스 |
class A{ class B {...} } |
A 객체를 생성해야만 사용할 수 있는 B 중첩 클래스 |
정적 멤버 클래스 |
class A{ static class B{...} } |
A 클래스로 바로 접근할 수 있는 B 중첩 클래스 |
|
로컬 클래스 | class A{ void method(){ class B{...} } } |
method()가 실행할 때만 사용할 수 있는 B 중첩 클래스 |
- 멤버 클래스 : 인스턴스 멤버 클래스 : 필드,생성자, 메소드 자리에 들어가는 클래스
- 멤버 클래스 : 정적 멤버 클래스 : 위에랑 똑같은데 static 붙은거
- 로컬 클래스 : 메소드 안에 들어간 클래스
* 멤버 클래스 바이트 코드 파일 이름 : $ 포함
* 로컬 클래스 바이트 코드 파일 이름 : $1 포함
* 인스턴스 멤버 클래스
- static 키워드 없이 선언된 클래스 : 인스턴스 필드 & 인스턴스 메소드
- 안에 static 붙일 수 없음 : A클래스에 객체가 생성되면 힙메모리에 들어가기 때문에
class A{
class B{
b(){}
int field1
void method1(){}
}
}
A 클래스 외부에서 인스턴스 멤버 클래스 B 객체 생성 방법
A a = new A();
A.B b = a.new B();
b.field1 = 3
b.method1();
* 정적 멤버 클래스
- static 키워드로 선언된 클래스, 모든 종류의 필드와 메소드 선언 가능함(인스턴스필드&메소드, 정적필드&메소드)
- 객체 만들기도 인스턴스 멤버 클래스보다 쉬움
static class C{
C(){}
int field1;
static int field2;
void method1(){}
static void method2(){}
}
A 클래스 외부에서 정적 멤버 클래스 C 객체 생성 방법
A.C c = new A.C();
c.field1 = 3; //인스턴스 필드 사용
c.method1(); //인스턴스 메소드 호출
A.C.field2 = 3; //정적 필드 사용
A.C.method2(); //정적 메소드 호출
* 로컬 클래스
- 메소드 내에서만 사용
- 접근제한자(public, private) 및 static 붙일 수 없음 : 메소드 내에서만 사용하기 때문에 필요 없음
- 로컬 클래스 내부 사용 : 인스턴스 필드, 인스턴스 메소드만 선언 가능 (정적 필드&메소드 X)
- 로컬 클래스는 메소드가 실행될 때 메소드 내에서 객체를 생성하고 사용해야 함
void method(){
class D{
D(){}
int field1;
//static int field2;
void method1(){}
//static void method2()
}
D d = new D();
d.field1 = 3;
d.method1();
}
3. 중첩 클래스의 접근 제한
* 바깥 필드와 메소드에서 사용 제한
- 인스턴스 멤버 클래스 : 인스턴스 필드 초기값, 인스턴스 메소드에서 객체 생성 가능 / 정적 필드 초기값X, 정적 메소드 객체 생성X
- 정적 멤버 클래스 : 모든 필드 초기값, 모든 메소드에서 객체 생성 가능
* 멤버 클래스에서 사용 제한
- 멤버 클래스 내부에서 바깥 클래스의 필드와 메소드를 접근할 때에도 제한이 있음
- 인스턴스 멤버 안 : 바깥 클래스 모든 필드, 메소드 가능
- 정적 멤버 안 : 바깥 정적 필드, 메소드 접근 가능 / 인스턴스 필드 , 메소드 접근 불가능
* 로컬 클래스에서 사용 제한 : 이해가 안대요..
- 로컬 클래스 내부 : 바깥 클래스 필드와 메소드 사용 가능
- 메소드의 매개 변수나 로컬 변수를 로컬 클래스에서 사용할 때 : 로컬 클래스의 객체는 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용될 수 있다. 매개 변수나 로컬 변수는 메소드 실행이 끝나면 스택 메모리에서 사라지기 대문에 로컬 객체에서 사용할 경우 문제가 발생. 자바는 이 문제를 해결하기 위해 컴파일 시 로컬 클래스에서 사용하는 매개 변수나 로컬 변수의 기억 장소를 로컬 클래스 내부에 복사해 두고 사용. 그리고 매개 변수나 로컬 변수가 수정되어 기억 장소가 변경되면 로컬 클래스에 복사해 둔 기억 장소와 달라지는 문제를 해결하기 위해 매개 변수나 로컬 변수를 final 로 선언해서 수정을 막는다.
- 결론적으로 로컬 클래스에서 사용 가능한 것은 final로 선언된 매개 변수와 로컬 변수뿐.
- 자바 8부터 final 키워드 없이 선언된 매개 변수와 로컬 변수를 사용해도 컴파일 에러가 나지 않는다. : final 선언을 하지 않아도 여전히 값을 수정할 수 없는 final의 특성을 갖는다는 것. final 키워드 존재 여부의 차이점은 로컬 클래스의 복사 위치. final 키워드가 있다면 로컬 클래스의 메소드 내부에 지역 변수로 복사되지만, final 키워드가 없다면 로컬 클래스의 필드로 복사됨
- 로컬 클래스의 내부 복사 위치에 신경 쓸 필요 없이 로컬 클래스에서 사용된 매개 변수와 로컬 변수는 모두 final 특성을 갖는다는 것만 알면 됨
* 중첩 클래스에서 바깥 클래스 참조 얻기
- this : 중첩 클래스에서 사용하면, 중첩 클래스의 객체 참조가 된다
중첩 클래스 내부에서 객체 참조 얻는 법
this.필드 //중첩 클래스의 필드
this.메소드() //중첩 클래스의 메소드
중첩 클래스 내부에서 바깥 클래스 객체 참조 얻는 법
바깥클래스.this.필드
바깥클래스.this.메소드();
4. 중첩 인터페이스
class A{
interface I{
void method();
}
}
* 클래스의 멤버로 선언된 인터페이스
* 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위함
- 특히 UI 프로그래밍에서 이벤트를 처리할 목적으로 많이 활용 됨
5. 익명 객체
* 익명 객체 : 이름이 없는 객체
- 단독 생성 불가 : 클래스 상속 or 인터페이스 구현해야 생성 가능
- 사용 위치 : 필드 초기값, 로컬변수 초기값, 매개변수의 매개값으로 주로 대입
- 목적 : UI 이벤트 처리 객체, 스레드 객체를 간편하게 생성할 목적
* 익명 자식 객체 생성 - 초기값 설정에 주목
class A{
Parent field = new Parent(){
int childField;
void childMethod(){}
@Override
void parentMethod(){}
};
}
* 익명 객체에 정의된 필드와 메소드
- 익명 객체 내부에서만 사용
- 외부에서는 익명 객체의 필드와 메소드에 접근할 수 없음
이유 : 익명 객체는 부모 타입 변수에 대입되므로 부모 타입에 선언된 것만 사용 가능
* 익명 구현 객체 생성
인터페이스 [필드|변수] = new 인터페이스(){
//인터페이스에 선언된 추상 메소드의 실제 메소드 선언
//필드
//메소드
};