본문 바로가기

BackEnd/Java

[java] 이것이 자바다 ch09 중첩 선언 2 및 익명 객체

728x90
반응형

1. 뱌깥 멤버의 접근

 

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

   ▷ 정적 멤버 클래스 내부에서는 바깥 클래스의 필드와 메소드를 사용할 때 제한이 따릅니다.

◎ 바깥 클래스의 사용 가능한 멤버
   ▷ 인스턴스 멤버 클래스 : 바깥 클래스의 모든 필드와 메소드
   ▷ 정적 멤버 클래스 : 바깥 클래스의 정적 필드와 정적 메소드

 

   ▷ 정적 멤버 클래스는 바깥 객체가 없어도 사용 가능해야 하므로 바깥 클래스의 인스턴스 필드와 인스턴스 메소드는 사용하지 못합니다.

 

◎ 바깥 클래스 접근 제한 예제

public class A { ​​​​// A의 인스턴스 필드와 메소드 ​​​​int field1; ​​​​void method1() { } ​​​​ ​​​​// A의 정적 필드와 메소드 ​​​​static int field2; ​​​​static void method2() { } ​​​​ ​​​​// 인스턴스 멤버 클래스 ​​​​class B{ ​​​​​​​​void method() { ​​​​​​​​​​​​// A의 인스턴스 필드와 메소드 사용 ​​​​​​​​​​​​field1 = 10; ​​​​​​​​​​​​method1(); ​​​​​​​​​​​​ ​​​​​​​​​​​​// A의 정적 필드와 메소드 사용 ​​​​​​​​​​​​field2 = 10; ​​​​​​​​​​​​method2(); ​​​​​​​​} ​​​​} ​​​​ ​​​​// 정적 멤버 클래스 ​​​​static class C{ ​​​​​​​​void method() { ​​​​​​​​​​​​// A의 인스턴스 필드와 메소드 사용 ​​​​​​​​​​​​// field1 = 10; ​​​​​​​​​​​​// method1(); ​​​​​​​​​​​​ ​​​​​​​​​​​​// A의 정적 필드와 메소드 사용 ​​​​​​​​​​​​field2 = 10; ​​​​​​​​​​​​method2(); ​​​​​​​​} ​​​​} }


인스턴스 멤버들은 정적 클래스에서 사용하지 못합니다.
정적 멤버들은 인스턴스 클래스에서 사용하지 못합니다.

 

◎ 바깥 클래스의 객체 접근

   ▷ 중첩 클래스 내부에서 바깥 클래스의 객체를 얻으려면 바깥 클래스 이름에 this를 붙입니다.

바깥클래스이름.this → 바깥 객체

 

◎ 바깥 클래스 객체 접근 예제

1. A 클래스
public class A { ​​​​// A 인스턴스 필드 ​​​​String field = "A-field"; ​​​​ ​​​​// A 인스턴스 메소드 ​​​​void method() { ​​​​​​​​System.out.println("A-method"); ​​​​} ​​​​ ​​​​// 인스턴스 멤버 클래스 ​​​​class B{ ​​​​​​​​// B 인스턴스 필드 ​​​​​​​​String field = "B-field"; ​​​​​​​​ ​​​​​​​​// B 인스턴스 메소드 ​​​​​​​​void method() { ​​​​​​​​​​​​System.out.println("B-method"); ​​​​​​​​} ​​​​​​​​ ​​​​​​​​// B 인스턴스 메소드 ​​​​​​​​void print() { ​​​​​​​​​​​​// B 객체의 필드와 메소드 사용 ​​​​​​​​​​​​System.out.println(this.field); ​​​​​​​​​​​​this.method(); ​​​​​​​​​​​​ ​​​​​​​​​​​​// A 객체의 필드와 메소드 사용 ​​​​​​​​​​​​System.out.println(A.this.field); ​​​​​​​​​​​​A.this.method(); ​​​​​​​​} ​​​​} ​​​​ ​​​​// A의 인스턴스 메소드 ​​​​void useB() { ​​​​​​​​B b = new B(); ​​​​​​​​b.print(); ​​​​} }

 

2. AExample 메인 클래스
public class AExample { ​​​​public static void main(String[] args) { ​​​​​​​​// A 객체 생성 ​​​​​​​​A a = new A(); ​​​​​​​​ ​​​​​​​​// A 메소드 호출 ​​​​​​​​a.useB(); ​​​​​​​​ ​​​​} } // 출력 : // B-field // B-method // A-field // A-method​

 

 

2. 중첩 인터페이스

   ▷ 해당 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해 클래스 멤버로 선언된 인터페이스

class A { ​​​​[public | private][static] interface B{ ​​​​​​​​// 상수 필드 ​​​​​​​​// 추상 메소드 ​​​​​​​​// 디폴트 메소드 ​​​​​​​​// 정적 메소드 ​​​​} }

 

