클래스 안의 클래스
class A {
...
class B {
...
}
}
내부 클래스의 장점
내부 클래스의 종류와 유효범위(scope)는 변수와 동일
class Outer {
class InstanceInner {}
static class StaticInner {}
void method() {
class LocalInner {}
}
}
class InstanceInner {}
: 인스턴스 내부 클래스, 인스턴스 변수(iv)와 특징이 같다.
static class StaticInner {}
: 스태틱 내부 클래스, 스태틱 변수(cv)와 특징이 같다.
class LocalInner {}
: 지역 내부 클래스, 지역 변수(lv)와 특징이 같다.
익명 클래스 : 클래스의 선언과 객체 생성을 동시에 하는 이름 없는 클래스(일회용)
-> 주로 이벤트를 처리하는데 사용
내부 클래스의 제어자는 변수에 사용 가능한 제어자와 동일
class Ex7_12 {
class InstanceInner {
int iv = 100;
// static int cv = 100; // 에러
final static int CONST = 100;
}
static class StaticInner {
int iv = 200;
static int cv = 200;
}
void myMethod() {
class LocalInner {
int iv = 300;
// static int cv = 300; // 에러
final static int CONST = 300;
}
int i = LocalInner.CONST; // OK
}
public static void main(String[] args) {
System.out.println(InstanceInner.CONST);
System.out.println(StaticInner.cv);
// System.out.println(LocalInner.CONST); // 에러
}
}
System.out.println(LocalInner.CONST);
: 지역 내부 클래스의 static 상수는 메서드 밖에서 사용 불가, 메서드 내에서만 사용 가능class Ex7_13 {
class InstanceInner {}
static class StaticInner {}
InstanceInner iv = new InstanceInner();
static StaticInner cv = new StaticInner();
static void staticMethod() {
// InstanceInner obj1 = new InstanceInner(); // 에러
StaticInner obj2 = new StaticInner();
}
void instanceMethod() {
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// LocalInner lv = new LocalInner(); // 에러
}
void myMethod() {
class LocalInner {}
LocalInner lv = new LocalInner();
}
}
InstanceInner iv = new InstanceInner();
: 인스턴스 멤버끼리 직접 접근 가능static StaticInner cv = new StaticInner();
: static 멤버끼리 직접 접근 가능InstanceInner obj1 = new InstanceInner();
: static 메서드에서 인스턴스 멤버에 직접 접근 불가 void instanceMethod() {
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// LocalInner lv = new LocalInner(); // 에러
}
인스턴스 메서드에서 인스턴스 멤버와 static 멤버 모두 접근 가능
LocalInner lv = new LocalInner();
: 지역 내부 클래스는 외부에서 접근 불가
class Outer {
private int outerIv = 0;
private static int outerCv = 0;
class InstanceInner {
int iiv = outerIv;
int iiv2 = outerCv;
}
static class StaticInner {
// int siv = outerIv; // 에러
static int scv = outerCv;
}
}
int iiv = outerIv;
: 외부 클래스의 private 멤버도 접근 가능
int siv = outerIv;
: static 내부 클래스는 외부 클래스의 인스턴스 멤버에 접근 불가
class Outer {
void myMethod() {
int lv = 0; // 값이 바뀌지 않는 변수는 상수로 간주
final int LV = 0; // 상수 OK
class LocalInner {
int liv = outerIv;
int liv2 = outerCv;
int liv3 = lv; // 에러(JDK1.8부터 에러 아님)
int liv4 = LV; // OK
}
}
}
int liv4 = LV;
: 외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근 가능
int liv3 = lv;
: JDK1.8부터 에러가 아니다. 원래는 지역 내부 클래스에서 메서드의 지역변수에 접근 불가하지만, JDK1.8부터 변수인데 값이 바뀌지 않으면 상수로 간주하기 때문이다.
class Outer {
void myMethod() {
int lv = 0; // 값이 바뀌지 않는 변수는 상수로 간주
lv = 10;
class LocalInner {
int liv3 = lv; // 에러
}
}
}
int liv3 = lv;
는 에러가 뜬다.class Outer {
void myMethod() {
int lv = 0;
final int LV = 0;
lv = 10;
class LocalInner {
void LiMethod() {
System.out.println(lv);
}
}
}
지역변수 lv는 myMethod() 종료와 함께 소멸된다. 그러나 지역 내부 클래스 안에 있는 LiMethod() 메서드는 myMethod() 메서드와 상관 없이 더 오래 존재할수도 있기 때문에 지역변수 lv를 사용할 수 없는 것이다.
상수 LV는 constant pool 에서 따로 관리하기 때문에 메서드 종료와 상관 없이 계속 쓸 수 있다. 따라서, 지역 내부 클래스에서 접근이 가능한 것이다.
class Outer2 {
class InstanceInner {
int iv = 100;
}
static class StaticInner {
int iv = 200;
static int cv = 300;
}
void myMethod() {
class LocalInner {
int iv = 400;
}
}
}
class Ex7_15 {
public static void main(String[] args) {
Outer2 oc = new Outer2(); // 외부 클래스의 객체를 먼저 생성
Outer2.InstanceInner ii = oc.new InstanceInner(); // 내부 클래스 객체 생성
System.out.println("ii.iv : "+ ii.iv);
System.out.println("Outer2.StaticInner.cv : "+Outer2.StaticInner.cv);
Outer2.StaticInner si = new Outer2.StaticInner();
System.out.println("si.iv : "+ si.iv);
}
}
Outer2 oc = new Outer2();
: 내부 클래스의 객체를 생성하려면 먼저 외부 클래스의 객체를 생성해야 한다.
-> 내부 클래스 InstanceInner 또한 인스턴스 멤버이기 때문에
Outer2.StaticInner si = new Outer2.StaticInner();
: static 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
class Outer3 {
int value = 10; // Outer3.this.value
class Inner {
int value = 20; // this.value
void method1() {
int value = 30;
System.out.println("value : " + value);
System.out.println("this.value : " + this.value);
System.out.println("Outer3.this.value : " + Outer3.this.value);
}
} // Inner 클래스의 끝
} // Outer3 클래스의 끝
class Ex7_16 {
public static void main(String args[]) {
Outer3 outer = new Outer3();
Outer3.Inner inner = outer.new Inner();
inner.method1();
}
}
결과
value : 30
this.value : 20
Outer3.this.value : 10
이름이 없는 일회용 클래스. 정의와 생성을 동시에
new 조상클래스이름() {
/*클래스 내용*/
}
new 구현 인터페이스이름() {
/*클래스 내용*/
}
import java.awt.*;
import java.awt.event.*;
class Ex7_18 {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new EventHandler());
}
}
class EventHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent occurred!!!");
}
}
EventHandler 클래스를 익명 클래스로 처리
import java.awt.*;
import java.awt.event.*;
class Ex7_18 {
public static void main(String[] args) {
Button b = new Button("Start");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("ActionEvent occurred!!!");
}
});
}
}