728x90
📍 학습목표
네스티드(Nested)클래스 대해서 알아보자
네스티드(Nested) 클래스 (내부 클래스)
- 클래스 내에 정의되는 모든 클래스
- 내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있다. 또, 멤버변수처럼 private, protected와 같은 접근제어자도 사용 가능하다.
- 내부 클래스 중에서 static 클래스만 static 멤버를 가질 수 있다. 다만, final과 static이 동시에 붙은 변수는 상수(constant)이므로 모든 내부 클래스에서 정의가 가능하다.
- 네스티드 클래스는 static의 선언 여부를 기준으로 나눌 수 있다.
- Static 네스티드 클래스 (스태틱 클래스)
- Non-static 네스티드 클래스 (이너(Inner) 클래스)
- 멤버 클래스 (인스턴스 클래스)
- 로컬 클래스 ( 지역 클래스)
- 익명 클래스 (익명 클래스)
Static 네스티드 클래스
- 외부 클래스의 멤버변수 선언위치에 선언하며, 외부 클래스의 static 멤버처럼 다뤄진다.
- 주로 외부 클래스의 static 메서드와 static 변수와 작업한다.
- Static 클래스는 외부 클래스의 인스턴스 변수와 메서드에 접근이 불가능하다.
더보기
예제
public class Prac {
public static void main (String[] args) {
Outer.Nested1 nst1 = new Outer.Nested1();
nst1.add(5);
Outer.Nested2 nst2 = new Outer.Nested2();
System.out.println(nst2.get());
}
}
class Outer {
private static int num = 0;
static class Nested1 { // static 클래스
void add(int n) {num += n;}
}
static class Nested2 { // static 클래스
int get() {return num;}
}
}
5
- Nested1 클래스와 Nested2 클래스는 Outer의 static 멤버 num에 접근하고 있다. num 멤버변수가 private로 선언되어 있어도 접근이 가능하다.
- Static 클래스 내에는 외부 클래스의 static 멤버변수와 메소드에만 접근이 가능하다.
내부 클래스
- 내부 클래스는 static이 붙지 않는 내부 클래스다.
- 내부 클래스는 3가지 종류의 클래스로 나눌 수 있다.
- 인스턴스 클래스
- 지역 클래스
- 익명 클래스
🔍 인스턴스 클래스
- 외부 클래스의 인스턴스 변수, 인스턴스 메소드와 동일한 위치에 선언된다.
- 외부 클래스의 인스턴스 멤버처럼 다뤄진다.
- 주로 외부 클래스의 인스턴스 멤버들과 작업한다.
- 클래스의 정의를 감춰야할 때 유용하게 사용한다.
더보기
예제
public class Prac {
public static void main (String[] args) {
Outer o1 = new Outer();
Outer o2 = new Outer();
// o1 기반으로 두 인스턴스 생성
Outer.Member o1m1 = o1.new Member();
Outer.Member o1m2 = o1.new Member();
// o2 기반으로 두 인스턴스 생성
Outer.Member o2m1 = o2.new Member();
Outer.Member o2m2 = o2.new Member();
// o1 기반으로 생성된 두 인스턴스의 메서드 호출
o1m1.add(5);
System.out.println(o1m1.get());
// o2 기반으로 생성된 두 인스턴스의 메서드 호출
o2m1.add(7);
System.out.println(o2m1.get());
}
}
class Outer {
private int num = 0;
class Member {
void add(int n) {num += n;}
int get() {return num;}
}
}
5
7
- Member 클래스의 인스턴스는 외부 클래스의 인스턴스에 종속적이다.
예제2
public class Prac {
public static void main (String[] args) {
Papers p = new Papers("서류 출력");
Printable prn = p.getPrinter();
prn.print();
}
}
interface Printable {
void print();
}
class Papers {
private String con;
public Papers(String s) {con = s;}
// 인스턴스 클래스 생성 및 반환
public Printable getPrinter() {
return new Printer();
}
//인스턴스 클래스 정의
private class Printer implements Printable {
public void print() {
System.out.println(con);
}
}
}
서류 출력
- Papers 클래스의 외부에서는 getPrinter() 메서드가 어떠한 인스턴스의 참조 값을 반환하는지 알지 못한다. 다만 반환되는 참조 값의 인스턴스가 Printable을 구현하고 있어서 Printable의 참조 타입으로 다룰 수 있다는 것만 알 수 있다. 이러한 상황을 '클래스의 정의가 감추어진 상황'이라고 한다.
- 이렇게 클래스의 정의를 감추면, getPrinter() 메서드가 반환하는 인스턴스가 다른 클래스의 인스턴스로 변경되어도 Papers 클래스 외부의 코드는 조금도 수정할 필요가 없다. (코드에 유연성 추가)
- Iterator<E> 인터페이스가 그런 예다.
🔍 지역 클래스
- 외부 클래스의 메서드나 초기화 블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
- 지역 클래스는 외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있다.
- 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다. 단, final이 붙은 지역변수만 접근 가능하다
- 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문이다.
- 메소드 내에서 생성된 객체는 메소드 실행이 끝나도 힙 메모리에 존재해서 계속 사용할 수 있다. 그러나 매개 변수나 지역 변수는 메소드 실행이 끝나면 스택 메모리에서 사라지기 때문에 객체에서 사용할 수 없게 되는 문제가 발생한다.
- JDK1.8부터 지역 클래스에서 접근하는 지역 변수 앞에 final을 생략할 수 있게 바뀌었다. 대신 컴파일러가 자동으로 붙여준다. 만약에 해당 변수의 값이 바뀌는 문장이 있으면 컴파일 에러가 발생한다.
더보기
예제
public class Prac {
public static void main (String[] args) {
Papers p = new Papers("서류 출력");
Printable prn = p.getPrinter();
prn.print();
}
}
interface Printable {
void print();
}
class Papers {
private String con;
public Papers(String s) {con = s;}
// 지역 클래스 생성 및 반환
public Printable getPrinter() {
// 지역 클래스 정의
class Printer implements Printable {
public void print() {
System.out.println(con);
}
}
return new Printer();
}
}
서류 출력
- Printer 클래스가 getPrinter() 메서드 안에 선언되었다.
- 이렇듯 메서드 내에 클래스를 정의하면 해당 메서드 내에서만 인스턴스 생성이 가능하다.
- 인스턴스 클래스보다 클래스를 더 깊이, 특정 블록 안으로 감추는 효과가 있다.
예제2
class Inner {
private int outerIv = 0;
void myMethod() {
int lv = 0;
final int lv2 = 0; // JDK1.8부터 final 생략 가능
class LocalInner {
// lv = 5; // 에러.
}
lv=5;
}
}
- 외부 클래스의 메서드 내에서 정의된 지역 클래스는 final이 붙은 지역변수만 접근 가능하다. (JDK1.8부터 지역변수에 final 생략 가능)
- 지역클래스인 LocalInner 클래스가 포함되고 있는 myMethod() 메서드의 지역변수를 참조하는 순간 해당 지역 변수는 final이 붙은 상수로 바뀐다. (final 생략 가능)
🔍 익명 클래스
- 클래스의 선언과 객체의 생성을 동시에 하는 이름 없는 클래스다. (일회용)
- 생성자를 선언할수도 없으며, 오로지 한 개의 클래스 또는 한 개의 인터페이스를 상속 받거나 구현할 수 있다.
💡 익명 클래스 정의 2가지 방법
new 조상클래스() {
// 멤버 선언
};
new 인터페이스() {
// 멤버 선언
};
더보기
예제
public class Prac {
public static void main (String[] args) {
Papers p = new Papers("서류 출력");
Printable prn = p.getPrinter();
prn.print();
}
}
interface Printable {
void print();
}
class Papers {
private String con;
public Papers(String s) {con = s;}
// 지역 클래스 생성 및 반환
public Printable getPrinter() {
return new Printable() {
public void print() {System.out.println(con);};
};
}
}
서류 출력
- getPrinter() 메서드 안에 지역 클래스를 선언하지 않고 익명 클래스로 선언하였다.
728x90
'[자바] > 자바' 카테고리의 다른 글
[Java] Optional<T> 클래스 (0) | 2022.02.07 |
---|---|
[Java] 메서드 참조 (Method References) (0) | 2022.02.04 |
[Java] 함수형 인터페이스 (0) | 2022.02.03 |
[Java] 애노테이션 (annotation) (0) | 2022.01.26 |
[Java] 열거형 (enum) (0) | 2022.01.26 |