[JAVA] 내부 클래스

AI 개발자 웅이·2022년 7월 14일
0

Java

목록 보기
8/11

자바 내부 클래스(inner class)란 클래스 내부에 생성된 클래스이다. 내부 클래스는 구현 위치에 따라 인스턴스 내부 클래스, 정적 내부 클래스, 지역 내부 클래스, 익명 내부 클래스로 나눌 수 있다. 하나씩 예제와 함께 살펴보자.

인스턴스 내부 클래스

인스턴스 내부 클래스란 외부 클래스 멤버 변수와 동일한 위치에 구현되며 외부 클래스를 먼저 만든 후 생성되는 내부 클래스이다. 인스턴스 내부 클래스에서는 외부 클래스 변수 중 외부 인스턴스 변수와 외부 전역 변수를 사용할 수 있다.

아래는 인스턴스 내부 클래스 예제이다.

class OutClass {

	private int num = 10;
	private static int sNum = 120;
	private InClass inClass;

	public OutClass() {
		inClass = new InClass();
	}
    
// 인스턴스 내부 클래스 구현
	class InClass {
		int inNum = 200;

		static int sInNum = 100; 
		void inTest() {
			System.out.println(num);
			System.out.println(sNum);
		}
	}

	public void usingInTest() {
		inClass.inTest();
	}
}
public class innerTest {

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

예제에서처럼 인스턴스 내부 클래스는 외부 클래스의 멤버 변수와 동일한 위치에 구현되고, private으로 클래스 내부에서만 접근할 수 있도록 제한하여 사용하는 경우가 많다. 또한 인스턴스 내부 클래스는 객체가 생성되어야만 사용할 수 있으므로 static 변수를 사용할 수 없다.

정적 내부 클래스

정적 내부 클래스란 외부 클래스 멤버 변수와 동일한 위치에 구현되며 외부 클래스 생성과 무관하게 생성되는 내부 클래스이다. 정적 내부 클래스에서는 외부 클래스 변수 중 외부 전역 변수만을 사용할 수 있다.

아래는 정적 내부 클래스 예제이다.

class OutClass {

	private int num = 10;
	private static int sNum = 120;

// 정적 내부 클래스 구현
	static class InStaticClass {
		int iNum = 100;
		static int sInNum = 200;

		void inTest() {
			// num += 10; //외부 클래스의 인스턴스 변수는 쓰지 못함
			sNum += 10; // 외부 클래스의 static 변수는 쓸 수 있음
			System.out.println(sNum);
			System.out.println(iNum);
			System.out.println(sInNum);
		}

		static void sTest() {
			System.out.println(sNum);
			System.out.println(sInNum);
		}
	}
}
public class innerTest {

	public static void main(String[] args) {

		OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
		sInClass.inTest(); // 인스턴스 메서드
		OutClass.InStaticClass.sTest(); // 정적 메서드
	}

}

예제에서처럼 정적 내부 클래스는 외부 클래스의 멤버 변수와 동일한 위치에 구현되고, 메서드에서 외부 클래스의 인스턴스 변수를 업데이트할 수 없다.

지역 내부 클래스

지역 내부 클래스란 외부 클래스의 메서드 내부에 구현되며 메서드를 호출할 때 생성되는 내부 클래스이다. 지역 내부 클래스에서는 외부 클래스 변수 중 외부 인스턴스 변수와 외부 전역 변수를 사용할 수 있다.

아래는 지역 내부 클래스 예제이다.

class Outer {

	int outNum = 100;
	static int sNum = 200;


	public Runnable getRunnable(int i) {

		int localNum = 150;
        // 지역 내부 클래스 구현
		class MyRunnable implements Runnable {
        
			@Override
			public void run() {
				localNum += 100; // error. 외부 클래스 메소드의 지역 변수 수정 불가
				i += 100; // error. 외부 클래스 메소드의 매개변수 수정 불가
				System.out.println(outNum);
				System.out.println(sNum);
				System.out.println(localNum);
				System.out.println(i);
			}
		}
		return new MyRunnable();
	}
}
public class LocalInnerTest {

	public static void main(String[] args) {

		Outer outer = new Outer();
		outer.getRunnable(2).run();
	}
}

예제에서처럼 지역 내부 클래스는 외부 클래스의 메서드에 구현되고, 외부 클래스의 인스턴스 변수와 전역 변수를 사용할 수 있다. 하지만 메서드 내부에서만 사용되는 지역 변수와 매개 변수는 지역 내부 클래스에서 변경할 수 없다. 원래 매개 변수와 지역 변수는 메소드 호출 시 스택 메모리 영역에 생성되었다가 메소드 사용이 종료되면 스택 메모리 영역에서 사라진다. 외부 클래스의 메소드 호출 + 종료 후에 내부 클래스의 메소드가 호출되기 때문에 만약 외부 클래스 메소드의 지역 변수와 매개 변수가 스택 메모리에 들어간다면, 내부 클래스에서 이것을 사용할 수 없다. 그러므로 java8 이후로는 외부 클래스의 메소드에 내부 클래스가 구현된 상황이라면 해당 메소드의 매개 변수와 지역 변수를 내부적으로 final로 선언하여 클래스(정적) 메모리 영역에 저장하여 내부 클래스에서도 이것들에 접근할 수 있도록 하였다. (하지만 final로 선언된 변수들이기 때문에 수정은 할 수 없다.)

JVM 메모리 영역

익명 내부 클래스

익명 내부 클래스란 메서드 내부에 구현되거나 변수에 대입하여 직접 구현되며 이름이 없는 내부 클래스이다. 익명 내부 클래스는 메서드를 호출할 때 생성되거나, 인터페이스 타입 변수에 대입할 때 new 예약어를 사용하여 생성할 수 있다. 또한, 외부 인스턴스 변수와 외부 전역 변수를 사용할 수 있다.

아래는 익명 내부 클래스 예제이다.

class Outer {

	int outNum = 100;
	static int sNum = 200;

	// 익명 내부 클래스, 변수에 대입하여 구현
    // Runnable: 자바 내장 interface
	Runnable runnable = new Runnable() {
		public void run() {
			System.out.println("runnable");
		};
	};

	public Runnable getRunnable(int i) {
		int localNum = 150;
		// 익명 내부 클래스, 메서드 내에 구현
		return new Runnable() {
			public void run() {
				outNum += 10;
				System.out.println(outNum);
				System.out.println(sNum);
				System.out.println(localNum);
				System.out.println(i);
			};
		};
	}
}
public class LocalInnerTest {

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

위 예제처럼 익명 내부 클래스는 변수에 대입하거나 외부 클래스의 메소드 내에 구현된다. 또한, 이름에서 유추할 수 있듯이 이름 없이 객체를 생성하는 클래스이다.

profile
저는 AI 개발자 '웅'입니다. AI 연구 및 개발 관련 잡다한 내용을 다룹니다 :)

0개의 댓글