📔 학습한 내용을 정리하기 위해 작성하는 게시글입니다.
중첩 클래스(nested class)란 클래스 내부에 클래스가 있는 형태의 클래스이다.
예전에는 자바 기반의 UI 처리를 할 때 사용자의 입력이나 외부의 이벤트에 대한 처리를 하는 곳에서 많이 사용했으며, 현재는 안드로이드 프로그래밍에서 위젯의 이벤트를 처리하는 핸들러를 구현할 때 사용한다.
class Out{ //외부 클래스
class In{ //내부 클래스
...
}
}
어떤 클래스가
1) 다른 클래스와 협력할 일이 적고,
2) 외부 클래스와 밀접한 관련이 있다면,
두 클래스를 한번에 관리하는 것이 적합하다. → 중첩 클래스를 사용하여 불필요한 관계를 감추고 높은 접근성을 얻을 수 있다.
외부 클래스와 내부 클래스가 서로의 멤버에 쉽게 접근할 수 있다.
소스의 가독성과 유지보수성을 높일 수 있다.
서로 관련 있는 클래스를 논리적으로 묶어서 표현함으로써, 코드의 캡슐화를 증가시킨다.
외부에서는 내부 클래스에 접근할 수 없으므로, 코드의 복잡성을 줄일 수 있다.
자바에서는 클래스 안에 클래스를 선언할 수 있다. 안쪽에 있는 클래스를 내부 클래스(inner class), 내부 클래스를 가지고 있는 클래스를 외부 클래스(outer class)라고 한다.
선언한 방법에 따라 static으로 선언된 중첩 클래스인 정적 클래스(static class), static으로 선언되지 않은 중첩 클래스인 인스턴스 클래스(instance class)로 구분된다.
내부 클래스는 다시 이름이 있는 내부 클래스인 지역 클래스(local class), 이름이 없는 클래스인 익명 클래스(anonymous class)로 구분된다.
출판 번역에 따라 여러 책에서 이너 클래스, 내부 클래스, 중첩 클래스라는 단어를 혼용해 사용하고 있다. 본 게시글에서는 중첩 클래스 ⊃ 내부 클래스 = 이너 클래스로 정리했다.
중첩 클래스는 클래스 내부에 클래스가 있는 형태라는 뜻으로, 내부 클래스는 외부 클래스 내부에 있는 클래스라는 의미로 사용했다.
외부 클래스 영역에 선언된 클래스 중에서 static 키워가 포함된 클래스를 정적 클래스(static class)라고 한다.
주로 외부 클래스(outer class)의 클래스 메서드에 사용될 목적으로 선언된다.
정적 메서드와 동일하게 외부 클래스의 정적 멤버에만 접근할 수 있다. (static의 특성)
외부 클래스의 객체를 생성하지 않아도 정적 내부 클래스의 객체를 생성해 사용할 수 있어야 한다.
→ 외부 클래스의 멤버 중 객체 생성 없이 바로 사용할 수 있는 정적(static)멤버만 정적 내부 클래스에서 사용할 수 있다.
class에 붙는 static과 멤버에 붙는 static의 의미 차이
- 클래스의 멤버(필드, 메서드)에 붙는 static키워드는 정적으로 메모리를 할당하므로 객체 생성 없이도 사용 가능하다는 의미
- 클래스에 붙는 static은 외부 클래스의 객체 생성없이 내부 클래스의 객체를 생성할 수 있다는 의미
외부 클래스.내부 클래스 클래스 참조 변수 = new 외부 클래스.내부 클래스();
class A {
static class B {
}
}
A.B b = new A.B();
외부 클래스 영역에 선언된 클래스 중에서 static 키워드를 가지지 않는 클래스를 인스턴스 클래스(instance class)라고 한다.
인스턴스, 즉 객체 내부에 멤버의 형태로 존재한다. 외부 클래스의 모든 접근 지정자의 멤버에 접근할 수 있다.
인스턴스 내부 클래스는 외부 클래스의 객체 내부에 존재한다. 따라서 내부 클래스의 객체를 생성하기 위해 먼저 외부 클래스의 객체를 생성해야 한다.
외부 클래스 외부 클래스 참조 변수 = new 외부 클래스();
외부 클래스.내부 클래스 내부 클래스 참조 변수 = 외부 클래스 참조 변수.new 내부 클래스();
class A {
class B {
}
}
A a = new A();
A.B b = a.new B();
지역 클래스(local class)란 외부 클래스의 멤버가 아닌 메서드나 초기화 블록에 선언된 클래스를 의미한다.
지역 변수처럼 정의된 메서드 내부에서만 사용할 수 있다. 일반적으로 지역 클래스는 선언 이후 바로 객체를 생성해 사용하며, 메서드가 호출될 때만 메모리에 로딩된다. (지역 클래스는 정적 클래스로 지정할 수 없다.)
지역 변수를 사용할 때는 반드시 해당 지역 변수가 final로 선언되어야 한다. 만약 final로 선언되지 않은 지역 변수를 지역 클래스 내부에서 사용하게 되면 컴파일러가 강제로 해당 지역 변수에 final을 추가한다.
지역 내부 클래스 지역 내부 클래스 참조 변수 = new 지역 내부 클래스();
class A {
void abc() {
class B { //지역 이너 클래스
}
B b = new B(); //지역 이너 클래스 객체 생성
}
}
익명 클래스(anonymous class)란 다른 내부 클래스와 달리, 이름을 가지지 않는 클래스를 의미한다.
정의된 위치에 따라 클래스의 중괄호 바로 아래에 사용했을 때는 인스턴스 익명 내부 클래스, 메서드 내부에서 사용했을 때는 지역 익명 내부 클래스를 의미한다. (정적 익명 내부 클래스는 존재할 수 없다.)
클래스의 선언과 객체의 생성을 동시에 하므로 단 하나의 객체만을 생성할 수 있고, 단 한번만 사용되는 일회용 클래스이다.
생성자를 선언할 수도 없으며, 오로지 단 하나의 클래스나 단 하나의 인터페이스를 상속받거나 구현할 수 있다.
익명 클래스는 선언과 동시에 생성하여 참조변수에 대입함.
클래스 이름 참조 변수 이름 = new 클래스 이름() {//메서드 선언};
class A {
C c = new C() {
public void bcd() {
System.out.println("익명 내부 클래스");
}
};
void abc() {
c.bcd();
}
}
interface C {
public abstract void bcd();
}
public class AnonymousClass_2 {
public static void main(String[] args) {
//객체 생성 및 메서드 호출
A a = new A();
a.abc();
}
}
종류 | 구현 위치 | 사용할 수 있는 외부 클래스 변수 | 생성 방법 |
---|---|---|---|
인스턴스 내부 클래스 | 외부 클래스 멤버 변수와 동일 | 외부 인스턴스 변수, 외부 전역 변수 | 외부 클래스를 먼저 만든 후 내부 클래스 생성 |
정적 내부 클래스 | 외부 클래스 멤버 변수와 동일 | 외부 전역 변수 | 외부 클래스와 무관하게 생성 |
지역 내부 클래스 | 메서드 내부에 구현 | 외부 인스턴스 변수, 외부 전역 변수 | 메서드를 호출할 때 생성 |
익명 내부 클래스 | 메서드 내부에 구현, 변수에 대입하여 직접 구현 | 외부 인스턴스 변수, 외부 전역 변수 | 메서드를 호출할 때 생성되거나, 인터페이스 타입 변수에 대입할 때 new 예약어를 사용하여 생성 |
클래스의 멤버로 선언된 인터페이스이다.
사용자 인터페이스의 이벤트 처리에 많이 사용된다.
인터페이스이므로 자체적으로 객체를 생성할 수 없다. 해당 인터페이스를 상속한 자식 클래스를 생성한 후 생성자를 이용해 객체를 생성하거나, 익명 이너 클래스를 활용해 객체를 생성해야 한다.
→ 객체의 타입을 '외부 클래스명. 내부 클래스명'과 같이 사용하는 점을 제외하면 일반적인 인터페이스 객체를 생성하는 방법과 동일하다.
class A {
//...
static interface B { //static을 생략해도 컴파일러가 자동으로 추가
void bcd();
}
}
<Do it! 자바 프로그래밍 입문>
<DO it! 자바 완전 정복>
<이재환의 자바 프로그래밍 입문>
https://shrtorznzl.tistory.com/23
https://insight-bgh.tistory.com/21
https://zrr.kr/XKF9
https://dkswnkk.tistory.com/540
https://blog.hexabrain.net/378
https://tecoble.techcourse.co.kr/post/2020-11-05-nested-class/
https://zrr.kr/ZpEk
http://www.tcpschool.com/