Java/정리

내부클래스

낭구리 2021. 9. 1. 18:30

● 클래스 내부에 선언한 클래스로 이 클래스를 감싸고 있는 외부 클래스와 밀접한 연관이 있는 경우가 많고,

다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스로 선언해서 사용함

● 중첩 클래스라고도 함

● 내부 클래스의 종류

인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local) 내부 클래스, 익명(anonymous) 내부 클래스

인스턴스 내부 클래스

● 내부적으로 사용할 클래스를 선언 (private으로 선언하는 것을 권장)

● 외부 클래스가 생성된 후 생성됨 ( 정적 내부 클래스와 다름 )

● private이 아닌 내부 클래스는 다른 외부 클래스에서 생성할 수 있음

OutClass outClass = new OutClass();
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(); // 내부 클래스 생성
	}

	private class InClass {

		int inNum = 100;
		// static int sInNum = 200; //에러 남

		void inTest() {
			System.out.println("OutClass num = " + num + "(외부 클래스의 인스턴스 변수)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
			System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
		}

		// static void sTest(){ //에러 남

		// }

	} // end of InClass (블록에 유요한 범위 확인)

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

} // end of OutClass (블록에 유요한 범위 확인)


// 실행해보는 InnerTest 클래스 
public class InnerTest {

	public static void main(String[] args) {
		OutClass outClass = new OutClass();
		System.out.println("외부 클래스 이용하여 내부 클래스 기능 호출");
		outClass.usingClass(); // 내부 클래스 기능 호출
		System.out.println();

//     내부 클래스에 private 선언하면 사용 불가  	    
//		OutClass.InClass inClass = outClass.new InClass();   // 외부 클래스를 이용하여 내부 클래스 생성
//		System.out.println("외부 클래스 변수를 이용하여 내부 클래스 생성");
//		inClass.inTest();
	}

} //  end of InnerTest

 

정적(static) 내부 클래스

class OutClass {

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

	static class InStaticClass {

		int inNum = 100;
		static int sInNum = 200;

		void inTest() { // 정적 클래스의 일반 메서드
			// num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
			System.out.println("InStaticClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수 사용)");
			System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
		}

		static void sTest() { // 정적 클래스의 static 메서드
			// num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
			// inNum += 10; // 내부 클래스의 인스턴스 변수는 사용할 수 없음
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
			System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");

		}

	}

}// end of OutClass

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();

	} // end of main

} // end of InnerTest

지역 내부 클래스 (메서드 내에 클래스)

● 지역 변수와 같이 메서드 내부에서 정의하여 사용하는 클래스

● 메서드의 호출이 끝나면 메서드에 사용된 지역변수의 유효성은 사라짐

● 메서드 호출 이후에도 사용해야 하는 경우가 있을 수 있으므로 지역 내부 클래스에서 사용하는 메서드의 지역 변

수나 매개 변수는 final로 선언됨

class Outer {
	
	int outNum = 100;
	static int sNum = 200;
	
	// Runnable 리턴타입의 메서드  	
	Runnable getRunnable(int i){

		int num = 100;
		
		class MyRunnable implements Runnable {

			int localNum = 10;
				
			@Override
			public void run() {
				//num = 200;   //에러 남. 지역변수는 상수로 바뀜
				//i = 100;     //에러 남. 매개 변수 역시 지역변수처럼 상수로 바뀜
				System.out.println("i =" + i); 
				System.out.println("num = " +num);  
				System.out.println("localNum = " +localNum);
					
				System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수)");
				System.out.println("Outter.sNum = " + Outer.sNum + "(외부 클래스 정적 변수)");
				}
			}
		 return new MyRunnable();
	}
}

public class LocalInnerTest {

	public static void main(String[] args) {

		Outer out = new Outer();
		Runnable runner = out.getRunnable(10);
		runner.run();
	}
}

익명 내부 클래스

● 이름이 없는 클래스 (위 지역 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없음)

● 클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환

● 인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부

에서 생성하여 반환 할 수 있음.

● 특징 중에 하나는 new 키워드 뒤에 원래는 인터페이스 구현 클래스 이름이 와야 하는데, 익명 구현 객체의 경우에

는 참조할 구현 클래스가 없기 때문에 User 인터페이스 이름을 그대로 사용합니다.

다만, 익명 구현 객체의 구현 부에는 인터페이스의 추상 메서드가 아닌 실체 메서드를 선언해야 합니다.

class Outter2{
		
	Runnable getRunnable(int i){

		int num = 100;
		
		return new Runnable() {
				
		@Override
		public void run() {
			//num = 200;   //에러 남
			//i = 10;      //에러 남
			System.out.println(i);
			System.out.println(num);
			}
		};
	}
	
	Runnable runner = new Runnable() {
		
		@Override
		public void run() {
			System.out.println("Runnable 이 구현된 익명 클래스 변수");
			
		}
	};
}

public class AnonymousInnerTest {

	public static void main(String[] args) {
		Outter2 out = new Outter2();
	
		Runnable runnerble = out.getRunnable(10);
		runnerble.run();
		
		out.runner.run();
	}
}

'Java > 정리' 카테고리의 다른 글

제네릭  (0) 2021.09.07
예외처리  (0) 2021.09.01
Object클래스  (0) 2021.09.01
인터페이스 활용예제  (0) 2021.08.31
인터페이스  (0) 2021.08.31