CH9. 중첩 선언과 익명 객체

a.rubz·2023년 1월 12일
0

이것이 자바다

목록 보기
13/15
post-thumbnail
post-custom-banner

9.1 중첩 클래스

중첩 클래스 (Nested Class)

  • 클래스 내부에 선언한 클래스

중첩 클래스 장점

  • 클래스의 멤버 쉽게 사용 가능
  • 외부에는 중첩 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있음 (유지보수에 도움)

중첩 클래스 종류

  • 멤버 클래스 : 클래스의 멤버로서 선언되는 중첩 클래스
  • 로컬 클래스 : 클래스의 메소드 내부에서 선언되는 중첩 클래스
선언 위치에 따른 분류선언 위치객체 생성 조건
멤버 클래스 - 인스턴스 멤버 클래스
class A {
class B { ... }
}
A 객체를 생성해야만
B 객체를 생성할 수 있음
멤버 클래스 - 정적 멤버 클래스
class A {
static class B { ... }
}
A 객체를 생성하지 않아도
B 객체를 생성할 수 있음
로컬 클래스
class A {
void method() {
class B { ... }
}
}
method가 실행해야만
B 객체를 생성할 수 있음

중첩 클래스의 바이트코드 파일

  • 멤버 클래스 : A $ B .class
  • 로컬 클래스 : A $1 B .class


9.2 인스턴스 멤버 클래스

인스턴스 멤버 클래스

  • 클래스의 멤버로 선언된 클래스
  • B 클래스는 A 클래스의 인스턴스 필드값, 생성자, 인스턴스 메소드에서 생성 가능
  • A 객체가 있어야 B 객체도 생성할 수 있기 때문
  • B 클래스 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언 가능
  • (Java17~) B 클래스 내부에 정적 필드, 정적 메소드 선언 가능
[public] class A {
  //B는 인스턴스 멤버 클래스
  [public | private] class B {
  }
}
A a = new A();
A.B b = a.new B();

접근 범위

  • 주로 A 클래스 내부에서 사용해 private 일반적
  • public class B {} : 다른 패키지에서 B 사용 가능
  • class B {} : 같은 패키지에서만 B 사용 가능
  • private class B {} : A 클래스 내부에서만 B 사용 가능

인스턴스 멤버 클래스 예시

public class A {
    
    //인스턴스 멤버 클래스
    class B {
        //인스턴스 필드
        int filed1 = 1;
        
        //정적 필드(Java17~)
        static int field2 = 2;
        
        //생성자
        B() {
            System.out.println("B 생성자");
        }
        
        //인스턴스 메소드
        void method1() {
            System.out.println("B method1")
        }
        
        //정적 메소드(Java17~)
        void static method2() {
            System.out.println("B method2")
        }
    }
    
    //여기부터는 A
    //인스턴스 필드 값으로 B 객체 대입
    B field = new B();
    
    //A 생성자
    A() {
        B b = new B();
    }
    
    //인스턴스 메소드
    void useB() {
        //B 객체 생성 및 인스턴스 필드 및 메소드 사용
        B b = new B();
        System.out.printIn(b.field1);
        b.method1();
        
        //B 클래스의 정적 필드 및 메소드 사용
        System.out.println(B.filed2);
        B.method2();
    }
}


9.3 정적 멤버 클래스

정적 멤버 클래스

  • static 키워드와 함께 클래스의 멤버로 선언된 클래스
  • B 객체는 A 클래스 내부 어디든 객체 생성 가능
  • A 객체 생성 없이 A 클래스로 접근해서 B 객체 생성 가능
  • B 클래스 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언 가능
[public] class A {
  [public | private] static class B {
  }
}
//A a = new A(); 없어도 됨
A.B b = new A.B();

접근 범위

  • A 클래스 외부에서 A 클래스와 함께 쓰이는 경우가 많아 주로 default, public
  • public static class B {} : 다른 패키지에서 B 사용 가능
  • static class B {} : 같은 패키지에서만 B 사용 가능
  • private static class B {} : A 클래스 내부에서만 B 사용 가능

