클래스 내부에 선언한 클래스로 이 클래스를 감싸고 있는 외부 클래스와 밀접한 연관
이 있는 경우가 많고, 다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스로 선언해서 사용함
중첩 클래스
라고도 함
내부 클래스의 종류
인스턴스 내부 클래스, 정적(static) 내부 클래스, 지역(local) 내부 클래스, 익명(anonymous) 내부 클래스
private
으로 선언하는 것을 권장)OutClass outClass = new OutClass();
OutClass.InClass inClass = outClass.new InClass();
package chapter6;
class OutClass{
private int num = 10;
private static int sNum = 20;
private InClass inClass;
public OutClass(){
inClass = new InClass();
}
class InClass{
int inNum = 100;
// static int sInNum = 500; 에러남 사용할려면 정적 내부 클래스에
void inTest(){
System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
}
}
public void usingClass() {
inClass.inTest(); // 주로 이런 식으로 사용.
}
}
public class innerTest {
public static void main(String[] args) {
OutClass outClass = new OutClass();
outClass.usingClass();
OutClass.InClass inner = outClass.new InClass(); // 위의 방법을 자주 사용
inner.inTest();
}
}
static class InStaticClass{
int inNum = 100;
static int sInNum = 200;
void inTest(){ //정적 클래스의 일반 메서드
//num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
System.out.println("InStaticClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
}
static void sTest(){ // 정적 클래스의 static 메서드
//num += 10; // 외부 클래스의 인스턴스 변수는 사용할 수 없음.
//inNum += 10; // 내부 클래스의 인스턴스 변수는 사용할 수 없음
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
}
}
public class InnerTest {
public static void main(String[] args) {
.....
//외부 클래스 생성하지 않고 바로 정적 내부 클래스 생성
OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
System.out.println("정적 내부 클래스 일반 메서드 호출");
sInClass.inTest();
System.out.println();
System.out.println("정적 내부 클래스의 스태틱 메소드 호출");
OutClass.InStaticClass.sTest();
}
}
메서드 내부
에서 정의하여 사용하는 클래스final
로 선언됨package chapter6;
class Outer2{
int outNum = 100;
static int sNum = 200;
// 내부 메서드 안 클래스. i와 num은 스택 메모리에 생성이 된다!
Runnable getRunnable(int i) {
int num = 10;
class MyRunnable implements Runnable{
int localNum = 1000;
@Override
public void run() {
// 밑에서 변경할려면 오류가 발생함
// 메서드는 호출이 끝나고나면 매개변수와 지역변수는 사라진다
// ->이후 또 호출했을때 i 와 num이 없을수도
// int i, int num에 final을 컴파일러가 붙임(스택 영역이 아닌 상수 영역에 잡힘)
// 따라서 change 불임
//num = 200; //에러 남. 지역변수는 상수로 바뀜
//i = 100; //에러 남. 매개 변수 역시 지역변수처럼 상수로 바뀜
System.out.println("i =" + i);
System.out.println("num = " +num);
System.out.println("localNum = " +localNum);
System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수)");
System.out.println("Outter.sNum = " + Outer2.sNum + "(외부 클래스 정적 변수)");
}
}
return new MyRunnable();
}
}
public class AnonymousTest {
public static void main(String[] args) {
Outer2 out = new Outer2();
Runnable runner = out.getRunnable(100);
// 위에서 메서드 호출이 끝났지만 다시 불리는 상황을 볼 수 있음
runner.run();
}
}
이름이 없는 클래스
(위 지역 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없음)
-> 위 경우 함수에 바로 return new Runnable(){ ... }
클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환
인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부에서 생성하여 반환 할 수 있음.
widget의 이벤트 핸들러에 활용됨
package chapter6;
class Outter2{
Runnable getRunnable(int i) {
int num = 100;
return new Runnable() {
@Override
public void run() {
// num = 200;
// i = 10;
// 위 둘다 에러
System.out.println(i);
System.out.println(num);
}
};
}
Runnable runner = new Runnable() {
public void run() {
System.out.println("Runnable이 구현되었습니다.");
}
};
}
public class AnnoymousInnerTest {
public static void main(String[] args) {
Outter2 out = new Outter2();
Runnable runnerable = out.getRunnable(10);
runnerable.run();
out.runner.run();
}
}
10
100
Runnable이 구현되었습니다.