1 내부클래스란?
1.1 내부클래스란?
클래스 내에 선언된 클래스
이유는?
두 클래스가 서로 긴밀한 관계에 있기 때문
한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클 래스의 멤버들 간에 서로 쉽게 접근할 수 있다
불필요한 클래스를 감춤으로서 코드의 복잡성을 줄일 수 있 다.
1.1 내부클래스란?
클래스 내에 선언된 클래스
내부 클래스는 JDK 1.1이후에 추가된 개념이다.
내부클래스는 주로 AWT나 Swing과 같은 GUI어플리케이션 의 이벤트 처리 외에는 잘 사용하지 않을 정도로 사용빈도 가높지않다
따라서 원리와 특징을 이해하는 정도만 살펴봐도 되겠다.
class A{
…
}
class B{
…
}
class A{
…
class B{
…
}
}
2 내부클래스의 종류와 특징
2.1 내부클래스의 종류와 특징
선언되는 위치에 따른 구분
변수가 선언되는 위치에 따라 클래스/인스턴스/지역변수로 구분되 듯이
클래스도 선언된 위치에 따라 다음과 같이 구분된다.
내부클래스
특징
인스턴스클래스
외부클래스의 멤버변수 선언위치에 선언하며 외부클래스의 인스턴 스멤버처럼다우어진다.
주로 외부클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으 로 선언된다.
스태틱클래스
외부클래스의 멤버변수 선언위치에 선언하며, 외부클래스의 static 멤버처럼 다루어진다.
주로 외부클래스의 static멤버, 특히 static 메서드에서 사용될 목 적으로 선언된다.
지역클래스
외부클래스의 메서드나 초기화 블럭안에 선언하며 선언된 영역내부 에서만사용될수있다.
익명클래스
클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스이다.
3 내부클래스의 선언
3.1 내부클래스의 선언
다음의 코드를 보자.
class Outer{
int iv = 0;
static int cv= 0;
void myMethod(){
int lv= 0;
}
}
class Outer{
class InstanceInner{}
static class StaticInner{}
void myMethod(){
class LocalInner{}
}
}
내부클래스의 선언된 위치에 따라 유효범위와 접근성이 결 정된다.
4 내부클래스의 제어자와 접근성
4.1 내부클래스의 제어자와 접근성
다음의 코드를 보자.
내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있을 뿐 아니라 멤버변수들과 같이 private, protected와 같은 접근제어자도 사용이 가능하다.
class Outer{
privateint iv = 0;
protectedstatic int cv= 0;
void myMethod(){
int lv= 0;
}
}
class Outer{
privateclass InstanceInner{}
protectedstatic class StaticInner{}
void myMethod(){
class LocalInner{}
}
}
4.2 예제(1)
class InnerEx1 {
class InstanceInner{
int iv = 100;
//static int cv= 100; // 에러! static변수를선언할수없다.
final static int CONST = 100; // static final은상수이므로허용한다.
}
static class StaticInner{
int iv = 200;
static int cv= 200; // static클래스만static멤버를정의할수있다.
}
void myMethod() {
class LocalInner{
int iv = 300;
// static int cv= 300; // 에러! static변수를선언할수없다.
final static int CONST = 300; // static final은상수이므로허용
}
}
public static void main(Stringargs[]) {
System.out.println(InstanceInner.CONST);
System.out.println(StaticInner.cv);
}
}
4.2 예제(1)
내부클래스에서의 제어자 선언에는 제약이 있다.
static 선언
static내부 클래스만 static변수의 선언이 가능하다
다만 final static으로는 모든 내부 클래스에서 선언이 가 능하다.
4.3 예제(2)
class InnerEx2 {
class InstanceInner{}
static class StaticInner{}
InstanceInneriv = new InstanceInner(); // 인스턴스멤버간에는서로직접접근이가능하다.
static StaticInnercv= new StaticInner(); // static 멤버간에는서로직접접근이가능하다.
static void staticMethod() {// static멤버는인스턴스멤버에직접접근할수없다.
//InstanceInnerobj1 = new InstanceInner();
StaticInnerobj2 = new StaticInner();
//굳이접근하려면아래와같이객체를생성해야한다.
//인스턴스클래스는외부클래스를먼저생성해야만생성할수있다.
InnerEx2 outer = new InnerEx2();
InstanceInnerobj1 = outer.newInstanceInner();
}
void instanceMethod() {// 인스턴스메서드에서는인스턴스멤버와static멤버모두접근가능하다.
InstanceInnerobj1 = new InstanceInner();
StaticInnerobj2 = new StaticInner();
//메서드내에지역적으로선언된내부클래스는외부에서접근할수없다.
//LocalInnerlv= new LocalInner();
}
void myMethod() {
class LocalInner{}
LocalInnerlv= new LocalInner();
}
}
4.3 예제(2)
내부클래스와 외부클래스 멤버간의 호출간에도 제약 이 있다.
인스턴스 클래스
외부클래스의 인스턴스멤버를 객체생성 없이 바로 사용할 수 있지만 스태틱 클래스는 외부클래스의 인스턴스멤버를 객체생성없이 사용할 수 있다.
스태틱 클래스
스태틱 클래스에서는 인스턴스 클래스의 멤버를 객체 생 성을 하고 난 후에야 사용이 가능하다.
4.4 예제(3)
class InnerEx3 {
private int outerIv= 0;
static int outerCv= 0;
class InstanceInner {
int iiv= outerIv;//외부클래스의private멤버도접근가능하다.
int iiv2 = outerCv;
}
static class StaticInner {
//스태틱클래스는외부클래스의인스턴스멤버에접근할수없다.
//int siv= outerIv;
static int scv= outerCv;
}
void myMethod() {
int lv= 0;
final int LV = 0;
class LocalInner {
int liv= outerIv;
int liv2 = outerCv;
//외부클래스의지역변수는final이붙은변수(상수)만접근가능하다.
//int liv3 = lv;
int liv4 = LV;
}
}
}
4.4 예제(3)
내부클래스에서 외부클래스의 변수들에 대한 접근성 을 보여준다.
인스턴스 클래스는 외부클래스(InnerEx3)의 인스턴스 멤버이기 때문에
인스턴스변수outerIv와
static변수 outerCv를 모두 사용할 수 있다.
심지어는 outetIv의 접근제어자가 private라도 사용 이 가능하다.
4.4 예제(3)
Static 클래스는 외부 클래스의 static멤버이다
따라서 외부클래스의 인스턴스 멤버인 outerIv와
InstanceInner를 사용할 수 없다.
단지 static 멤버인 outerCv만을 사용할 수 있다.
지역클래스(LocalInner)는 외부클래스의 인스턴스멤 버와 static멤버를 모두 사용할 수 있다.
지역클래스가 포함된 메서드에 정의된 지역변수도 사용할 수있다.
단 final이 붙은 지역변수만 접근 가능한데 그 이유는 메 서드가 수행을 마쳐서 지역변수가 소멸된 시점에도 지역클 래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문이다.
4.5 예제(4)
class Outer {
class InstanceInner {
int iv=100;
}
static class StaticInner {
int iv=200;
static int cv=300;
}
void myMethod() {
class LocalInner {
int iv=400;
}
}
}
class InnerEx4 {
public static void main(Stringargs[]) {
// 인스턴스클래스의인스턴스를생성하려면
// 외부클래스의인스턴스를먼저생성해야한다.
Outer oc= new Outer();
Outer.InstanceInnerii = oc.newInstanceInner();
System.out.println("ii.iv: "+ ii.iv);
System.out.println("Outer.StaticInner.cv: " + Outer.StaticInner.cv);
// 스태틱내부클래스의인스턴스는외부클래스를먼저생성하지않아도된다.
Outer.StaticInnersi= new Outer.StaticInner();
System.out.println("si.iv: "+ si.iv);
}
}
4.5 예제(4)
외부클래스가 아닌 타 클래스에서 내부 클래스를 생 성하고 내부클래스로의 접근을 하는 예제이다.
그러나 이런경우는 적절하게 프로그래밍이 되지 않았 음을 방증하는 것이다.
굳이 내부클래스로 선언한 목적은 외부로 부터 클래 스를 감추고자 할때 이기 때문이다.
4.5 예제(4)
참고로 컴파일시에는 다음과 같이 클래스가 생성된다.
InnerEx4.class
Outer.class
Outer$InstanceInner.class
Outer$StaticInner.class
Outer$1LocalInner.class
지역내부클래스는 다른 메서드에 같은 이름의 내부 클래스가 존재 할 수 있기 때문에 내부클래스명 앞에 숫자가 붙는다.
4.6 예제(5)
class Outer {
int value=10; // Outer.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("Outer.this.value:" + Outer.this.value);
}
} // Inner클래스의끝
} // Outer클래스의끝
class InnerEx5 {
public static void main(Stringargs[]) {
Outer outer= new Outer();
Outer.Innerinner = outer.newInner();
inner.method1();
}
}
4.6 예제(5)
내부클래스와 외부클래스에 선언된 변수의 이름이 같 을때변수앞에this또는외부클래스명.this를붙여 서서로구별할수있다.
5 익명클래스 (anonymous class)
5.1 익명클래스
익명클래스
다른 내부 클래스와 달리 이름이 없다.
클래스의 선언과 함께 객체의 생성을 동시에 하기 때문에
단 한번만 사용될 수 있고
오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.
이름이 없기 때문에 생성자도 가질 수 없으며
조상클래스의 이름이나 구현하고자 하는 인터페이스의 이 름을 사용해서 정의하기 때문에
하나의 클래스로 상속받는 동시에 인터페이스를 구현하거 나
하나이상의 인터페이스를 구현할 수 없다.
오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페 이스만을 구현할 수 있다.
5.1 익명클래스
class InnerEx6 {
Object iv = new Object(){ void method(){} }; // 익명클래스
static Object cv= new Object(){ void method(){} }; // 익명클래스
void myMethod() {
Object lv= new Object(){ void method(){} };// 익명클래스
}
}
이 예제를 컴파일 하면 다음과 같이 4개의 클래스가 생성된다.
InnerEx6.class
InnerEx6$1.class
InnerEx6$2.class
InnerEx6$3.class
익명클래스는 이름이 없기 때문에 외부클래스명$숫자.class의 형식으 로 클래스파일명이 결정된다.