상세 컨텐츠

본문 제목

Java - 내부클래스(InnerClass)

개발/Java

by 뉴에이스 2018. 10. 16. 18:13

본문

 내부클래스 : 최상위 클래스에 포함된 클래스
 선언되는 위치와 방법에 따라서 4가지 종류로 구분
 class TopClass {
 	class Inner {}
     // 클래스 영역
 	메서드 () {
 		// 메서드 영역	
     }
 }
 
 1. 내부클래스(InnerClass)  
    : 인클로징 클래스의 변수를 접근할 수 있음
    : static이 붙지않은 클래스 영역에 선언된 클래스
    : 인스턴스 변수
    : 클래스에만 선언 가능하고 인터페이스에는 선언이 불가능함
    : 외부에서 참조시 - 인클로징 클래스의 이름.이너 클래스 이름     
    : 인클로징 외부에서 이너 클래스의 객체 생성하기
    	  Cart cart = new Cart(); 
       Cart.Item item = cart.new Item();
                       
 2. 정적내부클래스(StaticInnerClass) 
    : static이 붙은 클래스 영역에 선언된 클래스
    : 클래스 변수
    : static 변수나 메서드를 선언할 수 있음
    
 3. 지역내부클래스(LocalInnerClass) 
    : 메서드 안에 선언되는 내부 클래스
    
 4. InnerAnnoymous(익명) : 클래스, 메서드 영역에 선언됨, 이름이 없음
                         : 두가지 동시 처리 (클래스 선언, 객체 생성)
                         
    * 메서드 안에 선언된 클래스가 메서드의 지역변수를 참조할 때는
      final로 선언된 변수만 사용 가능함
    
 5. 정적내부 인터페이스
    - 내부 인터페이스는 정적 내부 인터페이스 한종류만 가능함  
    
 class Top { 									=> 탑 클래스
     class InnerMember { }						=> 내부 클래스 (멤버변수 자리에 선언)
     static class StaticMember {}				=> 정적 내부 클래스
     public void test () {
     	final int val = 100;					=> 지역 내부 클래스 (메서드 내에 선언, 이름이 있음)
     	class InnerLocalNamed {
     	    public void print() {
                 System.out.println(val);
             }
     	}
     	new Random[상위클래스, 인터페이스]() { }		=> 익명 클래스 (메서드 내에 선언, 이름이 없음), 이벤트방식으로 가장 많이 사용됨
     }
 }

 

소스

 

