다시 돌아온 자바 개념서 정독 시간 ~_~
1. 내부 클래스 (Inner class)
1) 클래스 안의 클래스. 중첩 클래스 라고도 함.
선언 위치에 따른 분류 | 선언 위치 | 설명 | |
멤버 클래스 | 인스턴스 멤버 클래스 | class A { class B { ... } } |
A 객체를 생성해야만 사용할 수 있는 B 중첩 클래스. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언됨. |
정적 멤버 클래스 | class A { static class B { ... } } |
A 클래스로 바로 접근할 수 있는 B 접근 클래스. 주로 외부 클래스의 static 멤버, 특히 static 메서드에서 사용될 목적으로 선언됨. |
|
로컬 클래스 | class A { void method() { class B { ... } } } |
method() 가 실행될 때만 사용할 수 있는 B 중첩 클래스. 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있음. |
|
익명 클래스 | 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 일회용 클래스 |
2) 내부 클래스의 특징
- 클래스 멤버인 중첩 클래스는 멤버 클래스, 메서드 내부에 선언된 중첩 클래스는 로컬 클래스.
- 내부 클래스에서 외부 클래스의 멤버들을 객체 생성 없이도 접근 가능
- 다른 클래스에서 내부 클래스를 쓰려면 외부 클래스의 객체를 먼저 생성해야 내부 클래스도 접근 가능함.
- 외부에는 불필요한 관계 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있음. (캡슐화)
3) 멤버 클래스
- static 필드와 메서드를 선언할 수 없음.
- static 멤버 클래스는 모든 종류의 필드와 메서드를 선언할 수 있음.
- 인스턴스 멤버 클래스 예시
class A {
/**인스턴스 멤버 클래스**/
class B {
B() { } //생성자
ine field1; //인스턴스 필드
//static int field2; //정적 필드 사용 불가
void method1() { } //인스턴스 메서드
//static void method2() { } //정적 메서드 사용 불가
}
}
A a = new A(); //A클래스 객체를 생성해야 B클래스 접근 가능
A.B b = a.new B(); //A에 중첩된 B클래스 라는 의미로 객체 생성
b.field1 = 3; //참조변수 b로 인스턴스 필드 접근 가능
b.method1();
- 정적 멤버 클래스 예시
class A {
/**정적 멤버 클래스**/
static class C {
C() { } //생성자
ine field1; //인스턴스 필드
static int field2; //정적 필드 사용 가능
void method1() { } //인스턴스 메서드
static void method2() { } //정적 메서드 사용 가능
}
}
A.C c = new A.C();
c.field1 = 3; //C 객체를 생성해야 인스턴스 필드 사용 가능
c.method1(); //C 객체를 생성해야 인스턴스 메서드 사용 가능
A.C.field2 = 3; //C 객체를 만들지 않고도 접근 가능한 static 필드
A.C.method2(); //C 객체를 만들지 않고도 접근 가능한 static 메서드 호출
5) 로컬 클래스
- 자바 7 이전 : 메서드 실행이 끝나도 로컬 클래스의 객체는 힙 메모리에 존재하고 계속 사용될 수 있음. 매개 변수나 로컬 변수는 메서드 실행이 끝나면 스택 영역에서 사라짐. 그렇기 때문에 로컬 클래스는 매개변수나 로컬 변수를 컴파일 시 로컬 클래스 내부에 복사해서 사용하며, 매개 변수나 로컬 변수를 final로 선언해 수정을 막음.
- 자바 8 이후 : 로컬 클래스에서 사용될 경우 매개 변수와 로컬 변수는 final 특성을 자체적으로 가지기 때문에 final 키워드를 생략해도 되며, 이것은 로컬 클래스의 필드로 복사됨.
- 로컬 클래스는 접근 제한자나 static 을 붙일 수 없음. (메서드 내부에서만 사용되므로 접근을 제한할 필요가 없음.)
void method() {
/**로컬 클래스**/
class D {
D() { } //생성자
int field1; //인스턴스 필드
//static int field2; //정적 필드 사용 불가
void method1() { } //인스턴스 메서드
//static void method2() { } //정적 메서드 사용 불가
}
D d = new D(); //D 객체를 생성해야 객체의 필드 접근 가능
d.field1 = 3;
d.method1();
}
6) 로컬 클래스의 상속
void method() {
class DownloadThread extends Thread { ... }
DownloadThread thread = new DownloadThread();
thread.start();
}
2. 중첩 클래스에서 바깥 클래스 참조 얻기
public class Outter {
String field = "Outter-field";
void method() {
System.out.println("Outter-method");
}
class Nested {
String field = "Nested-field";
void method() {
System.out.println("Nested-method");
}
void print() {
System.out.println(this.field); //Nested 클래스의 참조가 됨.
this.method();
System.out.println(Outter.this.field); //Outter 클래스의 참조가 됨.
Outter.this.method();
}
}
3. 내부 클래스의 제어자와 접근성
1) 기본 클래스에서는 defalut, public 제어자만 쓸 수 있지만, 내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일. (모든 제어자 사용 가능)
class Outer {
private class InstanceInner {}
protected static class StaticInner {}
void myMethod() {
class LocalInner {}
}
}
2) 바깥 필드와 메서드에서 사용 제한
public class A {
//인스턴스 멤버 클래스
class B {}
//정적 멤버 클래스
static class C {}
}
- 만약 위 처럼 클래스 A 안에 B 내부 클래스, C 정적 내부 클래스가 있다고 할 때 사용 제한 범위는?
public class A {
//인스턴스 필드
B field1 = new B(); //사용 가능
C field2 = new C(); //사용 가능
//인스턴스 메서드
void method1() {
B var1 = new B(); //사용 가능
C var2 = new C(); //사용 가능
//정적 필드 초기화
//static B field3 = new B(); //에러. B는 인스턴스 멤버이기 때문에 A객체가 있어야 사용 가능.
static C field4 = new C(); //static 으로 선언된 C는 단독으로 사용 가능
//정적 메서드
//B var1 = new B(); //에러. B는 인스턴스 멤버이기 때문에 A객체가 있어야 사용 가능.
C var2 = new C(); //static 으로 선언된 C는 단독으로 사용 가능
3. 중첩 인터페이스
1) 클래스 내부에 선언한 인터페이스
2) 해당 클래스와 긴밀한 관계를 맺는 구현 클래스를 만들기 위해 선언.
- 외부에서는 사용하지 않고 클래스 내에서만 사용할 수 있는 인터페이스.
3) 메소드 실행이 끝나도 구현 객체는 힙 메모리에 존재하지만 매개 변수나 로컬 변수는 메소드 실행이 끝나면 스택 영역에서 사라지므로 로컬 클래스와 동일하게 처리.
public class Button
OnClickListener listener; //인터페이스 타입 필드
void setOnClickListener(OnClickListener listener) { //매개변수의 다형성. 다양한 구현객체가 옴.
this.listener = listener; //외부에서 구현객체를 대입받아서 필드에 대입시키기
}
void touch() {
listener.onClick(); //구현 객체인 onClick()메서드 호출
}
interface OnClickListener { // 중첩 인터페이스
void onClick();
}
}
4. 익명 클래스 (anonymous class)
1) 이름이 없는 일회용 객체. 정의와 생성을 동시에 함.
2) 단독으로 생성할 수 없고 클래스를 상속하거나 인터페이스를 구현해야만 생성할 수 있음.
3) UI 이벤트 처리 객체, 스레드 객체를 간편하게 생성할 목적으로 주로 활용됨.
4) 익명 객체는 필드의 초기값이나 로컬 변수의 초기값, 매개 변수의 매개값으로 주로 대입됨.
- 메소드의 매개 변수가 부모 타입일 경우 메소드 호출 코드에서 익명 자식 객체를 생성해서 매개값으로 대입할 수도 있음.
- 부모클래스(매개값){ }은 부모 클래스를 상속해서 중괄호와 같이 자식 클래스를 선언하라는 뜻이고 new 연산자는 이렇게 선언된 자식 클래스를 객체로 생성하는 것.
5) 익명 자식 객체 생성
//익명 자식 객체 생성
부모클래스 필드 = new 부모클래스(매개값) {
// 필드
// 메소드
};
6) 익명 자식 객체가 부모 타입 필드 초기값으로 대입된 예시
class A {
//A 클래스의 필드 선언
Parent field = new Parent() { //객체 끝에 중괄호가 붙은 것은 익명 자식 객체 생성하는 것.
int childField;
void childMethod() { }
@Override //Parent의 메서드를 오버라이딩
void parentMethod() { }
};
}
7) 로컬변수 초기값으로 자식 객체가 대입된 예시
class A {
void method() {
//로컬변수 선언
Parent localVar = new Parent() {
int childField;
void childMethod() { }
@Override //Parent의 메서드를 오버라이딩
void parentMethod() { }
8) 메서드의 매개값으로 익명 자식 객체를 생성
class A {
void method1(Parent parent) { }
void method2() {
method1 ( //method1() 메서드 호출
new Parent() { //method1()의 매개값으로 익명 하위 클래스를 이용해서 객체로 대입
int childField;
void childMethod() { }
@Override
void parentMethod() { }
}
};
}
9) 익명 구현 객체 생성
//익명 구현 객체 생성
부모클래스 [필드|변수] = new 부모클래스(매개값, ...) {
//인터페이스에 선언된 추상 메서드의 실체 메서드 선언
// 필드
// 메소드
};
10) 일반 클래스와의 차이점은 생성자를 선언할 수 없다는 것임.
11) 익명 객체에 새롭게 정의된 필드와 메서드
- 익명 객체 내부에서만 사용됨.
- 외부에서는 익명 객체의 필드와 메서드에 접근할 수 없음. (익명 객체는 이름이 없기 때문에 항상 부모 타입 변수에 대입되므로 부모 타입에 선언된 것만 사용할 수 있음)
참고 : [한빛미디어] 이것이 자바다 (신용권의 Java 프로그래밍 정복) Chapter 9.중첩 클래스
참고 : [도우출판] JAVA의 정석(3ND EDITION)-자바의 정석 최신 Java 8.0 포함 Chapter 7.내부 클래스
'TIL' 카테고리의 다른 글
React - require vs import (22.11.09 TIL) (0) | 2022.11.09 |
---|---|
controller 간단하게 만들기 (22.11.08 TIL) (0) | 2022.11.08 |
성공적인 자체 워크샵 (22.11.06 TIL) (0) | 2022.11.06 |
옵셔널 체이닝 '?.' (22.11.05 TIL) (0) | 2022.11.05 |
Java - Stack 과 Queue (22.11.04 TIL) (0) | 2022.11.04 |
댓글