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(); } }
2. buttonExample 클래스
인터페이스를 통해 onclick이라는 메소드를 만들고 따로 private 변수를 만들어 set을 통해 변수를 클래스로 지정할 수 있게 만들고 click 함수를 통해 인터페이스의 onclick메소드를 부를 수 있습니다.
이때, this.clickListener.onClick()은 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()); // 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을 사용한 것과 같이 메모리에 남아 부담이 됩니다.
인터페이스도 클래스와 같이 내부에서 인스턴스 또는 함수, 필드 형태로 만들어서 사용할 수 있습니다.
클래스보다는 인터페이스를 많이 사용한다고 하니 참고해서 공부해보시면 좋을 것 같아요!!
많은 분들의 피드백은 언제나 환영합니다! 많은 댓글 부탁드려요~~
'BackEnd > Java' 카테고리의 다른 글
[java] ch11 예외 처리 1 (0) | 2023.01.18 |
---|---|
[java] 이것이 자바다 ch10 라이브러리와 모듈 (0) | 2023.01.17 |
[java] 이것이 자바다 ch09 중첩 선언 (0) | 2023.01.17 |
[java] 인터페이스2 (0) | 2023.01.16 |
[java] 인터페이스 (2) | 2023.01.16 |