public class InnerTest {
	public void call(Parent p) {
	}
	public void call(Runnable r) {
	}
	public void test() {
		
		call(new Parent() {
			public void call() {
				System.out.println("재정의함");
			}
		});
		
		// 익명 클래스를 변수에 담아 사용
		Runnable r1 = new Runnable() {
			@Override
			public void run() {
				System.out.println("111");
			}
		};
		call(r1);
		// 익명 클래스를 바로 사용
		call(new Runnable() {
			@Override
			public void run() {
				System.out.println("111");
			}
		});
		
		/*
			Thread(Runnable r) // Runnable : API 제공 인터페이스
		*/
		
		Thread t2 = new Thread(r1);
		
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("111");
			}
		});
		
		/*
			class B extends Test      // 클래스 정의
			{
				int i = 1;
				public void call() {}
			}
		 
		 	Test t = new B();     // 객체 생성
		 
		 	-->
		 	익명클래스 :  객체 생성 + 클래스 정의
		 	Test t = new Test() 
		 	{
				int i = 1;
				public void call() {}
			};
		 
		 
		 	class Child1 extends Parent {
		 		public void call() {}
		 	}
		 	Parent p = new Child1();
		 	
		 	-->
		 	Parent p = new Parent() {
		 		public void call() {}
		 	};
		 */
		
		Runnable r = new MyRunnable();
		Thread t = new Thread(r);
		// 익명 클래스 : 객체 생성, 재정의
		Parent p = new Child();
		p.call();
		// new 상위클래스() { 클래스 재정의 } => 부모 클래스 재정의
		Parent p2 = new Parent() { // => 부모클래스를 재정의한 익명(자식) 클래스가 됨 
			public void call() {
				System.out.println("재정의함");
			}
		}; // p와 p2는 동일함.
		p2.call();
		
		// 익명클래스 형태
		// new 상위클래스[인터페이스]( ) {
		//     메서드 ..
		// }
		
		final int val = 100;
		class InnerLocal {
			public void call() {
				// 메서드에 선언된 지역변수 중 final 변수만 접근 가능
				System.out.println(val);
			}
		}
		InnerLocal local = new InnerLocal();
	}
	
	public static void main(String[] args) {
		Top top = new Top();
		// innerMember : non-static class
		Top.InnerMember innerMember = top.new InnerMember(); 
		System.out.println(innerMember.val);   //  100

		System.out.println(Top.StaticMember.val2);  // 200, static 변수만 접근
		Top.StaticMember.call();  // StaticMember
		Top.StaticMember innerStatic = new Top.StaticMember(); // static, non-statin 변수 모두 접근하기위해 객체 생성
		System.out.println(innerStatic.val);  // 100
		System.out.println(Top.StaticMember.val2);  // 200
		
		// 인터페이스
		System.out.println(TopInterface.Player.Address.addr);  // 인터페이스의 주소
		TopInterface.Player player = new TopInterface.Player() {
			@Override
			public void play() {
				System.out.println("인터페이스 play");
			}
			@Override
			public void call() {
				System.out.println("인터페이스 call");				
			}
		};
		player.play();  // 인터페이스 play
		player.call();  // 인터페이스 call
	}
}

class Top {
	String data;
	static String data2;
	
	class InnerMember { // Top 안에 있는 내부 클래스
		int val = 100;
//		static int val2 = 200;  // 오류, static이 붙지 않은 내부 클래스는 static 변수 선언이 안됨
		public void call() {
			System.out.println("InnerMember");
		}
		public void getEnclosing() {
			System.out.println(data); // 자기를 감싸고 있는 클래스내(외부클래스)에 선언된 일반 변수
			System.out.println(data2); // 자기를 감싸고 있는 클래스내(외부클래스)에 선언된 스태틱 변수
		}
	}
	static class StaticMember { // static 클래스
		int val = 100;
		static int val2 = 200; // static 클래스는 static 변수 선언 가능
		public static void call() {
			System.out.println("StaticMember");
		}
		
		public void getEnclosing() { // static 클래스내에서는 static 변수로만 접근 가능
//			System.out.println(data);  // non-static 접근 불가능
			System.out.println(data2); // static 접근 가능
		}
	}
}

interface TopInterface { // 인터페이스내에 내부 인터페이스 선언 가능
	static interface Player {  // 자동으로 static 가 붙는다.
		void play();
		void call();
		interface Address { // static 자동 생성
			String addr = "인터페이스의 주소"; // public static final 자동 생성
			// TopInterface.Plater.Address.addr
		}
	}
}
// 추상 클래스
abstract class Parent {
	abstract public void call();
}
// 추상 클래스를 상속받은 자식 클래스
class Child extends Parent {
	public void call() {
		System.out.println("재정의함");
	}
}
// Thread에서 사용되는 Runnable 클래스 재정의, 한번만 사용될 경우 내부클래스/익명클래스로 정의해서 사용
// new Runnable() { run 메서드 오버라이딩 };
/*
Runnable r = new Runnable() {
	public void run() {
		System.out.println("test");
	}
};
*/
class MyRunnable implements Runnable {
	@Override
	public void run() {
		System.out.println("test");
	}
}

 

결과

 

100
200
StaticMember
100
200
인터페이스의 주소
인터페이스 play
인터페이스 call

관련글 더보기

댓글 영역