본문 바로가기

자바

[자바기초요약9] 내부클래스

# 내부클래스
1 내부멤버클래스   외부클래스명$내부멤버클래스.class
2 내부지역클래스   외부클래스명$숫자 내부지역클래스.class 
3 내부무명클래스   외부클래스명$숫자.class 

[ex]
class A{                // A.class
      class B{}         // A$B.class
      void m1(){
            class C{}   // A$1C.class
            class D{}   // A$1D.class
      }
      void m2(){
            class C{}   // A$2C.class
            class E{}   // A$1E.class
      }
}


[ex]
class A{                     // A.class
      B o1=new B(){};        // A$1.class

      void m(){
            B o2=new B(){};  // A$2.class
      }
}
class B{}                     // B.class


# 내부멤버클래스

      외부클래스명.내부클래스명 변수=외부클래스주소.new 내부클래스명();      


[ex]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class A{
         int a=100;        
         class B{  
 
                  int b=200;
 
         }
 
}
class B{
         int c=300;
}
class C{
         public static void main(String args[]){
                  A o=new A();
 
          A.B o2=o.new B();                   //자료형이 A.B
 
          System.out.println(o.a);
 
          System.out.println(o2.b);                //위에 주소안만들고 바로 o.new B().b 해도됨 
 
                  B o3=new B();
 
          System.out.println(o3.c);
 
         }
 
}
cs




[ex] 내부클래스의 장점 : 외부클래스의 모든 멤버변수와 메서드를 객체생성없이 이용할 수 있다.

class A{
 private int a=100;
 class B{                                         //기생클래스
  void m(){
   System.out.println(a);
  }
 }
}
class C{
 public static void main(String args[]){
  A o=new A();
  A.B o2=o.new B();
  o2.m();
 }
}


[ex]   ??????????
class A{
 int a=100;
 class B{  
  int a=200;
  void m(){
   System.out.println(A.this.a); // 100             o.this.a    A.a   o.a  안됨!        new A().a 는 가능하나 객체생성을 이용한것임...   (상위클래스는 A.this를 이용해서 부름 )
   System.out.println(a);  // 200               this.a                                                                                                                                                         외부클래스명.this
  }
 } 
}
class C{
 public static void main(String args[]){
  A o=new A();
  A.B o2=o.new B();
  o2.m();
 }
}

 


[ex]
class A{
         int a=100;

         static void m1(){

                  System.out.println(new A().a);              //static이어서 A클래스의 a를 부를려면 A클래스의 주소값으로 불러야함 

         }
         void m2(){

                  System.out.println(this.a);                     //핵심은 C클래스에서 A클래스의 객채를 생성해주었기때문에 여기서 또다른 객체생성(new A().a )를 할필요없이

         }                                                                           //바로 this만 해주면됨 

}
 

class C{
         public static void main(String args[]){
                  A.m1();                                                      // static이어서 클래스명.메서드명으로 바로부를수 있음 

                  A o=new A();

                  o.m2();

         }

}


[ex]
class A{
 class B{
  int a=100;
 }
 static void m1(){                                        //static메서드라서 a를 부를려면 객체생성을 해줘야함 
  A o1=new A();
  A.B o2=o1.new B();                                //아니면 두문장을 하나로   A.B o2=new A().new B();  나타내도 의미는똑같음
  System.out.println(o2.a);                       //아니면 바로   new A().new B().a 해도 똑같음
 }
 void m2(){                                                  //원래 A o=new A();              (!! 3/29 1번 30분 볼것)
  A.B o2=this.new B();                               //      A.B o2=o.new B(); 인데 this를 통해 새로운 객체생성없이 C클래스에서 생성된객체를 이용 
  System.out.println(o2.a);                       // this는 C클래스에서 o.m2()의 o를 가리킴 (this 가 o를 가리킴 )
 }
}
class C{
 public static void main(String args[]){
  A.m1();
  A o=new A();
  o.m2();
 }
}
---------------------------------------------------   비교   
class A{
 class B{
  int a=100;
 }
 static void m1(){
  A o1=new A();
  B o2=o1.new B();                   //같은클래스안이라서 A.B o2 라 하지말고 B o2라고해도됨 
  System.out.println(o2.a); 
 }
 void m2(){
  B o2=new B();                                  
  System.out.println(o2.a);                    // 아니면 바로   new B().a           즉, A클래스안에서 B내부클래스의 멤버변수를 가질려면 단순히 주소만만들어주면됨
 }                                                               // 위처럼 A의주소값까짐 만들필요없음
}
class C{
 public static void main(String args[]){
  A.m1();
  A o=new A();
  o.m2();
 }
}

 

 

 

