공부했던 자료 정리하는 용도입니다.
재배포, 수정하지 마세요.
내부 클래스(Inner Class)
내부 클래스는 클래스 내에 선언된다는 점을 제외하고는 일반적인 클래스와 다르지 않다. AWT나 Swing과 같은 GUI 애플리케이션의 이벤트 처리 외에는 잘 사용되지 않는다.
내부 클래스란?
내부 클래스의 장점 1. 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있다. |
내부 클래스는 클래스 내에 선언된 클래스이다. 두 클래스가 서로 긴밀한 관계가 있을 때 내부 클래스를 사용한다. 한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클래스 멤버들 간에 서로 쉽게 접근할 수 있고, 외부에는 불필요한 클래스를 감춰서 코드의 복잡성을 줄일 수 있다는 장점이 있다.
class A{ //외부클래스
...
class B{ //내부클래스
...
}
...
}
위의 코드에서 B 는 A 의 내부 클래스가 되고 A 는 B 의 바깥에 있는 외부 클래스가 된다. 이때 내부 클래스인 B 는 외부 클래스인 A 를 제외하고는 다른 클래스에서 잘 사용되지 않는 것이어야 한다. (외부 클래스가 아닌 다른 클래스에서 내부 클래스에 접근해야 한다면 내부 클래스로 선언해서는 안 되는 클래스를 내부 클래스로 선언했다는 의미이다.)
내부 클래스의 종류와 특징
내부클래스 | 특징 |
인스턴스 클래스 (instance class) |
외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다뤄진다. 주로 외부 클래스의 인스턴스멤버들과 관련된 작업에 사용될 목적으로 선언된다. |
스태틱 클래스 (static class) |
외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 static멤버처럼 다뤄진다. 주로 외부 클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다. |
지역 클래스 (local class) |
외부 클래스의 메서드나 초기화블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다. |
익명 클래스 (anonymous class) |
클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용) |
내부 클래스의 종류는 변수의 선언 위치에 따른 종류와 같다.
내부 클래스의 선언
class Outer{
class InstanceInner { } //인스턴스클래스
static class StaticInner { } //스태틱클래스
void method1(){
class LocalInner{ } //지역클래스
}
}
각 내부 클래스의 선언 위치에 따라 같은 선언 위치의 변수와 동일한 유효 범위(scope)와 접근성(accessibility)을 갖는다.
내부 클래스의 제어자와 접근성
class Outer{
//내부클래스에 제어자를 붙일 수 있다.
private class InstanceInner { }
protected static class StaticInner { }
void method1(){
class LocalInner{ }
}
}
내부 클래스는 외부 클래스의 멤버와 같이 간주되고, 인스턴스 멤버와 static 멤버 간의 규칙이 내부 클래스에도 똑같이 적용된다. 그리고 내부 클래스도 클래스이기 때문에 abstract 나 final 과 같은 제어자를 사용할 수 있을 뿐만 아니라 멤버 변수들처럼 private , protected 와 접근제어자도 사용 가능하다.
내부 클래스중에서 스태틱 클래스(static class)만 static 멤버를 가질 수 있다. 드문 경우지만 내부 클래스에 static 변수를 선언해야 한다면 스태틱 클래스로 선언해야 한다. 다만 final 과 static 이 동시에 붙은 변수는 상수(constant)이므로 모든 내부 클래스에서 정의가 가능하다.
package test;
class test{
class InstanceInner {} //내부클래스(인스턴스 클래스)
static class StaticInner {} //내부클래스(스태틱 클래스)
//인스턴스 멤버 간에는 서로 직접접근 가능
InstanceInner iv = new InstanceInner();
//static 멤버들 간에도 서로 직접접근이 가능
static StaticInner cv = new StaticInner();
static void staticMethod() {
//static멤버는 인스턴스멤버에 직접 접근할 수 X
//InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
//접근하려면 아래와 같이 객체를 생성해야함
//인스턴스 클래스는 외부 클래스를 먼저 생성해야만 생성할 수 있다.
test outer = new test();
InstanceInner obj1 = outer.new InstanceInner();
}
void instanceMethod() {
//인스턴스 메서드에서는 인스턴스멤버와 static멤버 모두 접근가능
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
//메서드 내에 지역적으로 선언된 내부클래스는 외부에서 접근할 수 X
//LocalInner lv = new LocalInner();
}
void method() {
class LocalInner{}
LocalInner lv = new LocalInner();
}
}
인스턴스 클래스는 외부 클래스의 인스턴스 멤버를 객체 생성 없이 바로 사용할 수 있지만, 스태틱 클래스는 외부클래스의 인스턴스 멤버를 객체 생성 없이 사용할 수 없다. 또한 인스턴스 클래스는 스태틱 클래스의 멤버들을 객체 생성 없이 사용할 수 있지만, 스태틱 클래스에서는 인스턴스 클래스의 멤버들을 객체 생성 없이 사용할 수 없다.
package test;
class test{
private int outerIv = 0;
static int outerCv = 0;
class InstanceInner{
int iiv = outerIv; //내부클래스에서 외부클래스의 private멤버도 접근할 수 있다.
int iiv2 = outerCv;
}
static class StaticInner{
//스태틱 클래스는 외부클래스의 인스턴스멤버에 접근할 수 X
//int siv = outerIv;
static int scv = outerCv;
}
void method() {
int lv = 0;
final int LV = 0; //JDK1.8부터 final생략가능
class LocalInner{
int liv = outerIv;
int liv2 = outerCv;
//외부 클래스의 지역변수는 final이 붙은 변수(상수)만 접근가능하다.
//int liv3 = lv; //에러(jdk1.8부터는 에러 아님)
int liv4 = LV;
}
}
}
- 인스턴스 클래스( InstanceInner )는 외부 클래스( test )의 인스턴스 멤버이기 때문에 인스턴스 변수 outerlv 와 static 변수 outerCv 를 모두 사용할 수 있다. ( outerlv 의 접근제어자가 private 일지라도 사용 가능)
- 스태틱 클래스( StaticInner )는 외부 클래스( test )의 static 멤버기 때문에 외부 클래스의 인스턴스 멤버인 outerlv 와 InstanceInner 를 사용할 수 없고 static 멤버인 outerCv 만을 사용할 수 있다.
- 지역 클래스( LocalInner )는 외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있으며, 지역 클래스가 포함된 메서드에 정의된 지역변수도 final 이 붙은 지역변수면 접근 가능하다(메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문)
- JDK1.8부터 지역 클래스에서 접근하는 지역 변수 앞에 final 을 생략할 수 있다. 컴파일러가 자동으로 붙여주는 것뿐이라 해당 변수의 값이 바뀌는 문장이 있으면 컴파일 에러가 발생한다.
class Outer{
void method1(){
class LocalInner {}
}
void method2(){
class LocalInner {}
}
}
내부 클래스가 컴파일되면 클래스 파일명이 외부 클래스명$내부 클래스명.class 형식으로 된다. 다만 서로 다른 메서드 내에서는 같은 이름의 지역변수를 사용하는 것이 가능한 것처럼, 지역 내부 클래스는 다른 메서드에 같은 이름의 내부 클래스가 존재할 수 있기 때문에 내부 클래스명 앞에 숫자가 붙는다.
(위의 코드를 컴파일하면 Outer.class , Outer$1LocalInner.class , Outer$2LocalInner.class 인 3개의 클래스 파일이 생성됨)
package test;
class Outer{
int value = 10; //Outer.this.value
class Inner{
int value = 20; //this.value
void method() {
int value = 30; //value
System.out.println("value : " + value);
System.out.println("this.value : " + this.value);
System.out.println("Outer.this.value : " + Outer.this.value);
}
}
}
class test{
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.method();
}
}
내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 때 변수 앞에 this 또는 외부 클래스명.this 를 붙여서 구별할 수 있다.
익명 클래스(Anonymous class)
new 부모클래스 이름(){
//멤버선언
}
//다른방법
new 구현인터페이스이름(){
//멤버선언
}
익명 클래스는 클래스의 선언과 객체의 생성을 동시에 하기 때문에 단 한 번만 사용될 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다. 이름이 없기 때문에 생성자도 가질 수 없으며, 부모 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.
package test;
class test{
Object iv = new Object() { void method(){ } }; //익명클래스
static Object cv = new Object() { void method(){ }}; //익명클래스
void myMethod(){
Object lv = new Object() { void method(){ } }; //익명클래스
}
}
익명 클래스는 이름이 없기 때문에 외부 클래스명$숫자.class 의 형식으로 클래스 파일명이 결정된다. 그래서 위의 코드를 컴파일하면(편의상 뺐는데 실행하고 싶으면 main 을 넣어야 함) test.class 외에 test$1.class , test$2.class , test$3.class 라는 3개의 클래스 파일이 생성된다.
'Back end > Java' 카테고리의 다른 글
[Java] java.lang 패키지 - Object클래스 (0) | 2019.07.12 |
---|---|
[Java] 예외처리(Exception Handling) (0) | 2019.07.11 |
[Java] 추상클래스(Abstract Class)와 인터페이스(Interface) (0) | 2019.07.09 |
[Java] 다형성(Polymorphism) (0) | 2019.07.08 |
[Java] 제어자(modifier) (0) | 2019.07.05 |