일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- Machine Learning
- supervised learning
- AI
- PCA
- deep learning
- 회귀
- 분류
- 머신러닝
- Classification
- 티스토리챌린지
- LLM
- LG
- 지도학습
- ChatGPT
- LG Aimers 4th
- LG Aimers
- regression
- 딥러닝
- OpenAI
- gpt
- 해커톤
- 오블완
- GPT-4
Archives
- Today
- Total
SYDev
[이것이 자바다] Chapter 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 객체를 생성할 수 있음 |
- 중첩 클래스도 하나의 클래스이기 때문에, 컴파일하면 바이트코드 파일(.class)이 별도로 생성됨
- 멤버 클래스일 경우 바이트코드 파일의 이름은 다음과 같이 결정됨
- 로컬 클래스일 경우 바이트코드 파일의 이름은 다음과 같이 결정됨
2. 인스턴스 멤버 클래스
- 접근 제한자
- public class B {}: 다른 패키지에서 B 클래스 사용 가능
- class B {}: 같은 패키지에서만 B 클래스 사용 가능
- private class B {}: A 클래스 내부에서만 B 클래스 사용 가능
- 주로 private 접근 제한을 갖는 것이 일반적
[public] class A {
[public | private] class B {
}
}
- 외부에서 생성하려면, A 객체 생성 이후, B 객체를 생성해야 함
A a = new A();
A.B b = a.new B();
- 예제
package ch9.sec2;
public class A {
class B {
int field1 = 1;
// static field(Java 17부터 허용
static int field2 = 2;
B () {
System.out.println("B-생성자 실행");
}
void method1() {
System.out.println("B-method1 실행");
}
// static method(Java 17부터 허용
static void method2() {
System.out.println("B-method2 실행");
}
}
// instance method
void useB() {
// B 객체 생성 및 인스턴스 필드 및 메소드 사용
B b = new B();
System.out.println(b.field1);
b.method1();
// B 클래스의 정적 필드 및 메소드 사용
System.out.println(B.field2);
B.method2();
}
}
package ch9.sec2;
public class AExample {
public static void main(String[] args) {
// A 객체 생성
A a = new A();
A.B b = a.new B();
// A 인스턴스 메소드 호출
a.useB();
b.method1();
A.B.method2();
}
}
3. 정적 멤버 클래스
- 접근 제한자
- public static class B {}: 다른 패키지에서 B 클래스 사용 가능
- class B {}: 같은 패키지에서만 B 클래스 사용 가능
- private static class B {}: A 클래스 내부에서만 B 클래스 사용 가능
- 주로 default 또는 public 접근 제한을 가짐
[public] class A {
[public | private] static class B {
}
}
- A 클래스 외부에서 B 객체를 생셩하려면, A 객체 생성 없이 A 클래스로 접근해서 B 객체 생성 가능
A.B b = new A.B();
4. 로컬 클래스
- 로컬 클래스는 생성자와 메소드가 실행될 동안에만 객체를 생성 가능
- 로컬 변수(생성자 또는 메소드의 매개변수 또는 내부에서 선언된 변수)를 로컬 클래스에서 사용할 경우 로컬 변수는 final 특성을 갖게되므로, 값을 읽을 수만 있고 수정할 수 없음
[public] class A {
// 생성자
public A() {
class B { }
}
// 메소드
public void method() {
class B { }
}
}
- 예제
package ch9.sec4;
public class A {
// method
void useB() {
// local class
class B {
// instance field
int field1 = 1;
// static field
static int field2 = 2;
// constructor
B() {
System.out.println("B-생성자 실행");
}
// instance method
void method1() {
System.out.println("B-method1 실행");
}
// static method
static void method2() {
System.out.println("B-method2 실행");
}
}
// local object 생성
B b = new B();
// local object의 instance field와 method 사용
System.out.println(b.field1);
b.method1();
// local class의 static field와 method 사용
System.out.println(B.field2);
B.method2();
}
}
package ch9.sec4;
public class AExample {
public static void main(String[] args) {
A a = new A();
a.useB();
}
}
5. 바깥 멤버 접근
- nested class는 바깥 클래스와 긴밀한 관계를 맺으며, 바깥 클래스의 멤버(field, method)에 접근이 가능
5.1. 바깥 클래스의 멤버 접근 제한
구분 | 바깥 클래스의 사용 가능한 멤버 |
인스턴스 멤버 클래스 | 바깥 클래스의 모든 필드와 메소드 |
정적 멤버 클래스 | 바깥 클래스의 정적 필드와 정적 메소드 |
5.2. 바깥 클래스의 객체 접근
바깥클래스이름.this // 바깥객체
6. 중첩 인터페이스
- 중첩 인터페이스: 클래스의 멤버로 선언된 인터페이스
- 해당 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해 사용
class A {
[public | private] [static] interface B {
// 상수 필드
// 추상 메소드
// 디폴트 메소드
// 정적 메소드
}
}
- 예제
- 안드로이드와 같은 UI 프로그램에서 이벤트를 처리할 목적으로 많이 활용
- ex) 버튼을 클릭했을 때, 이벤트를 처리할 객체는 중첩 인터페이스를 구현해서 생성
package ch9.sec6;
public class Button {
// static nested interface
public static interface ClickListener {
// abstract method
void onClick();
}
// field
private ClickListener clickListener;
// method
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
public void click() {
this.clickListener.onClick();
}
}
package ch9.sec6;
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();
//----------------------------------------------------------
// Cancel 버튼 객체 생성
Button btnCancel = new Button();
// Cancel 버튼 클릭 이벤트를 처리할 ClickListener 구현클래스(로컬 클래스)
class CancelListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("Cancel 버튼을 클릭했습니다.");
}
}
//Cancel 버튼 객체에 ClickListener 구현 객체 주입
btnCancel.setClickListener(new CancelListener());
// Cancel 버튼 클릭하기
btnCancel.click();
}
}
7. 익명 객체
- 익명 객체(anonymous object): 이름이 없는 객체를 의미
- 명시적으로 클래스 선언 X -> 쉽게 객체 생성 가능
- 필드값, 로컬 변수값, 매개변수값으로 주로 사용
- 클래스를 상속하거나, 인터페이스를 구현해야만 생성 가능
- 익명 자식 객체: 클래스를 상속하는 경우
- 익명 구현 객체: 인터페이스를 구현해서 만드는 경우
7.1. 익명 자식 객체
- 부모 타입의 필드, 로컬 변수, 매개변수의 값으로 대입될 수 있음
new 부모생성자( 매개값, ... ) {
// 필드
// 메소드
}
- 예제
package ch9.sec7;
public class Tire {
public void roll() {
System.out.println("일반 타이어가 굴러갑니다.");
}
}
package ch9.sec7;
public class Car {
// 필드에 Tire 객체 대입
private Tire tire1 = new Tire();
// 필드에 익명 자식 객체 대입
private Tire tire2 = new Tire() {
@Override
public void roll() {
System.out.println("익명 자식 Tire 객체 1이 굴러갑니다.");
}
};
// method(field 이용)
public void run1() {
tire1.roll();
tire2.roll();
}
// method(로컬 변수 이용)
public void run2() {
// 로컬 변수에 익명 자식 객체 대입
Tire tire = new Tire() {
@Override
public void roll() {
System.out.println("익명 자식 Tire 객체 2가 굴러갑니다.");
}
};
tire.roll();
}
// method(parameter 이용)
public void run3(Tire tire) {
tire.roll();
}
}
package ch9.sec7;
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이 굴러갑니다.");
}
});
}
}
7.2. 익명 구현 객체
- 인터페이스 타입의 필드, 로컬변수, 매개변수의 값으로 대입될 수 있음
new 인터페이스() {
// 필드
// 메소드
}
- 안드로이드와 같은 UI 프로그램에서 이벤트를 처리하는 객체로 많이 사용
- 예제
package ch9.sec7.exam02;
public interface RemoteControl {
// abstract method
void turnOn();
void turnOff();
}
package ch9.sec7.exam02;
public class Home {
// 필드에 익명 구현 객체 대입
private RemoteControl rc = new RemoteControl() {
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
}
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
}
};
// method(field 이용)
public void use1() {
rc.turnOn();
rc.turnOff();
}
// method(로컬 변수 이용)
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();
}
// method(parameter 이용)
public void use3(RemoteControl rc) {
rc.turnOn();
rc.turnOff();
}
}
package ch9.sec7.exam02;
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("난방을 끕니다.");
}
});
}
}
-> 9.6에서 중첩 인터페이스 예제 또한, 명시적인 구현 클래스 생성 없이 코드 중복도를 없앨 수 있음
참고자료
'Programming Lang > Java' 카테고리의 다른 글
[이것이 자바다] Chapter 12. java.base 모듈 (0) | 2025.01.31 |
---|---|
[이것이 자바다] Chapter 11. 예외 처리 (0) | 2025.01.30 |
[혼자 공부하는 자바] Chapter 8. 인터페이스 (0) | 2025.01.29 |
[혼자 공부하는 자바] Chapter 7. 상속 (0) | 2025.01.27 |
[혼자 공부하는 자바] Chapter 6. 클래스 (0) | 2025.01.23 |