[ex] 메서드 m2를 here부분에서 호출하시오.

class A{
 int a=100;
 class B{
  int b=200;
 }
 void m(){
  //here
 }
}
class C{
 static void m2(A v1, A.B v2){
  System.out.println(v1.a); // 100
  System.out.println(v2.b); // 200
 }
}
class D{
 public static void main(String args[]){
  A o=new A();
  o.m();
 }
}
[an]  C.m2(this, this.new B());                // this.new B() 에서 this는 생략가능 

 

[ex] 메서드 m2를 here부분에서 호출하시오.

class A{
 int a=100;
 class B{
  int b=200;
  void m(){
   //here
  }
 }
}
class C{
 static void m2(A v1, A.B v2){
  System.out.println(v1.a); // 100
  System.out.println(v2.b); // 200
 }
}
class D{
 public static void main(String args[]){
  A o=new A();
  A.B o2=o.new B();
  o2.m();
 }
}
[an]  C.m2(A.this, this);                                  //new A()해도되지만 A.this 를 사용할수있어야함!


 

# Varags : 가변인수     ( 가변인수 두개이상을 쓸수없음,  가변인수와 다른인수를쓸경우 가변인수를 뒤에써야함)

[ex]
class A{
 public static void main(String args[]){
  B o=new B();
  o.m(1);
  o.m(1,2);
  o.m(1,2,3);
  o.m(1,2,3,4);
  o.m(1,2,3,4,5);
  o.m(new int[]{1,2,3,4,5,6});
 }
}
class B{
 void m(int... n){                          // int[] a=n;   n의 자료형은 int[]임   즉, n은 배열임 
  for(int num : n){                        // 따라서 int num : n 에서 n은 배열임 
   System.out.print(num+"\t");
  }
  System.out.println();
 }
}


# static import문( 밑에 예제처럼 하면 편하긴하지만 가독성이 떨어짐!!)   

[ex]
import static java.lang.System.out;           //out 은 멤버변수 , 즉 변수이름을 등록해준다!

class A{
 public static void main(String args[]){

  out.println(1);
  out.println(2);
  out.println(3);
  out.println(4);
  out.println(5);
  out.println(6);
  
 }
}





# 내부무명클래스 : 클래스선언+객체생성                                     ( 클래스 선언과 동시에 객체생성이 핵심! )
 객체를 전달하는 곳에 위치한다. (참조형의주소값이오는곳)                        {}                     new A()
 객체생성을 딱 한번만 할 수 있다. (하루살이클래스)..한번쓰이고 만다...재활용안됨...
 이름이 없는 클래스이다.

 new  부모클래스명(){                                        //혹은 상위클래스명
          //멤버변수,메서드,생성자.....
 };                                                                   // ; 꼭 써줄것!( 단 ( ) 안에서는 안써줌 )
 
[ex]
interface A{
 void m();
}
class B{
 public static void main(String args[]){
  A o=new A(){    // B$1.class                        // 다형적변수    //A가인터페이스라서 객체생성이안되지만 무명클래스를이용하여 생성가능 
   public void m(){                                          //반드시 오버라이딩해야함(인터페이스 A라서)
    System.out.println(100);
   }
  };  
  o.m();
 } 
}

