[Java 자바] 9. 중첩 ① 중첩 클래스
9-1. 중첩 클래스
- 클래스 내부에 선언한 클래스로 중첩 클래스를 사용할 경우 두 클래스의 멤버를 서로 쉽게 접근할 수 있으며,
외부에는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있음
- 클래스 내부에 선언되는 위치에 따라 두 가지로 분류
선언 위치에 따른 분류 | 선언 위치 | 설명 | |
멤버 클래스 |
인스턴스 멤버 클래스 |
class A { class B {...} } |
A 객체를 생성해야만 사용할 수 있는 B 중첩 클래스 |
정적 멤버 클래스 |
class A { static class B {...} } |
A 클래스로 바로 접근할 수 있는 B 중첩 클래스 | |
로컬 클래스 | class A { void method() { class B {...} } } |
method()를 실행할 때만 사용할 수 있는 B 중첩 클래스 |
- 멤버클래스도 하나의 클래스이기 때문에 컴파일시 바이트 코드 파일(.class)이 별도로 생성
A $ B . class
- 로컬 클래스일 경우에는 다음과 같이 $1이 포함된 바이트 코드 파일이 생성됨
A $1 B . class
9-1-1. 인스턴스 멤버 클래스
- 인스턴스 멤버 클래스는 인스턴스 필드, 메소드만 선언 가능 (정적 필드, 메소드 선언 불가)
- A클래스 외부에서 인스턴스 멤버 클래스 B의 객체를 생성하려면 먼저 A의 객체를 생성하고 B 객체를 생성해야 함
public class OuterClass {
class NestedClass {
NestedClass() {}
int field1;
void method1() {}
}
}
public class NestedClassTest {
public static void main(String[] args) {
OuterClass a = new OuterClass();
OuterClass.NestedClass b = a.new NestedClass();
b.field1 = 3;
b.method1();
}
}
9-1-2. 정적 멤버 클래스
- 정적 멤버 클래스는 모든 종류의 필드와 메소드 선언 가능
- A클래스 외부에서 정적 멤버 클래스 C의객체 객체를 생성하기 위해서는 별도의 A객체 생성 필요 없이 진행 가능
public class OuterClass {
static class StaticNestedClass {
StaticNestedClass() {}
int field1;
static int field2;
void method1() {}
static void method2() {}
}
}
public class NestedClassTest {
public static void main(String[] args) {
OuterClass.StaticNestedClass c = new OuterClass.StaticNestedClass();
// 일반 필드, 메소드는 객체 생성 후 객체로 호출
c.field1 = 3;
c.method1();
// 정적 필드, 메소드는 클래스명으로 바로 호출
OuterClass.StaticNestedClass.field2 = 3;
OuterClass.StaticNestedClass.method2();
}
}
9-1-3. 로컬 클래스
- 메소드 내부에서 선언하는 중첩 클래스로, 접근제한자 및 static을 쓸 수 없음 (메소드 내부에서만 사용 가능하기 때문)
- 메소드가 실행될 때 메소드 내에서 객체를 생성하고 사용해야 함
public class OuterClass {
void method() {
class LocalNestedClass {
int field1;
void method1() {}
}
LocalNestedClass d = new LocalNestedClass();
d.field1 = 3;
d.method1();
System.out.println(d.field1);
}
}
public class NestedClassTest {
public static void main(String[] args) {
OuterClass a = new OuterClass();
a.method();
}
}
9-2. 중첩 클래스의 접근 제한
9-2-1. 바깥 필드와 메소드에서 사용 제한
1) 인스턴스 멤버 클래스
- 바깥 클래스의 인스턴스 필드의 초기값이나 인스턴스 메소드에서 객체 생성 가능
- 바깥 클래스의 정적 필드의 초기값이나 정적 메소드에서는 객체 생성 불가
2) 정적 멤버 클래스
- 모든 필드의 초기값이나 모든 메소드에서 객체 생성 가능
public class A {
// 인스턴스 필드
B field1 = new B(); // (O)
C field2 = new C(); // (O)
// 인스턴스 메소드
void method1() {
B var1 = new B(); // (O)
C var2 = new C(); // (O)
}
// 정적 필드 초기화
// static B field3 = new B(); // (X)
static C field4 = new C(); // (O)
// 정적 메소드
static void method2() {
//B var1 = new B(); // (X)
C var2 = new C(); // (O)
}
// 인스턴스 멤버 클래스
Class B {}
// 정적 멤버 클래스
static Class C {}
}
9-2-2. 멤버 클래스에서 사용 제한
1) 인스턴스 멤버 클래스
- 인스턴스 멤버 클래스 안에서는 바깥 클래스의 모든 필드와 모든 메소드 접근 가능
2) 정적 멤버 클래스
- 정적 멤버 클래스 안에서는 바깥 클래스의 정적 필드와 정적 메소드에만 접근 가능
public class A {
int field1;
void method1() {}
static int field2;
static void method2() {}
class B {
void method() {
field1 = 10;
method1();
field2 = 10;
method2();
}
}
static class C {
void method() {
//field1 = 10; // 접근 불가
//method1(); // 접근 불가
field2 = 10;
method2();
}
}
}
9-2-3. 로컬 클래스에서 사용 제한
- 로컬클래스에서 사용되는 매개 변수와 로컬 변수는 모두 final의 특성을 갖게 되며, 값 수정이 불가해짐
public class OuterClass {
public void method1(int arg) {
int localVariable = 1;
//arg = 100;
//localVariable = 100;
class Inner {
public void method() {
int result = arg + localVariable;
System.out.println(result);
}
}
Inner i = new Inner();
i.method();
}
public static void main(String[] args) {
OuterClass a = new OuterClass();
a.method1(50);
}
}
9-2-4. 중첩 클래스에서 바깥 클래스 참조 얻기
- 중첩 클래스에서 this키워드는 중첩 클래스의 객체 참조를 의미
- 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 바깥 클래스 이름을 this 앞에 붙여주면 됨
public class Outter {
String field = "Outter-field";
void method() {
System.out.println("Outter-method");
}
class Nested {
String field = "Nested-field";
void method() {
System.out.println("Nested-method");
}
void print() {
// 중첩객체 참조
System.out.println(this.field);
this.method();
// 바깥객체 참조
System.out.println(Outter.this.field);
Outter.this.method();
}
}
}
public class OutterTest {
public static void main(String[] args) {
Outter outter = new Outter();
Outter.Nested nested = outter.new Nested();
nested.print();
}
}