 ▷ 안드로이드 같은 UI 프로그램에서 이벤트를 처리할 목적으로 많이 활용합니다.

public class Button{ ​​​​// 정적 중첩 인터페이스 ​​​​public static interface ClickListener{ ​​​​​​​​// 추상 메소드 ​​​​​​​​void onClick(); ​​​​} }

 

◎ 중첩 인터페이스 예제

1. Button 클래스
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(); ​​​​} }


인터페이스를 통해 onclick이라는 메소드를 만들고 따로 private 변수를 만들어 set을 통해 변수를 클래스로 지정할 수 있게 만들고 click 함수를 통해 인터페이스의 onclick메소드를 부를 수 있습니다.

이때, this.clickListener.onClick()은 clickListener 인터페이스에 있는 onclick 메소드를 지정한다는 말입니다.


2. buttonExample 클래스

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()); ​​​​​​​​ ​​​​​​​​// Ok 버튼 클릭하기 ​​​​​​​​btnOk.click(); ​​​​​​​​ ​​​​​​​​//------------------------------------------------------ ​​​​​​​​ ​​​​​​​​// Cancle 버튼 객체 작성 ​​​​​​​​Button btnCancel = new Button(); ​​​​​​​​ ​​​​​​​​// Cancle 버튼 클릭 이벤트를 처리할 ClickListener 구현 클래스(로컬 클래스) ​​​​​​​​class CancelListener implements Button.ClickListener{ ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void onClick(){ ​​​​​​​​​​​​​​​​System.out.println("Cancel 버튼을 클릭했습니다."); ​​​​​​​​​​​​} ​​​​​​​​} ​​​​​​​​ ​​​​​​​​// Cancel 버튼 객체에 ClickListener 구현 객체 주입 ​​​​​​​​btnCancel.setClickListener(new CancelListener()); ​​​​​​​​ ​​​​​​​​// Cancel 버튼 클릭하기 ​​​​​​​​btnCancel.click(); ​​​​} } // 출력 : // Ok 버튼을 클릭했습니다. // Cancel 버튼을 클릭했습니다.​


먼저 Button과 관련된 객체를 생성했고 메인 클래스에 로컬 클래스를 생성했습니다.
로컬 클래스에서는 오버라이딩을 하면서 동작할 수 있게 만들어줍니다.

생성한 객체에 CancelListener 객체를 주입하고 버튼을 클릭해서 오버라이딩한 메소드를 불러옵니다.

 

 

3. 익명 객체

   ▷ 이름이 없는 객체, 명시적으로 클래스를 선언하지 않기 때문에 쉽게 객체를 생성할 수 있습니다.

   ▷ 필드 값, 로컬 변수 값, 매개변수 값으로 주로 사용합니다.

 

◎ 익명 자식 객체

   ▷ 부모 클래스를 상속받아 생성되는 객체

   ▷ 부모 타입의 필드, 로컬 변수, 매개변수의 값으로 대입할 수 있습니다.

 

◎ 익명 객체 예제

1. Tire 클래스
public class Tire { ​​​​public void roll() { ​​​​​​​​System.out.println("일반 타이어가 굴러갑니다."); ​​​​} }

 

2. Car 클래스
public class Car { ​​​​ ​​​​// 필드에 Tire 객체 대입 ​​​​private Tire tire1 = new Tire(); ​​​​ ​​​​// 필드에 익명 자식 객체 대입 ​​​​private Tire tire2 =new Tire() { ​​​​​​​​@Override ​​​​​​​​public void roll() { ​​​​​​​​​​​​System.out.println("익명 자식 Tire 객체 1이 굴러갑니다."); ​​​​​​​​}; // 세미콜론을 넣어도 되고 안넣어도 됩니다. ​​​​​​​​// 보통 세미콜론을 사용하지 않는 경우가 많습니다. ​​​​}; ​​​​// 익명 객체는 마지막에 세미콜론(;)을 붙여줘야합니다. ​​​​ ​​​​// tire1과 tire2(익명 자식 객체) 객체 안의 roll() 메서드 실행 ​​​​public void run1() { ​​​​​​​​tire1.roll(); ​​​​​​​​tire2.roll(); ​​​​} ​​​​ ​​​​public void run2() { ​​​​​​​​// 로컬 변수에 익명 자식 객체 대입 ​​​​​​​​Tire tire = new Tire() { ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void roll() { ​​​​​​​​​​​​​​​​System.out.println("익명 자식 Tire 객체 2가 굴러갑니다."); ​​​​​​​​​​​​} ​​​​​​​​}; ​​​​​​​​tire.roll(); ​​​​} ​​​​ ​​​​// 메소드(매개변수 이용) ​​​​public void run3(Tire tire) { ​​​​​​​​tire.roll(); ​​​​} }

 

3. CarExample 메인 클래스
public class CarExample { ​​​​public static void main(String[] args) { ​​​​​​​​// Car 객체 생성 ​​​​​​​​Car car = new Car(); ​​​​​​​​ ​​​​​​​​// 익명 자식 객체가 대입된 필드 사용 ​​​​​​​​car.run1(); ​​​​​​​​ ​​​​​​​​// 익명 자식 객체가 대입된 로컬변수 사용 ​​​​​​​​car.run2(); ​​​​​​​​ ​​​​​​​​// 익명 자식 객체가 대입된 매개변수 사용 ​​​​​​​​car.run3(new Tire() { ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void roll() { ​​​​​​​​​​​​​​​​System.out.println("익명 자식 Tire 객체 3이 굴러갑니다."); ​​​​​​​​​​​​} ​​​​​​​​}); ​​​​} } // 출력 : // 일반 타이어가 굴러갑니다. // 익명 자식 Tire 객체 1이 굴러갑니다. // 익명 자식 Tire 객체 2가 굴러갑니다. // 익명 자식 Tire 객체 3이 굴러갑니다.​

 

◎ 익명 구현 객체

