내부클래스(Inner Class)
내부클래스란 클래스 내부에 구현한 클래스(중첩된 클래스)다.
내부클래스에서 외부클래스의 멤버들을 쉽게 접근할 수 있고 외부에 불필요한 클래스를 감춰서
코드의 복잡성을 줄일 수 있다.
두 클래스가 서로 긴밀한 관계가 있을 때 내부클래스를 사용한다.
주로 외부클래스 생성자에서 내부클래스를 생성한다.
종류 |
구현 위치 |
사용할 수 있는 외부 클래스 변수 |
생성 방법 |
인스턴스 내부 클래스 |
외부 클래스 멤버 변수와 동일 |
외부 인스턴스 변수 외부 전역변수 |
외부 클래스를 먼저 만든 후 내부 클래스를 생성 |
정적 내부 클래스 |
외부 클래스 멤버 변수와 동일 |
외부 전역변수 |
외부 클래스와 무관하게 생성 |
지역 내부 클래스 |
메서드 내부에 구현 |
외부 인스턴스 변수 외부 전역 변수 |
메서드를 호출할 때 생성 |
익명 내부 클래스 |
메서드 내부에 구현하거나 변수에 대입하여 직접 구현 |
외부 인스턴스 변수 외부 전역 변수 |
메서드를 호출할 때 생성되거나, 인터페이스 타입 변수에 대입할 때 new 예약어를 사용하여 생성 |
예제코드
class OutClass {
private int num = 10;
private static int sNum = 20;
private InClass inClass;
public OutClass() {
inClass = new InClass();
} //Constructor End
//innerClass를 주로 OutClass의 Constructor에서 많이 생성한다.
class InClass() {
int iNum = 100;
void inTest() {
System.out.println(num);
System.out.println(sNum);
}
} //InClass End
/*
InnerClass다. 메서드 안에 있는 것도 아니고
static이 붙은것도 아니기 때문에 instance Inner Class다.
안에 있는 변수인 iNum의 경우는 static를 붙이면 에러가 발생한다.
InnerClass는 생성이후에 쓸 수 있는 클래스인데
static은 생성과 관계없이 쓸 수 있기 때문에 오류가 발생한다.
물론 클래스에도 static을 붙인다면 문제가 되지 않지만
현재는 Instance Inner Class 이고 OutClass 이후에 생성되야 하기
때문에 사용할 수 없다.
*/
public void usingInner() {
inClass.inTest();
}
static class InStaticClass {
//static Inner Class이며 OutClass의 생성 여부와 상관없이 사용된다.
int inNum = 100;
static int sInNum = 200;
void inTest() {
System.out.println(inNum);
System.out.println(sInNum);
System.out.println(sNum);
}
static void sTest() {
System.out.println(sInNum);
System.out.println(sNum);
}
/*
static 클래스이기 때문에 static 변수나 static 메서드를 만들 수 있다.
여기서 static이 아닌 inNum은 사용할 수 없다.
inNum의 경우는 static 메서드들 보다 나중에 생성되기 때문이다.
*/
} //InStaticClass End
} //OutClass End
public class InnerTest {
public static void main(String[] args) {
OutClass outClass = new OutClass();
outClass.usingInner();
//InClass를 private변수로 만들었기 때문에 부를 수 없다.
//그래서 usingInner를 만들어서 호출한다.
OutClass.InClass myInClass = outClass.new InClass();
//많이 쓰는 문법은 아니라고 한다.
//outClass에서만 쓰려고 InnerClass를 사용하는 것인데
//이렇게 사용할거면 InnerClass로 만들어줄 필요가 없기 때문이다.
//문법적으로는 사용이 가능하다는 것이고
//이렇게 사용하는것도 방지하고자 한다면 InClass를 Private 으로 만들어주면 된다.
System.out.println();
OutClass.InStaticClass.sTest();
/*
static메서드는 이렇게 호출해서 사용할 수 있다.
하지만 inTest메서드는 static 메서드가 아니기 때문에
이렇게 호출 할 수는 없다.
inTest 메서드는
OutClass.InStaticClass.sInClass = new OutClass.InStaticClass();
sInClass.inTest();
이렇게만 호출이 가능하다.
sTest()도 이렇게 호출할 수 있다.
*/
}
} //InnerTest End
//지역 내부 클래스
class Outer {
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i) {
int num = 100;
class MyRunnable implements Runnable {
@Override
public void run() {
//이렇게 메서드 안에 클래스를 만들면
//지역 내부 클래스이다.
System.out.println(num);
System.out.println(i);
System.out.println(outNum);
System.out.println(Outer.sNum);
/*
여기서 num과 i는 메서드 안에 있는 지역변수다.
이 메서드가 호출되서 끝날때까지만 유효한게
지역변수이지만 MyRunnable이 반환되고 나면
이 메서드가 끝난 다음에도 run은 언제든지
호출 될 수 있다.
그럼 이 run이 호출되었을 때는 지역변수이기 때문에
변수가 유효하지 않게 된다.
그래서 지역내부 클래스가 쓰이는 메서드에서 변수들은
상수가 된다.
*/
} //run method End
}//MyRunnable End
return new MyRunnable();
} //getRunnable End
} //Outer End
public class LocalInnerClassTest {
public static void main(String[] args) {
Outer outer = new Outer();
Runnable runnable = outer.getRunnable(50);
runnalbe.run();
}
} //Test End
//익명 이너 클래스
class Outer {
int outNum = 100;
static int sNum = 200;
Runnable getRunnable(int i) {
int num = 100;
return new Runnable() {
@Override
public void run() {
Sytem.out.println(num);
Sytem.out.println(i);
Sytem.out.println(outNum);
Sytem.out.println(sNum);
}
};
//익명 이너클래스다. 이름이 없는 이너클래스.
}
Runnable runner = new Runnable() {
@Override
public void run() {
System.out.println("test");
}
};
/*
이렇게도 작성할 수 있다.
익명 이너 클래스는 바로 인터페이스나 추상클래스에 대한 생성을
바로 할 수 있다.
원래는 상속받은 클래스를 만들도 클래스를 생성해서 사용했는데
단 하나의 인터페이스나 단 하나의 추상클래스인 경우는
클래스의 이름없이 new 키워드를 이용해 생성할 수 있다.
*/
} //Outer End
public class AnonymousInnerClassTest {
public static void main(String[] args) {
Outer outer = new Outer();
outer.runner.run();
Runnable runnable = outer.getRunnable(50);
runnable.run();
}
} //Test End
레퍼런스
● 패스트캠퍼스 올인원 패키지 - 자바 객체지향프로그래밍
'JAVA' 카테고리의 다른 글
컬렉션 프레임워크(Collection Framework) (0) | 2021.02.08 |
---|---|
예외처리(Exception) (0) | 2021.02.07 |
Class 클래스 (0) | 2021.02.04 |
Object 클래스 (0) | 2021.02.03 |
final 키워드 (0) | 2021.02.02 |