반응형
내부 클래스
클래스 내에 선언된 클래스 → 두 클래스가 서로 긴밀한 관계에 있을 때 사용
내부 클래스 장점
- 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다.
- 코드의 복잡성을 줄일 수 있다.(캡슐화)
- 외부에는 불필요한 클래스를 감출 수 있기 때문에
class A { //독립적인 Class
...
}
class B { //독립적인 Class
...
}
class A { //외부 클래스
...
class B { //내부 클래스
...
}
...
}
내부 클래스 B는 외부 클래스 A를 제외하고는 다른 클래스에서 잘 사용되지 않아야 된다.
내부클래스의 종류와 특징
변수의 선언과 동일하게 내부클래스도 선언 위치에 따라서 구분되어 진다.
(내부 클래스는 변수를 선언하는 것과 같은 위치에 선언할 수 있다.)
- 인스턴스 클래스(instance class) - 외부 클래스의 멤버변수 선언위치에 선언한다.
- 외부 클래스의 인스턴스멤버 처럼 다루어 진다.
- 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언된다.
- 스태틱 클래스(static class) - 외부 클래스의 멤버변수 선언위치에 선언한다.
- 외부 클래스의 static멤버처럼 다루어 진다.
- 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다.
- 지역 클래스(local class)
- 외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다.
- 익명 클래스(anonymous class)
- 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용)
내부 클래스의 선언 → 변수 선언위치와 동일하다.
- 위치에 따라 같은 선언위치의 변수와 동일한 유효범위(scope)와 접근성(accessibillity)를 갖는다.
public class Outer {
int iv = 0; //인스턴스 생성시 생성
class InstanceInner{}
static int cv = 0; // Outer class가 메모리에 올라갈 때 생성
// 외부 클래스라서 정의 가능하다. 내부 클래스에서는 static 변수 정의 X
static class StaticInner{}
/*
인스턴스클래스와 스태틱클래스는 외부클래스 Outer의 멤버변수(인스턴스 변수와 클래스 변수)와
같은 위치에 선언되며, 멤버변수와 같은 성질을 갖는다.
*/
void myMethod() {
int lv = 0; //생성된 인스턴스에서 myMethod()호출시 생성?
class LocalInner{}
}
}
내부 클래스가 외부 클래스의 멤버와 같이 간주되기 때문에 인스턴스멤버와 static멤버 간의 규칙이 내부 클래스와 동일하다.
- 내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있다.
- 추가적으로 멤버 변수들처럼 private, protected같은 접근제어자도 사용 가능하다.
- 내부 클래스 중에서 스태틱클래스만 static멤버를 가질 수 있다.
- final과 static이 동시에 붙은 변수인 상수(constant)는 모든 클래스에서 정의가 가능하다.
public class Outer {
private int outerIv = 0;
static int outerCv = 0;
class InstanceInner {
int iiv = outerIv; // 외부 클래스의 private멤버도 접근 가능하다.
int iiv2 = outerCv;
}
static class StaticInner {
// static 클래스는 외부 클래스의 인스턴스멤버에 접근할 수 없다.
// int siv = outerIv;
static int scv = outerCv;
// 인스턴스클래스를 접근하려면 외부 클래스를 먼저 생성해야만 생성할 수 있다.
Outer outer = new Outer();
InstanceInner instanceInner = outer.new InstanceInner();
}
void myMethod(){
int lv = 0; //JDK1.8 부터 final 생략가능하다.
final int LV = 0;
class LocalInner {
int liv = outerIv;
int liv2 = outerCv;
// 외부 클래스의 지역변수는 final이 붙은 상수만 접근 가능하다.
// int liv3 = lv; //에러!! (JDK1.8부터는 에러 아니다.)
int liv4 = LV;
}
}
}
/*
컴파일 시 생성되는 클래스 파일
Outer.class
Outer$InstanceInner.class
Outer$StaticInner.class
Outer$1LocalInner.class
public static void main(String[] args) {
//외부 클래스의 인스턴스를 먼저 생성해야 인스턴스클래스의 인스턴스를 생성 가능하다.
Outer outer = new Outer();
Outer.InstanceInner ii = outer.new InstanceInner();
System.out.println("ii.iiv = " + ii.iiv);
//스태틱클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
Outer.StaticInner si = new Outer.StaticInner();
System.out.println("si.scv = " + si.scv);
}
인스턴스클래스는 외부 클래스의 인스턴스멤버이기 때문에 인스턴스 변수 모두 사용 가능하다.
- outerlv의 접근 제어자가 private일지라도 사용 가능하다.
스태틱클래스는 외부 클래스의 static멤버이기 때문에 static 멤버인 outerCv만 사용 가능하다.
지역클래스는 외부 클래스의 인스턴스멤버와 static멤버를 모두 사용할 수 있다.
- 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용 가능하다. (단 final이 붙은 지역변수만!)
- 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문에 상수만 가능하다.
- JDK1.8부터 지역 클래스에서 접근하는 지역 변수 앞에 final을 생략할 수 있게 바뀌었다.
- 컴파일러가 편의상 final을 자동으로 붙여줘서 생략할 수 있게 해준거라서 변수의 값이 바뀌는 문장이 있을면 컴파일 에러가 발생한다.
public class Outer {
private int value = 10; //Outer.this.value
class InstanceInner {
int value = 20; //this.value
void method(){
int value = 30; //value
System.out.println("Ou = " + Outer.this.value);
System.out.println("this.iiv = " + this.value);
System.out.println("value = " + value);
}
}
내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 때 변수 앞에 ‘this’ 또는 ‘외부 클래스명.this’를 붙여서 구별할 수 있다.
익명 클래스(anonymous class)
다른 내부 클래스들과는 달리 이름이 없다.
- 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.
new 부모클래스이름() {
//멤버 선언
}
또는
new 구현인터페이스이름() {
//멤버 선언
}
- 이름이 없기 때문에 생성자도 가질 수 없다.
- 부모클래스 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의한다.
- 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다.
- 단 하나의 클래스를 상속받거나, 단 하나의 인터페이스만 구현할 수 있다.
public class Anonymous {
public static void main(String[] args) {
Button b = new Button("Start"); //java.awt.Button
b.addActionListener(new EventHandler());
}
}
class EventHandler implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
System.out.println("ActionEvent occurred!!!");
}
//위에 코드를 익명 클래스로 변환
public class Anonymous {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent occurred!!!");
}
}); // 익명클래스 끝
}
}
익명클래스를 이용하여 보다 쉽게 코드를 작성할 수 있다.
반응형
'책 > Java의 정석' 카테고리의 다른 글
[java] 예외처리(1) (0) | 2023.02.07 |
---|---|
[java] instanceof 연산자 (0) | 2023.02.07 |
[java] 인터페이스 && default 메서드와 static 메서드 (0) | 2023.02.04 |
[java] 추상클래스와 추상메서드 (0) | 2023.02.04 |
[java] 제어자(modifier) (2) | 2023.02.04 |