   ▷ 인터페이스를 구현해서 생성되는 객체

   ▷ 인터페이스 타입의 필드, 로컬변수, 매개변수의 값으로 대입할 수 있습니다.

   ▷ 안드로이드와 같은 UI 프로그램에서 이벤트를 처리하는 객체로 많이 사용합니다.

 

익명 구현 객체 예제

1. RemoteControl 인터페이스
public interface RemoteControl { ​​​​// 추상 메소드 ​​​​void turnOn(); ​​​​void turnOff(); }

 

2. Home 클래스
public class Home { ​​​​// 필드에 익명 구현 객체 대입 ​​​​private RemoteControl rc = new RemoteControl() { ​​​​​​​​@Override ​​​​​​​​public void turnOn() { ​​​​​​​​​​​​System.out.println("TV를 켭니다."); ​​​​​​​​} ​​​​​​​​@Override ​​​​​​​​public void turnOff() { ​​​​​​​​​​​​System.out.println("TV를 끕니다."); ​​​​​​​​} ​​​​}; ​​​​ ​​​​// 메소드(필드 이용) ​​​​public void use1() { ​​​​​​​​rc.turnOn(); ​​​​​​​​rc.turnOff(); ​​​​} ​​​​// use1은 메모리에 계속 남을 수가 있습니다. ​​​​// 차라리 use2를 사용하면 사용시 객체 생성되었다가 rc가 사라집니다. ​​​​// 메모리 입장에서는 use1 보다는 use2의 방법이 훨씬 낫습니다. ​​​​ ​​​​// 메소드(로컬 변수 이용) ​​​​public void use2() { ​​​​​​​​// 로컬 변수에 익명 구현 객체 대입 ​​​​​​​​RemoteControl rc = new RemoteControl() { ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void turnOn() { ​​​​​​​​​​​​​​​​System.out.println("에어컨을 켭니다."); ​​​​​​​​​​​​} ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void turnOff() { ​​​​​​​​​​​​​​​​System.out.println("에어컨을 끕니다."); ​​​​​​​​​​​​} ​​​​​​​​}; ​​​​​​​​rc.turnOn(); ​​​​​​​​rc.turnOff(); ​​​​} ​​​​ ​​​​public void use3(RemoteControl rc) { ​​​​​​​​rc.turnOn(); ​​​​​​​​rc.turnOff(); ​​​​} }

 

3. HomeExample 메인 클래스
public class HomeExample { ​​​​public static void main(String[] args) { ​​​​​​​​// Home 객체 생성 ​​​​​​​​Home home = new Home(); ​​​​​​​​ ​​​​​​​​// 익명 구현 객체가 대입된 필드 사용 ​​​​​​​​home.use1(); ​​​​​​​​ ​​​​​​​​// 익명 구현 객체가 대입된 로컬 변수 사용 ​​​​​​​​home.use2(); ​​​​​​​​ ​​​​​​​​// 익명 구현 객체가 대입된 매개변수 사용 ​​​​​​​​home.use3(new RemoteControl() { ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void turnOn() { ​​​​​​​​​​​​​​​​System.out.println("난방을 켭니다."); ​​​​​​​​​​​​} ​​​​​​​​​​​​ ​​​​​​​​​​​​@Override ​​​​​​​​​​​​public void turnOff() { ​​​​​​​​​​​​​​​​System.out.println("난방을 끕니다."); ​​​​​​​​​​​​} ​​​​​​​​}); ​​​​} } // 출력 : // TV를 켭니다. // TV를 끕니다. // 에어컨을 켭니다. // 에어컨을 끕니다. // 난방을 켭니다. // 난방을 끕니다.​


use2() 메소드를 사용하면 use1(), use3() 메소드를 사용한 것보다 메모리 부담을 줄일 수 있습니다.
use3()를 사용하면 매개변수가 남기때문에 use1을 사용한 것과 같이 메모리에 남아 부담이 됩니다.

 

 

인터페이스도 클래스와 같이 내부에서 인스턴스 또는 함수, 필드 형태로 만들어서 사용할 수 있습니다.

 

클래스보다는 인터페이스를 많이 사용한다고 하니 참고해서 공부해보시면 좋을 것 같아요!!

 

많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~

 

728x90
반응형

'BackEnd > Java' 카테고리의 다른 글