일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
- UXUI챌린지
- KDT
- Java
- baekjoon
- 티스토리챌린지
- UXUI기초정복
- OPENPATH
- 백엔드 부트캠프
- 국비지원취업
- 객체지향
- UXUIPrimary
- 패스트캠퍼스
- 디자인교육
- 디자인강의
- 내일배움캠프
- 국비지원
- 오블완
- 백엔드개발자
- 백준
- 내일배움카드
- 백엔드
- 오픈챌린지
- Be
- 오픈패스
- 디자인챌린지
- Spring
- 환급챌린지
- 국비지원교육
- mysql
- 부트캠프
- Today
- Total
군만두의 IT 공부 일지
[스터디4] 05. 중첩 선언과 익명 객체 본문
목차
9장. 중첩 선언과 익명 객체
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)이 별도로 생성된다. 바이트코드 파일의 이름은 다음과 같다.
// 멤버 클래스
A $ B .class
// 로컬 클래스
A $1 B .class
9.2 인스턴스 멤버 클래스
인스턴스 멤버 클래스는 A 클래스 멤버로 선언된 B 클래스를 말한다.
[public] class A {
[public | private] class B { // 인스턴스 멤버 클래스
}
}
접근 제한자에 따른 인스턴스 멤버 클래스의 접근 범위
구분 | 접근 범위 |
public class B {} | 다른 패키지에서 B 클래스를 사용할 수 있다. |
class {} | 같은 패키지에서만 B 클래스를 사용할 수 있다. |
private class B {} | A 클래스 내부에서만 B 클래스를 사용할 수 있다. |
- 인스턴스 멤버 클래스 B는 주로 A 클래스 내부에서만 사용한다.
- B 객체는 A 클래스 내부 어디에서나 생성할 수는 없고, 인스턴스 필드값, 생성자, 인스턴스 메소드에서 생성할 수 있다. A 객체가 있어야 B 객체도 생성할 수 있다.
B 객체를 A 클래스 외부에 생성하려면 default 또는 public 접근 제한을 가져야 하고, A 객체를 먼저 생성한 다음 B 객체를 생성해야 한다.
A a = new A(); // A 객체 생성
A.B b = a.new B(); // B 객체 생성
인스턴스 멤버 클래스 B 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언이 올 수 있다. Java 17부터 정적 필드와 정적 메소드 선언이 가능하다.
// A.java
package ch09.sec02.exam02;
public class A {
// 인스턴스 멤버 클래스
class B {
// 인스턴스 필드
int field1 = 1;
// 정적 필드 (Java 17부터 허용)
static int field2 = 2;
// 생성자
B() {
System.out.println("B-생성자 실행");
}
// 인스턴스 메소드
void method1() {
System.out.println("B-method1 실행");
}
// 정적 메소드 (Java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
// 인스턴스 메소드
void useB() {
// B 객체 생성 및 인스턴스 필드 및 메소드 사용
B b = new B();
System.out.println(b.field1);
b.method1();
// B 클래스의 정적 필드 및 메소드 사용
System.out.println(B.field2);
B.method2();
}
}
9.3 정적 멤버 클래스
정적 멤버 클래스는 static 키워드와 함께 A 클래스 멤버로 선언된 B 클래스를 말한다.
[public] class A {
[public | private] static class B { // 정적 멤버 클래스
}
}
접근 제한자에 따른 정적 멤버 클래스의 접근 범위
구분 | 접근 범위 |
public static class B {} | 다른 패키지에서 B 클래스를 사용할 수 있다. |
static class B {} | 같은 패키지에서만 B 클래스를 사용할 수 있다. |
private static class B {} | A 클래스 내부에서만 B 클래스를 사용할 수 있다. |
- 정적 멤버 클래스 B는 A 클래스 내외부에서 사용된다.
- A 클래스 외부에서 A와 함께 많이 사용되기 때문에 default 또는 public 접근 제한을 가진다.
- B 객체는 A 클래스 내부 어디든 객체를 생성할 수 있다.
A 클래스 외부에서 B 객체를 생성하려면 A 객체 생성 없이 A 클래스로 접근해서 B 객체를 생성할 수 있다.
A.B b = new A.B();
정적 멤버 클래스 B 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언이 올 수 있다.
// A.java
package ch09.sec03.exam02;
public class A {
// 정적 멤버 클래스
static class B {
// 인스턴스 필드
int field1 = 1;
// 정적 필드 (Java 17부터 허용)
static int field2 = 2;
// 생성자
B() {
System.out.println("B-생성자 실행");
}
// 인스턴스 메소드
void method1() {
System.out.println("B-method1 실행");
}
// 정적 메소드 (Java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
}
9.4 로컬 클래스
로컬(local) 클래스는 생성자 또는 메소드 내부에서 선언된 클래스를 말한다.
[public] class A {
// 생성자
public A() {
class B {}
}
// 메소드
public void method() {
class B {}
}
}
- 로컬 클래스는 생성자와 메소드가 실행될 동안에만 객체를 생성할 수 있다.
- 로컬 변수(생성자 or 메소드의 매개변수 or 내부에서 선언된 변수)를 로컬 클래스에서 사용할 경우, 변수는 final 특성을 갖게 되므로 값을 읽을 수만 있고 수정할 수 없다.
- Java 8 이후부터는 명시적으로 final 키워드를 붙이지 않아도 되지만, 로컬 변수에 final 키워드를 추가해서 final 변수임을 명확히 할 수 있다.
로컬 클래스 B 내부에는 일반 클래스와 같이 필드, 생성자, 메소드 선언이 올 수 있다. Java 17부터는 정적 필드와 정젝 메소드 선언이 가능하다.
// A.java
package ch09.sec04.exam02;
public class A {
// 메소드
void useB() {
// 로컬 클래스
class B {
// 인스턴스 필드
int field1 = 1;
// 정적 필드 (Java 17부터 허용)
static int field2 = 2;
// 생성자
B() {
System.out.println("B-생성자 실행");
}
// 인스턴스 메소드
void method1() {
System.out.println("B-method1 실행");
}
// 정적 메소드 (Java 17부터 허용)
static void method2() {
System.out.println("B-method2 실행");
}
}
// 로컬 객체 생성
B b = new B();
// 로컬 객체의 인스턴스 필드 및 메소드 사용
System.out.println(b.field1);
b.method1();
// 로컬 클래스의 정적 필드 및 메소드 사용 (Java 17부터 허용)
System.out.println(B.field2);
B.method2();
}
}
9.5 바깥 멤버 접근
중첩 클래스는 바깥 클래스와 긴밀한 관계를 맺으면서 바깥 클래스의 멤버(필드, 메소드)에 접근할 수 있다. 하지만 중첩 클래스가 어떻게 선언되었느냐에 따라 접근 제한이 있을 수 있다.
바깥 클래스의 멤버 접근 제한
정적 멤버 클래스는 바깥 객체가 없어도 사용 가능해야 하므로 바깥 클래스의 인스턴스 필드와 인스턴스 메소드는 사용하지 못한다.
구분 | 바깥 클래스의 사용 가능한 멤버 |
인스턴스 멤버 클래스 | 바깥 클래스의 모든 필드와 메소드 |
정적 멤버 클래스 | 바깥 클래스으 정적 필드와 정적 메소드 |
// A.java
package ch09.sec05.exam01;
public class A {
// A의 인스턴스 필드와 메소드
int field1;
void method1() { }
// A의 정적 필드와 메소드
static int field2;
static void method2() { }
// 인스턴스 멤버 클래스
class B {
void method() {
// A의 인스턴스 필드와 메소드 사용
field1 = 10; // (O)
method1(); // (O)
// A의 정적 필드와 메소드 사용
field2 = 10; // (O)
method2(); // (O)
}
}
// 정적 멤버 클래스
static class C {
void method() {
// A의 인스턴스 필드와 메소드 사용
// field1 = 10; // (X)
// method1(); // (X)
// A의 정적 필드와 메소드 사용
field2 = 10; // (O)
method2(); // (O)
}
}
}
바깥 클래스의 객체 접근
중첩 클래스 내부에서 this는 해당 중첩 클래스의 객체를 말한다. 중첩 클래스 내부에서 바깥 클래스의 객체를 얻으려면, 바깥 클래스 이름에 this를 붙인다.
바깥클래스이름.this // 바깥객체
// A.java
package ch09.sec05.exam02;
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); // B의 field
this.method(); // B의 method()
// A 객체의 필드와 메소드 사용
System.out.println(A.this.field); // A의 field
A.this.method(); // A의 method()
}
}
// A의 인스턴스 메소드
void useB() {
B b = new B();
b.print();
}
}
9.6 중첩 인터페이스
중첩 인터페이스는 클래스의 멤버로 선언된 인터페이스를 말한다. 인터페이스를 클래스 내부에 선언하는 이유는 해당 클래스와 긴밀한 관계를 맺는 구현 객체를 만들기 위해서이다.
class A {
[public | private | static] interface B { // 중첩 인터페이스
// 상수 필드
// 추상 메소드
// 디폴트 메소드
// 정적 메소드
}
}
중첩 인터페이스는 안드로이드와 같은 UI 프로그램에서 이벤트를 처리할 목적으로 많이 활용된다. 예를 들어, 버튼을 클릭했을 때 이벤트를 처리할 객체는 중첩 인터페이스를 구현해서 만든다.
9.7 익명 객체
- 익명(anonymous) 객체: 이름이 없는 객체
- 장점: 명시적으로 클래스를 선언하지 않기 때문에 쉽게 객체를 생성할 수 있다.
- 익명 객체는 필드값, 로컬 변수값, 매개변수값으로 주로 사용된다.
익명 객체는 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있다.
- 익명 자식 객체: 클래스를 상속해서 만들 경우
- 익명 구현 객체: 인터페이스를 구현해서 만들 경우
익명 자식 객체
익명 자식 객체는 부모 클래스를 상속받아 생성되고, 이렇게 생성된 객체는 부모 타입의 필드, 로컬 변수, 매개변수의 값으로 대입할 수 있다.
new 부모생성자(매개값, ...) {
// 필드
// 메소드
}
중괄호 블록 안의 필드와 메소드는 익명 자식 객체가 가져야 할 멤버로, 중괄호 블록 안에서만 사용할 수 있다.
익명 구현 객체
익명 구현 객체는 인터페이스를 구현해서 생성되는데, 이렇게 생성된 객체는 인터페이스 타입의 필드, 로컬변수, 매개변수의 값으로 대입할 수 있다.
new 인터페이스(매개값, ...) {
// 필드
// 메소드
}
중괄호 블록 안의 필드와 메소드는 익명 구현 객체가 가져야 할 멤버로, 중괄호 블록 안에서만 사용할 수 있다.
이 글은 『이것이 자바다』 책을 학습한 내용을 정리한 것입니다.
'프로그래밍 > Java' 카테고리의 다른 글
[스터디4] 07. 멀티 스레드 (0) | 2025.03.11 |
---|---|
[스터디4] 06. 제네릭 (0) | 2025.03.02 |
[스터디4] 04. 인터페이스 (1) | 2025.02.16 |
[스터디4] 03. 상속 (0) | 2025.02.09 |
[스터디4] 02. 클래스 (0) | 2025.01.31 |