[ex]
class A{
 void m(){
  System.out.println("aa");
 }
}
class B{
 public static void main(String args[]){
  A o=new A(){  // B$1.class                                       
   void m(){                                                   //클래스A가 interface가아니므로 굳이 오버라이딩안해도되나..???(안해도 실행은됨)
    System.out.println("bb");
   } 
   //void m1(){
   // System.out.prinln("cc");
   //} 
  }; 
  o.m();
  //o.m1();            //o는 다형적변수라서 오버라이딩된것만 부를수있음 m1()는 부를수없음!(형변환으로가능하나 무명! 이기때문에 불가능)
 } 
}
 
[ex]
interface AA{
 void test2();
}
class A{
 static void m(AA o){
  o.test2();                                 //결국 무명클래스를 넣는다...?(오버라이딩된것을...?)
 }
}
class B{
 public static void main(String args[]){
  AA o=new AA(){
   public void test2(){
    System.out.println("bb");
   }
  };
  A.m(o);
 }
}
 
[ex] here부분에 내부무명클래스를 선언하시오.
class A{
 B o=//here;   
 void m1(){
  Object o2=//here; 
 }
 C m2(){
  return //here;  
 }
 static void m3(D v){
 }
}
class B{
 void test(){
  A.m3(//here);  
 }
}
class C{}
class D{}
[an]                                   //무명클래스는 객체를 전달하는곳에 위치한다!
class A{
 B o=new B(){};   
 void m1(){
  Object o2=new Object(){}; 
 }
 C m2(){
  return new C(){};  
 }
 static void m3(D v){
 }
}
class B{
 void test(){
  A.m3(new D(){});    //이거는 ( ) 안이라서 new D(){}만써주면됨...  ; 필요없음 
 }
}
class C{}
class D{}
 
 
//밑에 예제를 하기전에 알고있어야할것!!
1.
class A{
            static void m(Object o){
            }
}
 
class B{
           void test(){
                 A.m(new Object());                      //모든클래스는 Object의자손이므로 어떠한 자손객체값으로도 m()을 호출할수 있다.
                 A.m(new A()); 
                 A.m(new B()); 
                 A.m(new 어떠한클래스); 
            }
}
 
 
2.여기서 test()에서 m()을 부를려면
interface AA{
           void test2();
}
 
class A{
           static void m(AA o){
                      o.test2();
}
 
class B{
          void test(){
          }
}
[an]
 
interface AA{
           void test2();
}
class AAA implements AA{
          public void test2(){                           //결국 자식AAA에 오버라이딩된것이출력됨!
                 System.out.println("aa");
         }
}
 
class A{
           static void m(AA o){                      //다형적 변수 AA o=new AAA() 이 되기때문에  new AAA().test2()가됨!
                      o.test2();
            }
}
class B{
          public static void main(String args[]){
                  A.m(new AAA());         //자식의값을 전달해줌...다형적변수..다형적변수는 자식에 오버라이딩된것을 호출 
         }                                         //new AA()를 넣으면안됨!
}
 
 
 
3. 2번처럼 AAA클래스로 상속을 통해 하지않고 바로 무명클래스로 이용하는방법 (이게바로 무명클래스임)
//방법2... 그냥 바로 넣어주되 ( ) 안이라서 ; 는 빼준다 .
interface AA{
              void test2();
}
class A{
           static void m(AA o){
                      o.test2();
           }
}
class B{
           public static void main(String args[]){
                        A.m(new AA(){
                               public void test2(){System.out.println(100);}
                               }
                        );
           }
}
 
//방법1
interface AA{
                 void test2();
}
class A{
           static void m(AA o){
                    o.test2();
          }
}
class B{
           public static void main(String args[]){
                         AA o=new AA(){
                                    public void test2(){ System.out.println(100); }
                         }; 
                   A.m(o);
          }
}
 
 
 
 
 
[ex] Button클래스의 addActionListener메서드를 호출하는 소스코드를 작성하시오.
/*
package java.awt.event;
interface ActionListener{
 void actionPerformed(ActionEvent e);
}

package java.awt.event;
public class ActionEvent{ }

package java.awt;
public class Button{
 public void addActionListener(ActionListener l){
 }
}
*/
import java.awt.*;
import java.awt.event.*;
class A{
 void m(){
  Button b=new Button();
  //here
 }
}
[an1] 클래스2개만들어짐 
import java.awt.*;
import java.awt.event.*;
class A{
 public static void main(String args[]){
  Button b=new Button();
  b.addActionListener(                                               
   new ActionListener(){                                  //단순히 new ActionListener()해주면 오류...(interface는객체생성안됨..하지만 무명클래스이용하면됨)
    public void actionPerformed(ActionEvent e){ }               //interface를 이용하므로 당연히 오버라이딩을 해주어야함          
   }
  );
 }
}

[an2] 클래스 하나만 만들어짐 (위와달리 내부무명이없음)
import java.awt.*;
import java.awt.event.*;
class A implements ActionListener{                             //객체생성이안되므로 그냥 상속으로정의후
 public void actionPerformed(ActionEvent e){ }             //바로 오버라이딩
 void m(){                               // this와 super는 static메서드(클래스메서드?)에서 사용할수없음... 여기서 this사용법을 하기위해서 메인메서드대신 m()으로전환
  Button b=new Button();            // 왜냐하면 static메서드는 모든곳에서 공유하기때문에...
  b.addActionListener(
   this                                               // (this)의 () 자리에는 ActionListener의자식은다올수있음 (그래서 implements 해줌)
  );                                                  //this는 A를 가리킴...??   ( ActionListener의자식인 A도 올수있음)
 }
}

[an3]  this와달리  다른클래스에서 상속받은것의 주소값인 new B()를 불러옴 
import java.awt.*;
import java.awt.event.*;
class B implements ActionListener{                           //클래스B를 따로만들어 인터페이스인부모를 상속받음 
 public void actionPerformed(ActionEvent e){ } 
}
class A{
  