정적 멤버 클래스 예시

  • 인스턴스 멤버 클래스와 달리 A 클래스의 정적 필드, 정적 메소드에서 생성 가능
public class A {
    
    //정적 멤버 클래스
    static class B {
        //인스턴스 필드
        int filed1 = 1;
        
        //정적 필드(Java17~)
        static int field2 = 2;
        
        //생성자
        B() {
            System.out.println("B 생성자");
        }
        
        //인스턴스 메소드
        void method1() {
            System.out.println("B method1")
        }
        
        //정적 메소드(Java17~)
        void static method2() {
            System.out.println("B method2")
        }
    }
    
    //여기부터는 A
    //인스턴스 필드 값으로 B 객체 대입
    B field = new B();
    
    //정적 필드 값으로 B 객체 대입
    static B field2 = new B();
    
    //A 생성자
    A() {
        B b = new B();
    }
    
    //인스턴스 메소드
    void useB() {
        //B 객체 생성 및 인스턴스 필드 및 메소드 사용
        B b = new B();
        System.out.printIn(b.field1);
        b.method1();
        
        //B 클래스의 정적 필드 및 메소드 사용
        System.out.println(B.filed2);
        B.method2();
    }
    
    //정적 메소드
    static void useB2() {
        B b = new B();
    }
}


9.4 로컬 클래스

로컬 클래스 (Local class)

  • 생성자 또는 메소드 내부에서 선언된 클래스
  • 생성자와 메소드가 실행될 동안에만 객체 생성 가능
  • 로컬 클래스 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언이 올 수 있음
  • 정적 필드와, 정적 메소드는 Java 17부터 가능
//A 내부에서 B 사용
public class A {
    //생성자
    public A() {
        // 로컬 클래스 선언
        class B { ... }
        
        //로컬 객체 생성
        B b = new B();
    }
    
    //메소드
    void method() {
        //로컬 클래스 선언
        class B { ... }
        
        //로컬 객체 생성
        B b = new B();
    }
}
//A의 메소드 내부에 있으니 A 객체 필요
A a = new A();
a.method();

로컬 변수를 로컬 클래스에서 사용할 경우

  • 로컬 변수 : 생성자 또는 메소드의 매개변수 또는 내부에서 선언된 변수
  • 로컬 변수는 final 특성을 갖게 됨 (읽기O, 수정X)
  • 로컬 클래스 내부에서 값을 변경하지 못하도록 제한하기 때문
  • (Java 8~) final 키워드 생략 가능
public class A {
    //매개변수에 선언된 변수 arg (로컬 변수)
    public void method1(int arg) {
        //내부에서 선언된 변수 (로컬 변수)
        int var = 1;
        
        //로컬 클래스
        class B {
            void method2() {
                //로컬 변수 읽기 가능
                System.out.println(arg);
                System.out.println(var);
                
                //로컬 변수 수정 불가
                //arg = 2;
                //var = 2;
            }
        }
        
        B.b = new B();
        b.method();
        
        //로컬 변수 수정 불가
        //arg = 2;
        //var = 2;
    }
}


9.5 바깥 멤버 접근

바깥 클래스의 멤버 접근 제한

  • 인스턴스 멤버 클래스 : 바깥 클래스의 모든 필드와 메소드 사용 가능
  • 정적 멤버 클래스 : 바깥 클래스의 정적 필드와 정적 메소드 사용 가능
  • 정적 멤버 클래스는 바깥 객체가 없어도 사용 가능해야 하기 때문에 인스턴스 필드, 인스턴스 메소드 사용 불가

바깥 클래스의 객체 접근

  • 중첩 클래스 내부에서 this는 해당 중첩 클래스의 객체
  • 중첩 클래스 내부에서 바깥 클래스의 객체 => 바깥클래스이름.this
  • 보통 중첩 클래스와 바깥 클래스의 인스턴스 필드와 메소드의 이름이 동일할 경우 사용
public class A {
    int field1;
    int field2;
    void method1() {}
    void method2() {}
    
