본문 바로가기

Java

Java 내부 클래스(inner class)

 

1. 내부 클래스(inner class)

- 클래스 안의 클래스

 

2. 내부 클래스의 장점

- 내부 클래스에서 객체 생성 없이 외부 클래스의 멤버에 쉽게 접근 가능

- 코드 복잡성 감소(캡슐화): 외부 클래스에 불필요한 클래스 감춤

 

3. 내부 클래스의 종류와 특징

내부 클래스 특징
인스턴스 내부 클래스
(instance class)
- 외부 클래스의 멤버변수 선언 위치에 선언
- 외부 클래스의 인스턴스 멤버처럼 다루어짐
- 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용
스태틱 내부 클래스
(static class)
- 외부 클래스의 멤버변수 선언 위치에 선언
- 외부 클래스의 static멤버처럼 다루어짐
- 주로 외부 클래스의 static멤버, static 메서드에서 사용될 목적으로 선언
지역 내부 클래스
(local class)
- 외부 클래스 메서드, 초기화 블럭내에 선언
- 선언된 영역 내부에서만 사용
익명 클래스
(anonymous class)
클래스의 선언과 객체의 생성을 동시에하는 이름 없는 클래스(일회용)

 

4. 내부 클래스의 제어자와 접근성

- 변수에 사용 가능한 제어자와 동일

- 내부 클래스도 클래스이기 때문에 제어자(abstract, final 등), 접근 제어자(private, protected 등) 사용 가능

 

5. 내부 클래스 예제

1) Static 내부 클래스만 static멤버를 갖음(단, final과 static이 동시에 붙은 변수는 상수이므로 모든 내부 클래스에서 정의 가능)

class Ex7_12 { 
	// 인스턴스 내부 클래스
	class InstanceInner { 
		int iv = 100; 
//		static int cv = 100;            // Error, static메서드 선언 불가 
		final static int CONST = 100;   // final static은 상수이므로 허용
	} 
	
   // static 내부 클래스
   static class StaticInner { 
		int iv = 200; 
		static int cv = 200;    // static클래스만 static멤버 정의 가능 
	} 
   
    // 지역 내부 클래스 
	void myMethod() { 
		class LocalInner { 
			int iv = 300; 
//			static int cv = 300;             // Error, static변수 선언 불가
			final static int CONST = 300;    // final static은 상수이므로허용
		} 
	} 

	public static void main(String args[]) { 
		System.out.println(InstanceInner.CONST); 
		System.out.println(StaticInner.cv); 
	} 
}

 

👇🏻 변수의 종류와 특징

더보기

 

선언 위치 변수의 종류 생성 시기 및 특징
클래스 영역 멤버
변수
인스턴스 변수
(iv: instance variable)
- 인스턴스(객체)가 생성되었을 때 생성
- 인스턴스마다 고유한 상태 유지해야하는 속성에 선언
클래스 변수
(cv: class variable)
- 클래스가 메모리에 올라갈 때 생성
- 인스턴스 변수 앞에 static 붙이면 클래스 변수 선언임
- 인스턴스마다 공통적인 값을 유지해야하는 속성에 사용
- 아무때나 사용 가능
클래스 영역 이외의 영역
(메서드, 생성자, 초기화 블럭 내부)
지역변수
(lv: local variable)
- 변수 선언문이 수행되었을 때 생성
- 선언된 메서드 안에서만 사용 가능
- 메서드 종료 시 자동 제거

 

2) 인스턴스 클래스는 외부 클래스의 인스턴스 멤버, static멤버를 객체 생성없이 사용 가능, static 클래스는 외부 클래스의 인스턴스 멤버를 객체 생성없이 사용 불가

class Ex7_13 {
	// 인스턴스 내부 클래스 
	class InstanceInner {}
	//static 내부 클래스 
	static class StaticInner {}

	// 인스턴스 멤버 간 직접 접근 가능 
	InstanceInner iv = new InstanceInner();
	// static 멤버 간 직접 접근 가능
	static StaticInner cv = new StaticInner();

	static void staticMethod() {      
		//InstanceInner obj1 = new InstanceInner();	 // static 멤버는 인스턴스 멤버에 직접 접근 불가
		StaticInner obj2 = new StaticInner();

		// 인스턴스 클래스는 외부 클래스를 먼저 생성해야 가능, 하지만 이렇게 사용하는 경우는 거의 없음
		Ex7_13 outer = new Ex7_13();
		InstanceInner obj1 = outer.new InstanceInner();
	}

	void instanceMethod() {		
		InstanceInner obj1 = new InstanceInner(); // 인스턴스 멤버는 인스턴스 멤버와 static 멤버 모두 접근 가능
		StaticInner obj2 = new StaticInner();		
		//LocalInner lv = new LocalInner(); // 지역 내부 클래스는 외부에서 접근할 수 없음
	}

	void myMethod() {
		class LocalInner {}
		LocalInner lv = new LocalInner();
	}
}

 

3) 외부 클래스가 아닌 다른 클래스에서 내부 클래스를 사용하는 경우 

-> 이 자체가 문제가 있음!(다른 클래스에서 사용할 만한 것을 내부 클래스로 만드는 것 자체가 좋지 않은 것)

class Outer2 {
	class InstanceInner {
		int iv = 100;
	}

	static class StaticInner {
		int iv = 200;
		static int cv = 300;
	}

	void myMethod() {
		class LocalInner {
			int iv = 400;
		}
	}
}

class Ex7_15 {
	public static void main(String[] args) {
		// InstanceInnr 내부 클래스는 Outer2 외부 클래스에서 사용하려고 만든건데, 다른 클래스에서 사용하려고하려고 하니까 번거롭게 외부 클래스 인스턴스 생성 후 내부 클래스 인스턴스를 생성하는 것
		Outer2 oc = new Outer2(); // 1. 외부 클래스 인스턴스 Outer2() 생성
		Outer2.InstanceInner ii = oc.new InstanceInner(); // 2.내부 클래스 인스턴스InstanceInner() 생성

		System.out.println("ii.iv : "+ ii.iv);
		
		System.out.println("Outer2.StaticInner.cv : "+Outer2.StaticInner.cv); // 상수이기 때문에 인스턴스 생성없이 사용
                                     
	   // 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 됨
		Outer2.StaticInner si = new Outer2.StaticInner(); // 외부클래스명.스태틱내부클래스()
		System.out.println("si.iv : "+ si.iv);
	}
}

 

6. 익명 클래스(anonymous class)

- 이름이 없는 일회용 클래스

- 정의와 생성이 동시에 되기 때문에 단 한번만 사용될 수 있고, 오직 하나의 객체만 생성할 수 있음

/** 익명 클래스의 정의와 생성
* 1. 클래스명이 없기 때문에 조상클래스명 또는 인터페이스명을 사용하여 정의
* 2. 클래스명이 없기 때문에 new 조상클래스명() {}  또는 new 인터페이스명() {}
*/

new 조상클래스명() {
 // 멤버 선언
 }
 
 또는
 
 new  인터페이스명() {
  // 멤버 선언
 }
 
 
// (일반) 클래스의 정의와 생성
// 1. 클래스 정의
class MyClass {
}

// 2. 객체 생성
MyClass myClass = new MyClass();

- 단 하나의 클래스를 상속받거나, 단 하나의 인터페이스만 구현 가능

 

📝 단 한번만 사용할 클래스를 정의할 때 사용! 코드가 단순해지기 때문에 필요 시 사용하면 됨