오늘 한 일

  • java 공부
    • 내부 클래스
      종류 구현 위치 사용할 수 있는
      외부 클래스 변수
      생성 방법
      인스턴스 내부 클래스 외부 클래스 멤버 변수와 동일 외부 인스턴스 변수
      외부 전역 변수
      외부 클래스를 먼저 만든 후 내부 클래스 생성
      정적 내부 클래스 외부 클래스 멤버 변수와 동일 외부 전역 변수 외부 클래스와 무관하게 생성
      지역 내부 클래스 메서드 내부에 구현 외부 인스턴스 변수
      외부 전역 변수
      메서드를 호출할 때 생성
      익명 내부 클래스 메서드 내부에 구현
      변수에 대입하여 직접 구현
      외부 인스턴스 변수
      외부 전역 변수
      메서드를 호출할 때 생성되거나, 인터페이스 타입 변수에 대입할 때 new 예약어를 사용하여 생성

      내부 클래스의 인스턴스나 생성자를 밖에서 접근하거나 사용할 수 는 있으니 일반적으로 내부 클래스는 내부에서만 사용하는 용도이므로 private으로 선언되는 경우가 대다수이다.

      • 인스턴스 내부 클래스
        인스턴스 내부 클래스에서는 static 예약어를 사용할 수 없다. 이는 외부 클래스의 인스턴스가 생성되어야 내부 클래스에 접근가능해지기 때문이다.

      • 정적 내부 클래스
        정적 내부 클래스는 외부 클래스의 객체 생성 없이도 내부 클래스의 객체를 생성할 수 있다. 또한 인스턴스 내부 클래스에서는 불가능 했던 static 변수나 메서드 선언이 가능하다. 대신 외부 인스턴스의 변수에는 접근이 불가능하다.

      • 지역 내부 클래스
        지역 내부 클래스는 메서드 내부에 구현되는 클래스이다.
        class Outer {
          int outNum = 100;
          static int sNum = 200;
        
          public Runnable getRunnable(final int i) {
            final int localNum = 100;
            class MyRunnable implements Runnable {
              @Override
              public void run() {
                // localNum += 100; // error
                // i += 200;        // error
                System.out.println(outNum);
                System.out.println(sNum);
                System.out.println(localNum);
                System.out.println(i);
              }
            }
        
            return new MyRunnable();
          }
        }
        

        지역 내부 클래스에서 메서드의 변수를 사용할 때는 주의가 필요한데, 이는 지역변수의 유효범위 때문이다. 위의 예제처럼 메서드의 반환 값으로 지역 내부 클래스의 인스턴스를 받았을 때, i와 localNum은 지역변수이므로 stack에 저장되었다가 메서드가 종료됨과 동시에 삭제된다.

        때문에 필요하다면 final로 선언해 stack이 아닌 상수 풀에 저장해야 한다. 단 final은 수정이 불가능하므로 참조는 가능하지만 할당은 불가능함에 유의해야 한다.

        cf) Java 8부터 지역 클래스에서 접근하는 지역 변수 앞에 final을 생략할 수 있다. 컴파일러가 후에 자동으로 붙여줄 뿐만 아니라 값을 수정하고자 하면 컴파일 에러도 띄워준다.

        외부 클래스의 인스턴스 멤버 변수나 정적 변수에는 해당 사항이 없다.

      • 익명 내부 클래스
        익명 내부 클래스는 단 하나의 추상 클래스나 인터페이스만을 구현할 수 있다.
        class OuterClass {
          int outNum = 100;
          static int sNum = 200;
        
          // 변수에 대입하여 직접 구현
          Runnable runnable = new Runnable() {
            @Override
            public void run() {
              System.out.println(outNum);
              System.out.println(sNum);
            }  
          };
        
          // 메서드 내부에 구현
          public Runnable getRunnable(final int i) {
            return new Runnable() {
              @Override
              public void run() {
                System.out.println(outNum);
                System.out.println(sNum);
              }
            };
          }
        }
        

참조