 void m(){
  Button b=new Button();
  b.addActionListener(
   new B()                                                //상속을받은뒤 자식인B클래스를 호출(new B())하면 부모가 인터페이스라도 접근가능
  );
 }
}
 
 
 
 
//결국 
    Car car1=new Car();
    Car car2=new Car();   는 하나의클래스로 객체가 두번 생성된것이지만
 
    Car car1=new Car(){};
    Car car2=new Car(){}; 는 객체가 두번생성된것이아님!! 무명클래스하나당 각하나의객체임!!(클래스2개에 객체 하나식임)(객체생성을 한번만할수있음!)
그래서 쓰이는 용도는 위에 [an1]에서처럼 한번쓰이고 말때는 내부무명클래스를이용...!
 
 
 
 

# 메서드호출방식(주소전달방식, 값전달방식)
[ex]
class A{
 int a=100;
 void m1(){
  B.m2();
 }
 public static void main(String args[]){
  new A().m1();
 }
}
class B{
 static void m2(){
  System.out.println(a); // 100
 }
}
[an1] 클래스A의 객체를 두번생성하는 경우가 됨...
class A{
 int a=100;
 void m1(){
  B.m2();
 }
 public static void main(String args[]){
  new A().m1();
 }
}
class B{
 static void m2(){
  System.out.println(new A().a); // 100  
 }
}
 
[an2]  이미 만들어진 객체를 이용 !! 이렇게 해야함!!!
class A{
 int a=100;
 void m1(){
  B.m2(this);              //this 는 A클래스주소값
 }
 public static void main(String args[]){
  new A().m1();
 }
}
class B{
 static void m2(A o){            // A클래스주소값을 전달하기때문에  자료형은 A 
  System.out.println(o.a);
 }
}
 
[an3] 혹은 값전달을 이용할수도 있음( 하지만 만약 b나 c나 혹은 메서드를 전달하고자할때는 불편함... 위처럼 주소값을전달해버리면 A의모든것을 쓸수있음)
class A{
 int a=100;
 void m1(){
  B.m2(a);               }
 public static void main(String args[]){
  new A().m1();
 }
}
class B{
 static void m2(int b){  
  System.out.println(b);
 }
}
 
[ex] 리턴을통해 다른클래스의 지역변수를 부를수있다!!!( 다른클래스의 멤버변수는 단순히 부르고자하는클래스에서 주소생성.a 하면되지만 지역변수는안됨!)
class A{
 static int m(){
  int a=100;
  return a;
 }
}
class B{
 public static void main(String args[]){
  System.out.println(A.m());
 }
}

[ex] 컴파일될 수 있도록 메서드m을 수정하시오.
class A{}
class B{}
class C{
 static void m(){
  return new A();
  return new B();
 }
}
class D{
 public static void main(String args[]){
  A o1=C.m(1);
  B o2=C.m(2);
 }
}
 
[an]
static void ...

 






# 내부 로컬 클래스

[ex] 내부로컬클래스에서는 지역변수는 호출 할 수 없다.
 만약호출하길 원한다면 final선언을 해야한다.
class A{
   int a=100;
   void m1(){
        int b=200;        //지역변수  지역변수는 그메서드 내에서만 사용가능 
        class B{
              void m2(){
                    System.out.println(a); // 100
                    System.out.println(b); // 컴파일에러   
             }
        }
       B o2=new B();         //같은메서드에서 지역변수와 로컬클래스는 부를수 있음 
       o2.m2();
   }
}
 
class C{
   public static void main(String args[]){
       A o=new A();                  // o 는 지역변수... stack에 올라감 
       o.m1();
     //o.b;   다른클래스의 지역변수를 여기서 부를수없음
             //다른클래스의 지역클래스도 부를수없음 
             //다른클래스의 멤버클래스는 A.B o1=o.new B(); 이런식으로 부를수 있음!! 
    }
}
 

[an]
class A{
 int a=100;
 void m1(final int c){                         //final 은 메모리에 고정이라는 뜻도 가지고있음 (static도 되는데 static은 지역변수와 매개변수에 붙힐수없음)
  final int b=200; 
  class B{
   void m2(){
    System.out.println(a); // 100
    System.out.println(b); // 200
    System.out.println(c); // 300
   }
  }
  B o2=new B();
  o2.m2();
 }
}
class C{
 public static void main(String args[]){
  A o=new A();
  o.m1(300);
 }
}
-------------------------------------------------------------- 종강! 복습시작!!
 
 
[ex] 클래스A와 Dialog를 상속관계가 될 수 있도록 선언하시오.
/*
package java.awt;
public class Dialog{ 
 public Dialog(Frame f){           //public클래스는 생성자앞에 public이붙음
 } 
}
package java.awt;
public class Frame{
}
*/
class A{
}
[an1]
import java.awt.*;
class A extends Dialog{
 A(){               // 다른곳에서 호출할때 이런식으로해줌..A o=new A();               생성자라는것이 객체를 생성하는것인지..???
  super(new Frame());
 }
}
[an2]매개변수를 이용하는방법
import java.awt.*;
class A extends Dialog{
 A(Frame f){      // 다른곳에서 호출할때 이런식으로해줌.. A o=new A(new Frame());  결국 new Frame()를 A생성자안에 f에 넣고 그 f는 매개변수로 super(f)에 전달
  super(f);          // 만약 A o=new A(); 하면 오류남!!!!
 }
}
///위에것이 이해가안된다면 호출하는부분까지 보면...
[an1]
import java.awt.*;
class A extends Dialog{
     A(){
         super(new Frame()); 
    }
}
 
class C{
     public static void main(String[] args){
            A o=new A(); 
    }
}
 
[an2]
import java.awt.*;
class A extends Dialog{
       A(Frame f){         //매개변수방식으로 주소값을 전달 
           super(f);
}
}
 
class C{
       public static void main(String[] args){
              A o=new A(new Frame());
}
}
 
[ex] 클래스Choice의 addItemListener메서드를 호출하시오.
/*
package java.awt.event;
interface ItemListener{
 void itemStateChanged(ItemEvent e);
}
package java.awt;
public class Choice{
 public void addItemListener(ItemListener l){
 }
}
*/
import java.awt.*;
import java.awt.event.*;
class A{
 void m(){
  Choice c=new Choice();
  //here
 }
}
class B implements ItemListener{ 
 public void itemStateChanged(ItemEvent e){}
}

[an1] 상속관계에의해 인터페이스를 오버라이딩해주었으므로 자식의주소값을 전달하면 부모도 포함됨 
 c.addItemListener(new B());
 
[an2] 상속관계가없었다면.... 그냥 바로 내부무명클래스를 이용해서 객체생성과 동시에 클래스선언해줌
 
