[Java] 내부 클래스란? (inner class)

2022. 2. 21. 01:45Back-end/Java

  • 클래스 내부에 선언한 클래스로 이 클래스를 감싸고 있는 외부 클래스와  밀접한 연관이 있는 경우가 많다
  • 다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스로 선언해서 사용한다
  • 중첩 클래스라고도 한다
  • 인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local) 내부 클래스, 익명(anonymous) 내부 클래스가 있다

인스턴스 내부 클래스

  • 내부적으로 사용할 클래스를 선언 (private으로 선언)
  • 외부 클래스가 생성된 후 생성됨 (정적 내부 클래스와 다름)
  • private이 아닌 내부 클래스는 다른 외부 클래스에서 생성할 수 있다
OutClass outClass = new OutClass();
OutClass.InClass inClass = outClass.new InClass();
인스턴스 내부 클래스 예제 코드
package ch01;

class OutClass {
	
	private int num = 10;
	private static int sNum = 20;
	private InClass inClass;
	
	public OutClass() {
		inClass = new InClass(); // 내부 클래스 생성
	}
	
	private class InClass {
		
		int iNum = 30;
		
		void inTest() {
			System.out.println("(외부 클래스의 인스턴스 변수) OutClass num = " + num);
			System.out.println("(외부 클래스의 스태틱 변수) OutClass num = " + sNum);
			System.out.println("(내부 클래스의 인스턴스 변수) InClass num = " + iNum);
		}
	}

	public void usingClass() {
		inClass.inTest(); // 내부 클래스 변수를 사용하여 메서드 호출
	}
}

public class InnerTest {

	public static void main(String[] args) {
		
		OutClass outClass = new OutClass();
		outClass.usingClass();
	}

}

정적 내부 클래스

  • 외부 클래스 생성과 무관하게 사용할 수 있다
  • 정적 변수, 정적 메서드 사용
정적 내부 클래스 예제 코드 (인스턴스 내부 클래스 예제 코드에 이어서 작성)
package ch01;

class OutClass {
	
	private int num = 10;
	private static int sNum = 20;
	private InClass inClass;
	
	public OutClass() {
		inClass = new InClass(); // 내부 클래스 생성
	}
	
	private class InClass {
		
		int iNum = 30;
		
		void inTest() {
			System.out.println("(외부 클래스의 인스턴스 변수) OutClass num = " + num);
			System.out.println("(외부 클래스의 스태틱 변수) OutClass num = " + sNum);
			System.out.println("(내부 클래스의 인스턴스 변수) InClass num = " + iNum);
		}
	}

	public void usingClass() {
		inClass.inTest(); // 내부 클래스 변수를 사용하여 메서드 호출
	}
	
	static class InStaticClass {
		
		int inNum = 100;
		static int inStaticNum = 200;
		
		void inTest() { //정적 클래스의 일반 메서드
			// 외부 클래스의 인스턴스 변수는 사용할 수 없음
			System.out.println("(내부 클래스의 인스턴스 변수) InStaticClass num = " + inNum);
			System.out.println("(내부 클래스의 스태틱 변수) InStaticClass num = " + inStaticNum);
			System.out.println("(외부 클래스의 스태틱 변수) InClass num = " + sNum);
		}
		
		static void sTest() { // 정적 클래스의 스태틱 메서드
			// 외부, 내부 클래스의 인스턴스 변수는 사용할 수 없음
			System.out.println("(내부 클래스의 스태틱 변수) InStaticClass num = " + inStaticNum);
			System.out.println("(외부 클래스의 스태틱 변수) InClass num = " + sNum);
		}
	}
	
}

public class InnerTest {

	public static void main(String[] args) {
		
//		OutClass outClass = new OutClass();
//		outClass.usingClass();
		
		// 외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
		OutClass.InStaticClass inStaticClass = new OutClass.InStaticClass();
		System.out.println("정적 내부 클래스 일반 메서드 호출");
		inStaticClass.inTest();
		
		System.out.println("정적 내부 클래스의 스태틱 메서드 호출");
		OutClass.InStaticClass.sTest();
	}

}

지역 내부 클래스

  • 지역 변수와 같이 메서드 내부에서 정의하여 사용하는 클래스
  • 메서드의 호출이 끝나면 메서드에 사용된 지역 변수의 유효성은 사라진다
  • 메서드 호출 이후에도 사용해야 하는 경우가 있을 수 있으므로 지역 내부 클래스에서 사용하는 메서드의 지역 변수나 매개 변수는 final로 선언된다
package ch01;

class Outer {

	Runnable getRunnable(int i) {

		int num = 100;

		class MyRunnable implements Runnable {
        
			@Override
			public void run() {
				// i = 123; -> error
				// num = 456; -> error
				System.out.println(i);
				System.out.println(num);
			}
			
		}
		return new MyRunnable();
		
	}
	
}

public class AnonumousInnerTest {

	public static void main(String[] args) {
		
		Outer outer = new Outer();
		Runnable runnable = outer.getRunnable(10);
		
		runnable.run();
	}

}
  • MyRunnable 클래스를 사용하려면 getRunnable 메서드를 호출해서 생성된 개체를 반환 받아야 한다

익명 내부 클래스

  • 이름이 없는 클래스 (위 지역 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없음)
  • 클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환한다
  • 인터페이스나 하나의 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부에서 생성하여 반환할 수 있다
  • 안드로이드 위젯의 이벤트 핸들러에 활용된다
package ch01;

class Outer {

	Runnable getRunnable(int i) {

		int num = 100;

		return new Runnable() {
        
			@Override
			public void run() {
				// i = 123; -> error
				// num = 456; -> error
				System.out.println(i);
				System.out.println(num);
			}
		};		
	}
	
	Runnable runnable2 = new Runnable() {
		
		@Override
		public void run() {
			System.out.println("Runnable 이 구현된 익명 클래스 변수");
		}
	};

}

public class AnonumousInnerTest {

	public static void main(String[] args) {
		
		Outer outer = new Outer();
		Runnable runnable1 = outer.getRunnable(10);
		
		runnable1.run();
		
		outer.runnable2.run();
	}

}
  • 익명 내부 클래스가 제일 많이 쓰인다고 한다

이상으로 자바의 내부 클래스에 대해 알아보았다.

반응형