클래스 내부에 선언한 클래스로 일반적으로 내부 클래스를 감싸고 있는 외부 클래스와 연관이 있으며, 다른 외부 클래스에서 사용할 일이 거의 없는 경우에 내부 클래스를 선언해서 사용한다.
내부 클래스는 중첩 클래스라고도 한다.
내부 클래스의 종류
내부적으로 사용할 클래스를 선언하며 Private으로 선언하는 것을 권장한다.
private이 아닌 내부 클래스는 다른 외부 클래스에서 생성할 수 있다.
외부 클래스가 생성된 후 생성된다.
package ch01;
class OutClass {
private int num=10;
private static int sNum =20;
private InClass inClass;
public OutClass() {
inClass = new InClass();
}
// 내부 인스턴스
// inner class는 주로 private로 구현
private class InClass{
int iNum = 100;
//static int sInClass = 500;
// inner class는 일반적으로 outer class가 생성이 된 후애 생성이된다.
// 그래서 class생성전에 먼저 공간을 잡는 static 변수는 inner class에서 사용이 불가하다.
void inTest(){
System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수)");
System.out.println("InClass inNum = " + iNum + "(내부 클래스의 인스턴스 변수)");
}
}
public void usingClass() {
inClass.inTest();
// inner class내에 있는 method사용 예시
}
}
public class InnerTest {
public static void main(String args[]) {
OutClass outClass = new OutClass();
outClass.usingClass();
/*// inner class가 private로 만들지 않으면 아래와 같이 바로 사용도 가능
OutClass.InClass inner = outClass.new InClass();
inner.inTest();
*/
}
}
static으로 생성하여 외부 클래스와 무관하게 사용할 수 있다.
static variable과 static method를 사용한다.
정적 내부 클래스는 일반 메서드와 정적 메서드에서의 변수 사용에 제약이 있다.
package ch01_1;
class OutClass {
private int num=10;
private static int sNum =20;
// 정적 내부 클래스
static class InStaticClass {
int iNum = 100;
static int sInNum = 1200;
void inTest(){
// 내부 인스턴스와 다르게 정적 내부 클래스는 static으로 만들어 진 것이라 외부 클래스의
// 인스턴스 생성 여부에 상관없이 생성이 된다.
// 그래서 외부 인스턴스의 일반 인스턴스 변수는 정적 내부 클래스에서 사용이 불가능하다.
//System.out.println("OutClass num = " +num + "(외부 클래스의 인스턴스 변수)");
System.out.println("InStaticClass inNum = " + iNum + "(내부 클래스의 인스턴스 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
}
static void sTest(){ // 정적 클래스의 static 메서드
// 정적 클래스의 static 메서드에서는 내부 클래스의 인스턴스 변수도 사용할 수 없음 (외부 클래스의 인스턴스 변수도 사용할 수 없음.)
// System.out.println("InStaticClass inNum = " + iNum + "(내부 클래스의 인스턴스 변수 사용)");
System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 스태틱 변수 사용)");
System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 스태틱 변수 사용)");
}
}
}
public class InnerTest2 {
public static void main(String args[]) {
// 인스턴스 inner class와 다르게 정적 inner class는 바로 생성 가능
OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
sInClass.inTest();
System.out.println("\n정적 내부 클래스의 스태틱 메소드 호출");
OutClass.InStaticClass.sTest();
// 정적 내부 클래스의 static 메소드는 바로 호출 가능하다.
}
}
지역 변수와 같이 메서드 내부에서 정의하여 사용하는 클래스이다.
지역변수와 메서드의 매개변수는 내부클래스에게는 상수로 잡혀서 읽기만 가능하고 변경은 불가하다. (final로 선언되어 사용된다.)
내부 class의 method는 일을 수행하고나면 사라지는데 외부의 지역변수와 매게변수는 계속 stack에 남아있어서 변경이 불가하다.
package ch02;
class Outer {
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i) {
// 매개변수 i는 매서드가 호출될 때 stack memory에 생성이 된다.
int num = 10;
class MyRunnable implements Runnable {
int localNum = 1000;
@Override
public void run() {
//num = 200;
//i = 100;
// 지역변수와 메서드의 매개변수는 내부클래스에게는 상수로 잡혀서 읽기만 가능하고 변경은 불가하다. (final로 잡힘)
// 내부 class의 method는 일을 수행하고나면 사라지는데 외부의 지역변수와 매게변수는 계속 stack에 남아있어서 변경이 불가하다.
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 = " + Outer.sNum + "(외부 클래스 정적 변수)");
}
}
return new MyRunnable();
}
}
public class LocalInnerClass {
public static void main(String args[]) {
Outer out = new Outer();
Runnable runner = out.getRunnable(10);
runner.run();
}
}
이름이 없는 내부 클래스로 클래스의 이름을 생략하고 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 반환한다.
인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나 지역 내부 클래스의 메서드 내부에서 생성하여 반환할 수 있다.
Android programming의 widget 이벤트 핸들러에 활용된다.
package ch02_1;
class Outer {
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i) {
// 매개변수 i는 매서드가 호출될 때 stack memory에 생성이 된다.
int num = 10;
// anonymous inner class
return new Runnable() {
int localNum = 1000;
@Override
public void run() {
//num = 200;
//i = 100;
// 지역변수와 메서드의 매개변수는 내부클래스에게는 상수로 잡혀서 읽기만 가능하고 변경은 불가하다. (final로 잡힘)
// 내부 class의 method는 일을 수행하고나면 사라지는데 외부의 지역변수와 매게변수는 계속 stack에 남아있어서 변경이 불가하다.
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 = " + Outer.sNum + "(외부 클래스 정적 변수)");
}
};
}
/* 다음과 같이도 사용 가능
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
*/
}
public class AnonymousInnerTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Outer out = new Outer();
Runnable runner = out.getRunnable(10);
runner.run();
}
}