중첩 클래스
는 클래스 내부에 또 다른 클래스를 선언한 것입니다.
자바에서 클래스는 여러 클래스와 상호작용을 하기에 독립적으로 선언하고 생성합니다. 이때 특정 클래스끼리만 상호작용을 한다면 따로 생성하는 것보다 상호작용을 하는 클래스와 같이 작성하는 것이 효율이 더 좋겠죠. 그래서 중첩 클래스
를 이용합니다.
중첩 클래스
는 다시 클래스의 선언 위치에 따라 멤버 클래스, 로컬 클래스
두 가지로 나뉩니다. 클래스의 멤버로 선언되면 멤버 클래스
, 메소드 내부에서 선언되면 로컬 클래스
라고 불립니다.
클래스의 멤버로 선언된 내부 클래스를 멤버 클래스
라고 부릅니다.
멤버 클래스
는 static 선언에 따라서 다시 두 가지로 나뉘는데 static 선언이 없는 멤버 클래스는 인스턴스 멤버 클래스
, static 선언을 한 멤버 클래스는 정적 멤버 클래스
라고 부르게 됩니다.
인스턴스 멤버 클래스
는 클래스 내부에 선언된 또 다른 클래스입니다.
class A {
class B {} //인스턴스 멤버 클래스
}
접근 제어자로는 public, private
가 올 수 있습니다.
중첩 클래스를 사용하는 이유가 보통 해당 클래스끼리만 상호작용하는 것이기 때문에 대부분의 상황에서는 private
를 이용해서 선언합니다.
A 클래스 내부에서만 B에 접근한다고해서 A 클래스의 아무곳에서나 B에 접근할 수는 없습니다. A의 인스턴스 필드, 생성자, 인스턴스 메소드
에서만 접근할 수 있습니다. 그 이유는 인스턴스 멤버 클래스
는 외부 클래스(A)가 생성되야 인스턴스 멤버 클래스(B)가 생성될 수 있기 때문입니다.
public class A {
public A() {
System.out.println("A클래스 생성자 호출");
}
private class B { //인스턴스 멤버 클래스
B() {
System.out.println("B클래스 생성자 호출");
}
}
public void createB() {
B b = new B();
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.createB();
}
}
인스턴스 멤버 클래스의 멤버로는 멤버 변수(필드), 생성자, 메소드가 올 수 있습니다. Java 17
버전부터는 정적 멤버 변수, 정적 메소드 선언도 할 수 있습니다.
정적 멤버 클래스
는 멤버 클래스를 선언할 때 static
키워드를 붙인 것을 말합니다. static
으로 정적 선언을 하면 정적 멤버 클래스
는 외부 클래스가 생성되지 않아도 생성될 수 있습니다.
class A {
static class B {} //정적 멤버 클래스
}
접근 제어자는 마찬가지로 public, private
를 사용할 수 있습니다.
정적 멤버 클래스
는 외부 클래스 생성 없이 생성이 가능하다는 특성으로 인해 public, default
접근 제어자를 주로 사용합니다.
정적 멤버 클래스
에 접근할 때는 멤버에 접근하는 .
연산자를 이용해서 접근합니다.
클래스.정적_멤버_클래스
public class A {
public A() {
System.out.println("A클래스 생성자 호출");
}
public static class B { //정적 멤버 클래스 B
public B() {
System.out.println("B클래스 생성자 호출");
}
}
public void createB() {
B b = new B();
}
}
public class Main {
public static void main(String[] args) {
A.B b = new A.B(); //정적 멤버 클래스 단독 생성
A a = new A();
a.createB(); //A 생성 후 정적 멤버 클래스 생성
}
}
정적 멤버 클래스를 단독으로 생성하고 호출해도, A를 생성한 후 생성해서 호출해도 같은 결과를 보여줍니다.
로컬 클래스
는 메소드, 생성자 내부에서 선언된 클래스를 의미합니다. 로컬 클래스
는 생성자와 메소드가 실행중일 때만 객체를 생성할 수 있습니다.
class A {
public A() { //생성자
class B {} //로컬 클래스
}
public void method() { //메소드
class B {} //로컬 클래스
}
}
마찬가지로 로컬 클래스
의 멤버로는 멤버 변수, 생성자, 메소드가 올 수 있으며 Java 17
부터 정적 멤버 변수와 정적 메소드 선언이 가능합니다.
A 클래스의 생성자 내부에 B 로컬 클래스를 선언한 예제입니다.
public class A {
public A() { //A 클래스 생성자
System.out.println("A클래스 생성자 호출");
class B { //로컬 클래스 B
public B() {
System.out.println("B클래스 생성자 호출");
}
}
B b = new B(); //A 클래스 생성자에서 B 객체 생성
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
}
}
생성자와 메소드 내부에서 선언된 로컬 변수를 로컬 클래스에서 호출하면 자동적으로
final
특성이 붙습니다. 이는 로컬 클래스에서 로컬 변수 변경을 막기 위함입니다.
중첩 클래스의 선언 방식에 따라서 외부 클래스의 멤버에 대한 접근 제한이 조금씩 다릅니다.
인스턴스 멤버 클래스
는 외부 클래스의 모든 멤버 변수와 메소드에 접근할 수 있습니다. 하지만 정적 멤버 클래스
는 외부 클래스의 정적 멤버 변수와 정적 메소드에만 접근할 수 있습니다.
this는 현재 인스턴스 자기 자신을 가리키는 변수였습니다. this
를 중첩 클래스 내부에서 사용하게 될 경우 중첩 클래스를 가리키게 됩니다. 이를 이용해서 중첩 클래스 내부에서 외부 클래스를 가리키게 할 수 있습니다.
외부클래스명.this
인스턴스 멤버 클래스에서 외부 클래스의 메소드를 호출하는 예제입니다.
public class A {
public class B {
public void callSayHi() {
A.this.sayHi(); //B에서 A의 메소드 호출
}
}
public void createB() {
B b = new B();
b.callSayHi();
}
public void sayHi() { //A의 메소드
System.out.println("Hi");
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.createB();
}
}