15-Nested Class



중첩 클래스(nested class)

  • 중첩클래스 : 클래스 내부에 완전한 클래스가 구성될 수 있다.
class A{            // > Outer class 
  //멤버변수
  //메소드(){지역변수}
  //생성자
  class B{          // > Inner class (중첩 클래스)
    //멤버변수
  //메소드(){지역변수}
  //생성자
  }
}


왜 포함을 시켜 쓰는가?

  • 특정한 클래스를 한 클래스 내에서 한정해서 쓰고싶을 때
class A{ 
  B b1 = new B();
class B{ }
}

class C{ B b1 = new B(); // > 오류 
       A.B b1 = new A().newB(); // 가능
       } 

​ 경우 1)

Interface I1 ( mi1(); )
Interface I2 ( mi2(); )
Interface I3 ( mi3(); )
class F{
  f1(){}
  f2(){}
}
class D extends F implemnets I1, I2, I3{
  mi1(){overriding}
  mi2(){overriding}
  mi3(){overriding}
  // overriding 의무 
  f1(){}
  f2(){}
  // 선택적 overriding 
  
  // 추가 메소드
  d1(){ }  
}

// D class 안 메소드가 6개 
----------------------------------
  //클래스 안의 클래스 - 명확한 명시가 가능.
  //중첩 인터페이스도 가능. (다른 클래스 내부에 포함된 인터페이스)
  class D extends F implemnets I1, I2, I3{
  class I1sub implements I1{
     mi1(){overriding}
  }
     class I2sub implements I1{
     mi2(){overriding}
  }
     class I3sub implements I1{
     mi3(){overriding}
  }
    
  class FSub extends F{
    f1(){}
    f2(){}
  // 선택적 overriding 
  }
    
  // 추가 메소드
  d1(){ }  
}
  

경우2)

package day8;

class Outer{
	class Inner{ // non-ststic(=인스턴스) 멤버중첩클래스
		void m() {
			System.out.println("중첩클래스 메소드 실행");
		}
	}
    static class Inner2{ // static 멤버 중첩 클래스
    	  void m2() {
    		  System.out.println("중첩클래스 메소드 실행2");
    	  }
      }
    void test() {
    	//지역 중첩 클래스 
    	class Inner3{
    		void m3() {
    			System.out.println("중첩클래스 메소드 실행3");
    		}
    	}
    	  new Inner3().m3(); // 지역변수처럼 쓰이는 중첩 클래스에 대한 객체를 만들고, 호출도 이 안에서 해야
    }
  
}
//이너클래스는 멤버변수처럼 사용되기 때문에 static 가능 
public class InnerTest1 {

	public static void main(String[] args) {
		// Inner i = new Inner(); --- Outer class 안에 있는 것, 단독으로 객체 만들기 불가

		   Outer o = new Outer();
	       Outer.Inner i = o.new Inner(); 
	        //  =- Outer.Inner i = new Outer().new Inner();
		   i.m();
		   
		   Outer.Inner2 i2 = new Outer.Inner2(); // static일 경우 
		   i2.m2();
		   
		   o.test();
		 
	}
}
  • static은 객체가 생성되기 전에 메모리에 생성(미리 메모리 할당, 그래서 공유 가능), 객체를 만들면서 만들거나 이후에 만드는 것은 따라서 불가능하다.

  • 중첩클래스 중에서 instance 멤버클래스를 가지고 static 변수, static 메소드를 취급해서는 안된다. 사용이 불가.

    • static : 객체 생성 이전(프로그램 최초 시작) 메모리 할당 저장
    • 객체 1개 값만 공유, 이후 사용시 클래스명.xxx
    • static 중첩 내부 클래스 -> static 메소드 가능
    • 중첩내부클래스 - > static 메소드 불가
    • static끼리 정의된 것은 그것들끼리. // 메모리생성시기를 생각해보면 된다.
      • instance 멤버 내부 클래스 / 인터페이스
      • static 멤버 내부 클래스 / 인터페이스
      • 메소드 내부 - 지역 내부 클래스 / 인터페이스
      • 익명 내부 클래스 - 상속 인터페이스 구현, 객체 생성 / 인터페이스


  • 인터페이스
class A{
  class B{void m(){}}
  interface I{mi();}
  class C implements I{ mi(){ overriding } }
  // I 인터페이스 상속받은 하위클래스를 C라는 클래스로 정의
}
  • 익명 객체
class A{
  class B{void m(){}}
     interface I{mi();}
  class C implements I{ mi(){ overriding } }
  // I 인터페이스 상속받은 하위클래스를 C라는 클래스로 정의
}

-- main
C c1 = new C();
c1.mi();

I x = new I() {mi(){overriding}}
// I 인터페이스 상속받은 하위클래스를 익명의 클래스로 정의
// I 인터페이스 타입의 익명 객체를 생성한 것 
// 익명 클래스 정의와 객체 생성이 교차되어있는 표현. 
new I(){mi(){ovrriding}}.mi(); // 위와 같이 가능 
 // 익명클래스는 딱 한 번만 객체를 생성해서 쓸 것이라는 뜻, 다른 곳에서 사용하지 않음. 
x.mi();
상위클래스나 인터페이스명 변수 = new 상위클래스나 인터페이스명(){
  상위클래스나 인터페이스 상속 하위클래스 정의 ( = 무명 )
    추가멤버변수
    추가메소드
    상속오버라이딩
}

example

//무명객체 
		//interface Runnable { public void run(); }

		 class RunnableSub implements Runnable{
			public void run() {
				System.out.println("실행중");
			}
		}
		Runnable sub = new RunnableSub(); // 상위클래스 인터페이스 형변
		//메소드 호출
		Thread t1 = new Thread(sub);
		t1.start(); 
		
	    // 다음의 익명객체는 위와 같음 
		new Thread(new Runnable() {
			public void run() {
				System.out.println("실행중");
			}
		}).start();

​ 익명객체는 딱 한 번만 사용할것. 매소드는 하나일때가 유용하다


		interface myInter { 
	void mi1();
	void mi2();
}
---- main ----
		new myInter(){
			public void mi1() {
			     System.out.println("mi1");	
			}
			public void mi2() {
				System.out.println("mi2");
			}
		}.mi1();


		
		new myInter(){
			public void mi1() {
			     System.out.println("mi1");	
			}
			public void mi2() {
				System.out.println("mi2");
			}
		}.mi2();
// 2개의 메소드를 호출할 경우 익명객체는 이렇게 두 번을 작성해야 한다.
// 이 경우, 다음과 같은 식이 더 나으

		
		myInter i = new myInter(){
			public void mi1() {
			     System.out.println("mi1");	
			}
			public void mi2() {
				System.out.println("mi2");
			}
		};

i.mi1();
i.mi2();