Java의 내부 클래스(Inner Class) - 🐥 카카오 테크 캠퍼스
클래스 내부에 선언하는 클래스(또는 중첩 클래스)입니다. 자신이 속한 외부 클래스와 함께 사용하는 경우가 잦습니다
다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스로 선언해서 사용합니다.
내부 클래스의 종류
인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local) 내부 클래스, 익명(anonymous) 내부 클래스
인스턴스 내부 클래스
- 내부적으로 사용할 클래스를 선언 (private으로 선언하는 것을 권장)
- 외부 클래스가 생성된 후 생성됨 ( 정적 내부 클래스와 다름 )
- private이 아닌 내부 클래스는 다른 외부 클래스에서 생성할 수 있음
주의 사항
- 이너 클래스는 외부 클래스가 생성 될 때 자동으로 생성되지 않으며, 아래 코드처럼 명시적으로 인스턴스를 생성해줘야 합니다
- 또는,
OutClass.InClass inClass = outClass.new InClass()
이렇게 외부 클래스를 이용해서 생성 할수도 있습니다
class OutClass {
private int num = 10;
private static int sNum = 20;
private InClass inClass;
public OutClass(){
inClass = new InClass(); // 내부 클래스 명시적 생성
}
class InClass{
int inNum = 100;
void inTest(){
System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
}
}
public void usingClass(){
inClass.inTest(); //내부 클래스 변수를 사용하여 메서드 호출하기
}
}
정적 내부 클래스
정적 내부 클래스는 외부 클래스와 무관하게 사용 할 수 있습니다
정적 클래스는 외부 클래스나 내부 클래스의 인스턴스 변수를 사용할 수 없습니다.
인스턴스 변수는 자신이 속한 개체의 일부로 힙에 저장이 되지만, 정적 내부 클래스는 외부 클래스 자체와 연관되어 다른 클래스 레벨 정보화 함께 JVM의 메소드 영역에 저장되기 때문입니다
즉 Java의 정적 내부 클래스와 인스턴스 변수는 메모리에 다르게 저장되기 때문이죠
위와 같은 이유로 바로 클래스의 인스턴스를 생성하지 않고 정적 내부 클래스의 정적 메소드를 호출 할 수 있는 것입니다
public class InnerTest {
public static void main(String[] args) {
//외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
System.out.println("정적 내부 클래스 일반 메서드 호출");
sInClass.inTest();
System.out.println();
System.out.println("정적 내부 클래스의 스태틱 메소드 호출");
OutClass.InStaticClass.sTest();
}
}
지역 내부 클래스
로컬 내부 클래스는 메서드 내에서 정의된 클래스로, 지역 변수와 유사합니다.
일반 내부 클래스와 비교하여 몇 가지 특정 규칙과 제한 사항이 있습니다.
- 로컬 내부 클래스는 정의된 메서드 내에서만 사용할 수 있습니다.
- 메서드 호출이 종료되면 메서드 내에서 사용된 지역 변수의 유효성이 사라집니다.
- 즉, 지역 내부 클래스는 사실상 final로 선언되지 않은 지역 변수나 메서드 매개변수를 사용할 수 없습니다.
- 로컬 내부 클래스는 제한 없이 외부 클래스의 인스턴스 및 정적 변수에 액세스할 수 있습니다.
주의 사항 : 로컬 내부 클래스에서 외부 메소드의 변수를 수정하는 경우에 에러가 발생 할 수 있습니다
이는 메소드의 생성 시기와 클래스가 호출 되는 시점이 다르기 때문입니다.
메소드 호출이 끝나면 메소드의 변수들은 스택에 있다가 사라지지만, 클래스 호출 시점에 변수가 없다면 호출을 하지 못합니다
현재는 컴파일러 단에서 자동으로 final로 변경함으로써 이런 문제를 해결합니다. 변수들을 스택이 아니라 상수들이 위치하는 구역에 저장하기 위함입니다
public class LocalInnerExample {
private int instanceVar = 50;
public void createRunnable(int localVar) {
final int finalLocalVar = 100;
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Accessing instance variable: " + instanceVar);
System.out.println("Accessing non-final local variable: " + localVar);
System.out.println("Accessing final local variable: " + finalLocalVar);
}
}
Runnable runnable = new MyRunnable();
runnable.run();
}
public static void main(String[] args) {
LocalInnerExample example = new LocalInnerExample();
example.createRunnable(20);
}
}
익명 내부 클래스
익명 내부 클래스는 일반적으로 인터페이스를 구현하거나 추상 클래스를 확장하는 데 사용되는 이름이 없는 클래스입니다.
익명의 내부 클래스는 별도의 명명된 클래스를 정의하는 것이 불필요하거나 읽기가 어려울 수 있는 수명이 짧은 객체 또는 이벤트 핸들러에 자주 사용됩니다.
익명 내부 클래스의 주요 특징은 다음과 같습니다.
- 이름이 없고 변수에 직접 할당하거나 메서드에서 반환하여 생성됩니다.
- 일반적으로 인터페이스를 구현하거나 추상 클래스를 확장하는 데 사용됩니다.
- 메서드에서 생성 및 반환되거나 변수에 직접 할당될 수 있습니다.
간단한 예시
public class AnonymousInnerExample {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous inner class implementing Runnable");
}
};
runnable.run();
}
}
이 예제에서는 Runnable
인터페이스를 구현하는 익명의 내부 클래스를 만듭니다.
run()
메서드는 익명의 내부 클래스 내에서 재정의되며 클래스는 Runnable
변수에 할당됩니다.
그런 다음 run()
메소드가 runnable
변수에서 호출됩니다.
레퍼런스
- [[자바의 메모리 구조]]
부족한 점이나 잘못 된 점을 알려주시면 시정하겠습니다 :>
'DEV > Java' 카테고리의 다른 글
Stream (0) | 2023.05.02 |
---|---|
Java의 Lambda - 🐥 카카오 테크 캠퍼스 (0) | 2023.05.02 |
Interface의 활용 - 🐥 카카오 테크 캠퍼스 (0) | 2023.04.28 |
Interface (0) | 2023.04.27 |
타입 상속 (0) | 2023.04.27 |