    class B {
        int field2;
        void method2() {}
        
        void example() {
            //동일하지 않은 이름
            field1 = 10;
            method1();
            
            //동일한 이름
            //B의 필드와 메소드 사용
            System.out.println(this.field2);
            this.method2();
            
            //A의 필드와 메소드 사용
            System.out.println(A.this.field2);
            A.this.method2();
        }
    }
}


9.6 중첩 인터페이스

중첩 인터페이스

  • 클래스의 멤버로 선언된 인터페이스
  • 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해 사용
  • public, default, private 모두 가능
  • 객체 없이 인터페이스 사용하려면 static 추가
  • 안드로이드와 같은 UI 프로그램에서 이벤트 처리를 목적으로 활용
class A {
    [public | private] [static] interface B {
        //상수 필드
        //추상 메소드
        //디폴트 메소드
        //정적 메소드
    }
}

예시

  • 버튼에 어떤 ClickListener 구현 객체가 설정되었느냐에 따라 실행 결과 달라짐 => 다형성
public class Button {
    //정적 멤버 인터페이스
    public static interface ClickListener {
        //추상 메소드
        void onClick();
    }
    
    //필드
    private ClickListener clickListener;
    
    //메소드
    public void setClickListener(ClickListener clickListener) {
        this.clickListener = clickListener;
    }
    
    public void click() {
        this.clickListener.onClick();
    }
}
public class ButtonExample {
    public static void main(String[] args) {
        //ok버튼 객체 생성
        Button btnOk = new Button();
        
        //Ok 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
        class OkListener implements Button.ClickListener {
            @Override
            public void onClick() {
                System.out.println("Ok 버튼 클릭")
            }
        }
        
        //Ok 버튼 객체에 ClickListener 구현 객체 주입
        btnOk.setClickListener(new OkListener());
        
        btnOk.click(); //Ok 버튼 클릭 출력
        
        //---------------------------------
        
        //Cancel버튼 객체 생성
        Button btnCancel = new Button();
        
        //Ok 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스)
        class CancelListener implements Button.ClickListener {
            @Override
            public void onClick() {
                System.out.println("Cancel 버튼 클릭")
            }
        }
        
        //Cancel 버튼 객체에 ClickListener 구현 객체 주입
        btnCancel.setClickListener(new CancelListener());
        
        btnCancel.click(); //Ok 버튼 클릭 출력
    }
}


9.7 익명 객체

익명 객체

  • 이름이 없는 객체
  • 명시적으로 클래스를 선언하지 않아 쉽게 객체 생성
  • 필드값, 로컬 변수값, 매개변수값으로 주로 사용
  • 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있음
  • 클래스 상속 => 익명 자식 객체
  • 인터페이스 구현 => 익명 구현 객체

익명 자식 객체
=> 따로 자식 객체를 여러 개 만들지 않고 부모 객체 안에서 다 정의

  • 부모 클래스를 상속받아 생성
  • 부모 타입의 필드, 로컬 변수, 매겨변수의 값으로 대입 가능
  • 중괄호 블록 안의 필드와 메소드는 중괄호 안에서만 사용 가능
  • 중괄호 블록 안에는 주로 부모 메소드를 재정의하는 코드
new 부모생성자(매개값, ... ) {
  //필드
  //메소드
}

익명 구현 객체
=> 구현 객체를 따로 만들지 않고, 인터페이스 구현을 통해 정의

  • 인터페이스를 구현해서 생성
  • 인터페이스 타입의 필드, 로컬변수, 매개변수 값으로 대입 가능
  • 안드로이드와 같은 UI 프로그램에서 이벤트를 처리하는 객체로 많이 사용
  • 중괄호 블록 안의 필드와 메소드는 중괄호 안에서만 사용 가능
  • 중괄호 블록 안에는 주로 인터페이스의 추상 메소드를 재정의하는 코드
new 인터페이스() {
  //필드
  //메소드
}
profile
🔥 개발 공부 🔥
post-custom-banner

0개의 댓글