 c.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){}
});

 --------------------------------위,아래비교... 비슷한문제의 다른형식 (밑에는 B클래스가없음) 

[ex] 컴파일에러를 해결하시오.
/*
package java.awt.event;
interface ItemListener{
 void itemStateChanged(ItemEvent e);
}
package java.awt;
public class Choice{
 public void addItemListener(ItemListener l){
 }
}
*/
import java.awt.*;
import java.awt.event.*;
class A{
 void m(){
  Choice c=new Choice();
  c.addItemListener(this);
 }
}
[an]  this는 현재클래스A를 가리키므로 A를 불렀는데 오류가 안나게하려면 A가 ItemListener()메서드를 상속받으면됨!
import java.awt.*;
import java.awt.event.*;
class A implements ItemListener{
 public void itemStateChanged(ItemEvent e){
 }
 void m(){
  Choice c=new Choice();
  c.addItemListener(this);
 }
}
 

[ex] 아래소스코드가 컴파일에러 발생한 이유는 
 클래스B에서 변수tf를 발견하지 못하기 때문에 에러가 났다.
 그렇다면 클래스A의 변수tf를 클래스B에서 접근하려면?
import java.awt.*;
import java.awt.event.*;
class A extends Frame{
 TextField tf; 
 Button b;
 A(){
  tf=new TextField("aaa");
  b=new Button("bbb");
  b.addActionListener(new B());
  add(tf,"North");
  add(b,"Center");
 }
}
class B implements ActionListener{
 public void actionPerformed(ActionEvent e){
  System.out.println(tf.getText()); // 컴파일에러
 }
}
class C{
 public static void main(String args[]){
  A frame=new A();
  frame.setLocation(200,200);
  frame.pack();
  frame.setVisible(true);
 }
}
[an1]90점짜리정답(하지만 실행은 조금이상함)
 단순히   new A.tf.getText()     해주면 오류는 안남...하지만 원하는대로 실행은안됨..이미 메인메서드에서 new A()객체생성해주었기때문에 이렇게하지말것!
 
[an2]정답은 call by ref 주소값전달을 이용
import java.awt.*;
import java.awt.event.*; 

class A extends Frame{
 TextField tf; 
 Button b;
 A(){
  tf=new TextField("aaa");
  b=new Button("bbb");
  b.addActionListener(new B(this));     //생성자를 이용... 이미 메인에서 A의주소값을 생성해두었기때문에 this로 A주소값을 매개변수형식으로 전달..
  add(tf,"North");                                 //          ( 그런데 코딩할때 단순히 어디든지 A의 주소값만 생성해주면 this로 A의주소값을 사용가능한가..?? )
  add(b,"Center");
 }
}
class B implements ActionListener{
 A frame;         //매개변수로넘어온값을 멤버변수로 전달해줌
 B(A v){
  frame=v;
 }
 public void actionPerformed(ActionEvent e){  
  System.out.println(frame.tf.getText());  
 }
}
class C{
 public static void main(String args[]){
  A frame=new A();
  frame.setLocation(200,200);
  frame.pack();
  frame.setVisible(true);
 }
}