내부클래스(Inner Class)

  내부클래스란 클래스 내부에 구현한 클래스(중첩된 클래스)다.

  내부클래스에서 외부클래스의 멤버들을 쉽게 접근할 수 있고 외부에 불필요한 클래스를 감춰서

  코드의 복잡성을 줄일 수 있다.

  두 클래스가 서로 긴밀한 관계가 있을 때 내부클래스를 사용한다.

  주로 외부클래스 생성자에서 내부클래스를 생성한다.

 

종류

구현 위치

사용할 수 있는

외부 클래스 변수

생성 방법

인스턴스 내부 클래스

외부 클래스 멤버 변수와 동일

외부 인스턴스 변수

외부 전역변수

외부 클래스를 먼저 만든 후 내부 클래스를 생성

정적 내부 클래스

외부 클래스 멤버 변수와 동일

외부 전역변수

외부 클래스와 무관하게 생성

지역 내부 클래스

메서드 내부에 구현

외부 인스턴스 변수

외부 전역 변수

메서드를 호출할 때 생성

익명 내부 클래스

메서드 내부에 구현하거나

변수에 대입하여 직접 구현

외부 인스턴스 변수

외부 전역 변수

메서드를 호출할 때 생성되거나, 인터페이스 타입 변수에 대입할 때 new 예약어를 사용하여 생성

 

예제코드

class OutClass {
  private int num = 10;
  private static int sNum = 20;
  private InClass inClass;
  
  public OutClass() {
    inClass = new InClass();
  } //Constructor End
  //innerClass를 주로 OutClass의 Constructor에서 많이 생성한다.
  
  class InClass() {
    int iNum = 100;
    
    void inTest() {
      System.out.println(num);
      System.out.println(sNum);
    }
  } //InClass End
  /*
    InnerClass다. 메서드 안에 있는 것도 아니고
    static이 붙은것도 아니기 때문에 instance Inner Class다.
    안에 있는 변수인 iNum의 경우는 static를 붙이면 에러가 발생한다.
    InnerClass는 생성이후에 쓸 수 있는 클래스인데
    static은 생성과 관계없이 쓸 수 있기 때문에 오류가 발생한다.
    물론 클래스에도 static을 붙인다면 문제가 되지 않지만
    현재는 Instance Inner Class 이고 OutClass 이후에 생성되야 하기
    때문에 사용할 수 없다.
  */
  
  public void usingInner() {
    inClass.inTest();
  }
  
  static class InStaticClass {
    //static Inner Class이며 OutClass의 생성 여부와 상관없이 사용된다.
    
    int inNum = 100;
    static int sInNum = 200;
    
    void inTest() {
      System.out.println(inNum);
      System.out.println(sInNum);
      System.out.println(sNum);
    }
    
    static void sTest() {
      System.out.println(sInNum);
      System.out.println(sNum);
    }
    /*
      static 클래스이기 때문에 static 변수나 static 메서드를 만들 수 있다.
      여기서 static이 아닌 inNum은 사용할 수 없다.
      inNum의 경우는 static 메서드들 보다 나중에 생성되기 때문이다.
    */
  } //InStaticClass End
} //OutClass End
  

public class InnerTest {
  
  public static void main(String[] args) {
    OutClass outClass = new OutClass();
    
    outClass.usingInner();
    //InClass를 private변수로 만들었기 때문에 부를 수 없다.
    //그래서 usingInner를 만들어서 호출한다.
    
    OutClass.InClass myInClass = outClass.new InClass();
    //많이 쓰는 문법은 아니라고 한다.
    //outClass에서만 쓰려고 InnerClass를 사용하는 것인데
    //이렇게 사용할거면 InnerClass로 만들어줄 필요가 없기 때문이다.
    //문법적으로는 사용이 가능하다는 것이고
    //이렇게 사용하는것도 방지하고자 한다면 InClass를 Private 으로 만들어주면 된다.
    
    System.out.println();
    
    OutClass.InStaticClass.sTest();
    /*
      static메서드는 이렇게 호출해서 사용할 수 있다.
      하지만 inTest메서드는 static 메서드가 아니기 때문에
      이렇게 호출 할 수는 없다.
      inTest 메서드는
      OutClass.InStaticClass.sInClass = new OutClass.InStaticClass();
      sInClass.inTest();
      이렇게만 호출이 가능하다.
      sTest()도 이렇게 호출할 수 있다.
    */
  }
} //InnerTest End

 

//지역 내부 클래스

class Outer {
  int outNum = 100;
  static int sNum = 200;
  
  Runnable getRunnable(int i) {
    int num = 100;
    class MyRunnable implements Runnable {
      
      @Override
      public void run() {
        //이렇게 메서드 안에 클래스를 만들면
        //지역 내부 클래스이다.
        
        System.out.println(num);
        System.out.println(i);
        System.out.println(outNum);
        System.out.println(Outer.sNum);
        
        /*
          여기서 num과 i는 메서드 안에 있는 지역변수다.
          이 메서드가 호출되서 끝날때까지만 유효한게
          지역변수이지만 MyRunnable이 반환되고 나면
          이 메서드가 끝난 다음에도 run은 언제든지
          호출 될 수 있다.
          그럼 이 run이 호출되었을 때는 지역변수이기 때문에
          변수가 유효하지 않게 된다.
          그래서 지역내부 클래스가 쓰이는 메서드에서 변수들은
          상수가 된다.
        */
      } //run method End
    }//MyRunnable End
    
    return new MyRunnable();
  } //getRunnable End
} //Outer End

public class LocalInnerClassTest {
  
  public static void main(String[] args) {
    Outer outer = new Outer();
    Runnable runnable = outer.getRunnable(50);
    
    runnalbe.run();
  }
} //Test End

 

 

//익명 이너 클래스

class Outer {
  int outNum = 100;
  static int sNum = 200;
  
  Runnable getRunnable(int i) {
    int num = 100;
    return new Runnable() {
      @Override
      public void run() {
        Sytem.out.println(num);
        Sytem.out.println(i);
        Sytem.out.println(outNum);
        Sytem.out.println(sNum);
      }
    };
    //익명 이너클래스다. 이름이 없는 이너클래스.
  }
  
  Runnable runner = new Runnable() {
    @Override
    public void run() {
      System.out.println("test");
    }
  };
  /*
    이렇게도 작성할 수 있다.
    익명 이너 클래스는 바로 인터페이스나 추상클래스에 대한 생성을
    바로 할 수 있다.
    원래는 상속받은 클래스를 만들도 클래스를 생성해서 사용했는데
    단 하나의 인터페이스나 단 하나의 추상클래스인 경우는
    클래스의 이름없이 new 키워드를 이용해 생성할 수 있다.
  */
} //Outer End

public class AnonymousInnerClassTest {
  
  public static void main(String[] args) {
    Outer outer = new Outer();
    outer.runner.run();
    
    Runnable runnable = outer.getRunnable(50);
    
    runnable.run();
  }
} //Test End
        

 

 

레퍼런스

 패스트캠퍼스 올인원 패키지 - 자바 객체지향프로그래밍

'JAVA' 카테고리의 다른 글

컬렉션 프레임워크(Collection Framework)  (0) 2021.02.08
예외처리(Exception)  (0) 2021.02.07
Class 클래스  (0) 2021.02.04
Object 클래스  (0) 2021.02.03
final 키워드  (0) 2021.02.02

+ Recent posts