중첩 클래스(Nested Class)
개념
- 하나의 클래스 내에 선언된 또 다른 클래스
- 즉, 한 클래스 내에서 다른 클래스를 정의하여 사용
- 외부 클래스의 멤버로써 중첩 클래스를 사용함
중첩 클래스를 사용하는 이유
- 하나의 클래스가 여러 클래스와 관계를 맺는 경우에는 독립적으로 선언하여 사용하는 것이 좋지만
- 특정 1개의 클래스와 관계를 맺는 경우에는, 관계를 맺은 클래스 내부에 선언하는 것이 좋음
- 외부 클래스와는 서로 밀접한 관계가 있는 경우에
- 2개의 클래스를 묶어서 한번에 관리하여 캡슐화를 증가 시키고, 유지보수에 도움을 줌
장점
- 중첩 클래스를 사용하면, 두 클래스의 멤버들끼리 서로 쉽게 접근할 수 있음
- 불필요한 관계 클래스를 내부에 감춰서, 코드의 복잡성을 줄일 수 있음
중첩 클래스의 4가지 종류
class OuterClass {
// Inner Class(내부 클래스)
class InnerClass { ... }
// Static Nested Class(정적 중첩 클래스)
static class StaticInnerClass { ... }
}
1. Inner Class
- Non-Static Nested class
- 인스턴스 클래스
2. Static Nested Class
- static Nested class
- 정적 클래스
3. local class
- 지역 클래스(로컬 클래스)
4. anonymous class
- 익명 클래스
[ 외부클래스 ]
- 중첩 클래스를 감싸는 바깥 클래스
외부클래스의 멤버
1. 필드(멤버변수)
2. 메서드
3. 내부 클래스
class OuterClass { int num = 1; // 멤버변수 public void print() { ... } // 메서드 class InnerClass { ... } // 내부클래스 }
클래스 내부에 선언되는 위치에 따른 분류
1. 클래스의 멤버로 선언되는 클래스
- Inner Class(인스턴스 클래스)
- Static Nested Class(정적 클래스)
2. 메서드 내부에 선언되는 클래스
- Local Class(로컬 클래스)
여러 단어를 혼용하여 쓰기 때문에,
Inner클래스는 인스턴스 클래스로, Static Nested 클래스는 정적 클래스로 기준을 두고 설명함
인스턴스 클래스
class OuterClass {
class InnerClass { ... } // OuterClass 객체를 생성해야만 사용할 수 있는 InnerClass
}
개념
- static 키워드 없이, 클래스의 내부에 선언된 클래스
- 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언
- 외부 클래스 객체의 필드와 메서드에 직접 접근이 가능함
클래스의 멤버
- 인스턴스 멤버만 선언할 수 있음
- 인스턴스 필드
- 인스턴스 메서드
- static 멤버는 선언 불가
특징
1. 외부 클래스의 인스턴스를 먼저 생성한 후에, 인스턴스 클래스의 인스턴스 생성이 가능
2. 인스턴스 클래스에서 외부 클래스의 멤버에 접근이 가능함
- 외부 클래스의 멤버는 필드, 메서드, 내부 클래스이고, 이 멤버들끼리는 동일한 레벨
- 따라서 인스턴스 클래스에서 외부 클래스의 멤버에 접근할 수 있음
3. 인스턴스 필드와 메소드만 선언이 가능하고 정적 필드와 메소드는 선언할 수 없음
- 인스턴스 클래스의 멤버로 인스턴스 필드와 메서드만 가질 수 있고
- 정적(static) 필드와 메서드는 선언할 수 없음
4. 외부 클래스에서는 인스턴스 클래스의 필드와 메서드에 접근할 수 없음
외부 클래스를 기준으로 인스턴스 클래스의 필드와 메서드를 지역변수로 보기 때문에 외부 클래스에서 접근이 불가능함
[ 주의 사항 ]
1. 인스턴스 클래스에서 외부 클래스의 정적 필드와 메서드(static) 사용 시, 외부 클래스의 인스턴스를 생성하지 않아도 바로 사용 가능
2. 인스턴스 클래스의 멤버로 정적 필드와 메서드(static)를 가질 수 없음
인스턴스 클래스의 인스턴스 생성 방법
- 먼저 외부 클래스의 인스턴스를 생성한 후 → 인스턴스 클래스의 인스턴스를 생성
OuterClass outer = new OuterClass();
Outer.InnerClass inner = outer.new InnerClass();
- 외부 클래스의 인스턴스를 생성한 후에, 같은 타입의 참조변수에 대입
- 참조변수1.new를 이용하여 내부클래스의 인스턴스를 생성한 후에, 내부클래스 참조변수에 대입
예제
public class Outer { // 외부 클래스 선언
// 외부 클래스의 필드: static변수, 인스턴스 변수 모두 사용 가능
static int a = 10;
int b = 20;
private int c = 30;
// 외부 클래스의 메서드: static메서드, 인스턴스 메서드 모두 사용 가능
void outerInstanceMethod(){
System.out.println("외부 클래스의 인스턴스 메서드");
}
static void outerStaticMethod(){
System.out.println("외부 클래스의 정적 메서드");
}
// 내부 클래스(non-static inner class) 선언
class Inner{
// 내부 클래스 안에서 static변수 사용 X
// static int d = 40;
int e = 50;
private int f = 60;
Inner(){} // 기본 생성자
Inner(int num1, int num2, int num3){ // 매개변수 있는 생성자
a = num1; // 외부 클래스의 필드를 제한 없이 사용 가능
// 외부 클래스의 필드를 불러오기 위해서 this.를 사용 X
Outer.this.c = num2; // 외부클래스명.this.c 사용
this.f = num3; // 내부 클래스 자신의 필드를 불러오기 위해 this.를 사용
}
void instanceMethod(){
System.out.println("내부 클래스의 인스턴스 메서드");
System.out.printf("%d, %d, %d, %d, %d \n", a, b, c, e, f);
// 외부 클래스의 필드를 제한 없이 사용 가능
outerStaticMethod();
outerInstanceMethod();
}
// 내부 클래스에서 static 메서드 사용 X
// static void staticMethod(){
// System.out.println("내부 클래스에서 static 메서드 사용 불가");
// }
}
}
public class InnerTest {
public static void main(String[] args) {
// 1. 외부 클래스의 인스턴스를 생성
Outer out = new Outer();
// 2. 내부 클래스의 인스턴스를 생성
Outer.Inner inner = out.new Inner(1, 2, 3);
// 3. 내부 클래스의 인스턴스메서드 호출
inner.instanceMethod();
}
}
인스턴스 클래스의 컴파일 형태
- 내부 클래스는 클래스 안의 클래스 형태이기 때문에, 보통의 컴파일과 형태가 다름
- 컴파일시 생성되는 클래스 파일명은 외부클래스$내부클래스.class 형태
내부 클래스는 다른 클래스에서 직접 사용하는 것보다 해당 외부 클래스에서만 사용하는 것이 일반적이기 때문에
내부 클래스의 인스턴스 생성은, 주로 외부 클래스 내에서 이루어짐
정적 클래스
개념
- static 키워드로 선언된 내부 클래스
클래스의 멤버
- 인스턴스 필드와 메서드
- 정적 필드와 메서드
- 모두를 선언하여 사용할 수 있음
형식
class OuterClass { // 외부 클래스
static class InnerClass { ... }
}
특징
- 정적 클래스의 객체를 생성하려면, 외부 클래스의 객체를 생성할 필요 없이 바로 생성 가능
- 내부 클래스에서 외부 클래스의 인스턴스 멤버에는 접근이 불가능함
public class CaptionTv {
public int channel; // 인스턴스 멤버변수
static class Tape {
void showChannel() {
// 외부 클래스의 인스턴스 멤버 접근 불가
// System.out.println(channel);
}
}
}
3. 외부 클래스의 멤버가 정적 멤버(static)라면, 내부클래스에서 외부 클래스의 멤버에 접근 가능
public class CaptionTv {
static int channel; // 정적 멤버변수
int price;
static class Tape {
static String name = "테이프";
int length = 10;
void showChannel() {
// 외부 클래스의 인스턴스 멤버 접근 불가능
// System.out.println(price);
// 외부 클래스의 스태틱 멤버 접근 가능
System.out.println(channel);
}
static void staticName() { // 스태틱 메서드
// 스태틱 클래스의 멤버도, 스태틱 멤버만 접근 가능
System.out.println(name);
}
}
}
정적 클래스의 인스턴스를 생성하는 방법
- 외부 클래스(Outer)의 인스턴스를 생성하지 않고,
- 바로 정적 클래의 인스턴스를 생성해서 사용 가능
// 바로 내부 스태틱 클래스의 인스턴스를 생성
CaptionTv.Tape inner = new CaptionTv.Tape();
// 참조변수.정적메서드()
inner.staticName();
// 외부클래스.스태틱클래스.정적메서드()
CaptionTv.Tape.staticName();
예제
public class Outer { // 외부 클래스 선언
// 외부 클래스의 필드: static변수, 인스턴스 변수 모두 사용 가능
static int a = 10;
int b = 20;
private int c = 30;
// 외부 클래스의 메서드: static메서드, 인스턴스 메서드 모두 사용 가능
void outerInstanceMethod(){
System.out.println("외부 클래스의 인스턴스 메서드");
}
static void outerStaticMethod(){
System.out.println("외부 클래스의 정적 메서드");
}
// 정적 내부 클래스(static inner class) 선언
static class StaticInner {
static int d = 40;
int e = 50;
private int f = 60;
void instanceMethod(){
System.out.println("정적 내부 클래스의 인스턴스 메서드");
// 외부 클래스의 인스턴스 필드는, 외부 클래스의 객체 생성 후 사용 가능
Outer outer = new Outer();
System.out.printf("외부 클래스의 인스턴스 필드 : %d, %d\n", outer.b, outer.c);
outer.outerInstanceMethod();
// 외부 클래스의 정적 필드(static)는, 객체 생성 없이 사용 가능
System.out.printf("외부 클래스의 정적 필드 : %d, %d \n", a, d);
outerStaticMethod();
}
static void staticMethod(){
System.out.println("정적 내부 클래스의 정적 메서드");
// 외부 클래스의 정적 필드(static)는 객체 생성 없이 사용 가능
System.out.printf("외부 클래스의 정적 필드 : %d, %d \n", a, d);
outerStaticMethod();
// 외부 클래스의 인스턴스 필드는, 외부 클래스의 객체 생성 후 사용 가능
Outer outer = new Outer();
System.out.printf("외부 클래스의 인스턴스 필드 : %d, %d\n", outer.b, outer.c);
outer.outerInstanceMethod();
}
}
}
정적 클래스의 객체 생성하고, 정적 클래스의 인스턴스 메서드 호출
public class InnerClass {
public static void main(String[] args) {
Outer.StaticInner staticInner = new Outer.StaticInner();
staticInner.instanceMethod();
}
}
[ 실행 결과 ]
정적 클래스의 객체 생성하고, 정적 클래스의 정적 메서드 호출
public class InnerClass {
public static void main(String[] args) {
Outer.StaticInner staticInner = new Outer.StaticInner();
staticInner.staticMethod();
}
}
[ 실행 결과 ]
로컬 클래스
class OuterClass {
void method() {
class LocalClass { ... } // method()가 실행될 때만 사용할 수 있는 중첩클래스
}
}
개념
- 메서드 내에 선언한 중첩 클래스
클래스의 멤버
- 인스턴스 필드와 메서드만 사용 가능
- 정적 필드와 메서드는 선언 불가
특징
- 로컬 클래스에는 접근 제한자 및 static 키워드를 붙일 수 없음
- 로컬 클래스 내부에는 인스턴스 필드와 메서드만 선언이 가능함
- 정적 필드와 메서드는 선언할 수 없음
- 메서드가 실행될 때, 메서드 내에서 로컬 클래스의 객체를 생성하고 사용해야 함
[ 주의할 점 ]
1. static 키워드 사용 불가
2. 정적 필드와 메서드 선언 불가
출처
'JAVA' 카테고리의 다른 글
[JAVA] 깊은 복사, 얕은 복사 (0) | 2024.04.24 |
---|---|
[JAVA] 익명 클래스(익명 객체) (0) | 2024.04.23 |
[JAVA] 상속과 인터페이스, 추상클래스와 인터페이스의 차이 (0) | 2024.04.23 |
[JAVA] 추상 클래스, 추상 메서드, 추상클래스와 인터페이스 차이점 (0) | 2024.04.22 |
[JAVA] 인터페이스(특징, 형식과 구현), 상속과 인터페이스의 차이점 (0) | 2024.04.22 |