18. 내부클래스
1. 내부클래스란
- 클래스 내에 선언된 클래스
- 주로 AWT나 Swing과 같은 GUI어플리케이션 이벤트처리에 사용
- 클래스 내에 내부클래스를 선언하면 두 클래스의 멤버 간 접근이 용이
- 외부에는 불필요한 클래스를 감춘다
- 내부클래스 선언 위치에 따른 종류
- 인스턴스 클래스
- 외부클래스의 멤버변수 선언위치에 선언
- 외부클래스의 인스턴스멤버처럼 다루어진다
- 스태틱 클래스
- 외부클래스의 멤버변수 선언위치에 선언
- 외부캘르새의 static 멤버처럼 다루어진다
- 지역 클래스
- 외부클래스의 메서드나 초기화블럭 안에 선언
- 선언된 영역 내부에서만 사용가능
- 익명 클래스
- 클래스의 선언과 객체의 생성을 동시에하는 일회용 클래스
- 인스턴스 클래스
- 내부클래스도 클래스이기에 abstract나 final 등의 제어자 사용 가능
- 추가적으로 private, protected 제어자 사용 가능
public class InnerTest1 {
class InstanceInner{
int iv=100;
// static int cv = 100; // error : 내부클래스 중 static클래스는 static 멤버를 가질 수 있다
final static int CONST = 100; //static final은 상수이므로 사용 가능
}
static class StaticInner{
int iv = 200;
static int cv = 200; // static 클래스만 static 멤버 정의 가능
}
void method() {
class LocalInner{
int iv = 300;
// static int cv = 300; // error
final static int CONST = 300;
}
}
public static void main(String[] args) {
System.out.println(InstanceInner.CONST);
System.out.println(StaticInner.cv);
}
}
- static 내부 클래스는 외부클래스의 static 멤버만 접근 가능
- 내부클래스는 외부클래스의 지역변수중 final이 붙은 상수만 접근 가능
- jdk8.0부터는 지역변수도 접근 가능
public class InnerTest2 {
private int outerIv = 0;
static int outerCv = 0;
class InstanceInner{
int iiv = outerIv;
int icv = outerCv;
}
static class StaticInner{
// int siv = outerIv; // error : 외부클래스의 static 멤버만 접근 가능
static int scv = outerCv;
}
public void method() {
int lv = 0; //지역변수
final int LV = 0;
class LocalInner{
int liv = outerIv;
int lcv = outerCv;
int llv = lv; // jdk8.0부터는 지역변수도 접근가능
int lLv = LV;
}
}
public static void main(String[] args) {
}
}
- 인스턴스 내부 클래스의 인스턴스를 생성하려면 외부클래스의 인스턴스 먼저 생성해야한다.
- 스태틱 내부 클래스의 인스턴스는 외부클래스 먼저 생성하지 않아도 된다.
class Outer{
class InstanceInner{
int iv = 100;
}
static class StaticInner{
int iv = 200;
static int cv = 300;
}
void method() {
class LocalInner{
int iv = 400; // 외부에서 접근 불가
}
}
}
public class InnerTest3 {
public static void main(String[] args) {
//1 static 내부클래스의 인스턴스 생성
Outer.StaticInner si = new Outer.StaticInner();
System.out.println(si.iv);
//2 인스턴스 내부 클래스의 인스턴스 생성
Outer oc = new Outer();
Outer.InstanceInner ii = oc.new InstanceInner();
System.out.println(ii.iv);
}
}
- 내부 클래스의 this 확인
class Outer2{
int value = 10;
class Inner{
int value = 20;
void method() {
int value = 30;
System.out.println("value="+value); //30
System.out.println("this.value="+this.value); // 20
System.out.println("Outer2.this.value="+Outer2.this.value); //10
}
}
}
public class InnerTest4 {
public static void main(String[] args) {
Outer2 oc = new Outer2();
Outer2.Inner inner = oc.new Inner();
inner.method();
}
}
- 내부클래스 내 객체생성 확인
public class InnerTest5 {
class instanceInner{
}
static class StaticInner{
}
static void staticMethod() {
//static멤버는 static 만 접근 가능
//instanceInnsr obj1 = new InstanceInner(); //error
StaticInner obj2 = new StaticInner();
}
void instanceMethod() {
instanceInner obj1 = new instanceInner(); //error
StaticInner obj2 = new StaticInner();
}
public static void main(String[] args) {
}
}
익명클래스
- 클래스의 선언과 객체의 생성을 동시에 한다
- 단 한번만 사용될 수 있으며, 하나의 객체만 생성하는 일회용 클래스
- 이름이 없어 생성자를 가질 수 없다
- 부모의 클래스이름이나 인터페이스의 이름을 사용해서 정의
- 오직 하나의 클래스를 상속 혹은 하나의 인터페이스만을 구현 가능
new 부모클래스명(){멤버선언};
public class Anonymous1 {
Object iv = new Object() {
void method() {}
};
static Object cv = new Object() {
void method() {}
};
void myMethod() {
Object lv = new Object() {
void method() {}
};
}
public static void main(String[] args) {
}
}
2. 내부클래스 활용 이벤트처리
- 내부클래스 이용
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class EventTest1 extends Frame {
private Button bt;
public EventTest1() {
bt=new Button("닫기");
this.add(bt,"South");
bt.addActionListener(new EventHandler());
}
class EventHandler implements ActionListener{
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
public static void main(String[] args) {
EventTest1 f= new EventTest1();
f.setSize(300,200);
f.setVisible(true);
}
}
- 익명클래스 이용
import java.awt.Button;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class EventTest2 extends Frame {
private Button bt;
public EventTest2() {
bt=new Button("닫기");
this.add(bt,"South");
bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args) {
EventTest2 f= new EventTest2();
f.setSize(300,200);
f.setVisible(true);
}
}