내부 클래스
- 클래스 내에 선언된 클래스이다.
- 내부, 외부 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다.
- 외부에 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다(캡슐화)
/* 서로 독립적인 A, B 클래스 */
class A {
...
}
class B {
...
}
/* B를 A의 내부클래스로, A를 B를 감싸고 있는 외부클래스로 변경 */
class A { // 외부 클래스
...
class B { // 내부
...
}
}
내부 클래스의 종류와 특징
- 내부클래스는 마치 변수를 선언하는 것과 같은 위치에 선언할 수 있으며, 선언 위치에 따라 종류가 나뉘어진다.
- 내부 클래스의 유효범위와 성질이 같은 위치에 선언된 변수와 유사하다. (ex. 인스턴스 클래스 - 인스턴스 변수)
내부 클래스 | 특징 |
인스턴스 클래스 (instance class) | 외부 클래스의 멤버변수 선언 위치에 선언. 인스턴스멤버처럼 사용된다. 주로 외부클래스의 인스턴스멤버들과 관련된 작업에 사용됨. |
스테틱 클래스 (static class) | 외부 클래스의 멤버변수 선언 위치에 선언. static 멤버처럼 사용된다. 주로 외부클래스의 static멤버, 특히 static메서드에서 사용될 목적으로 선언된다. |
지역 클래스 (local class) | 외부 클래스의 메서드나 초기화 블럭안에 선언. 선언된 영역 내부에서만 사용됨. |
익명 클래스 (anonymous class) | 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스(일회용) |
내부 클래스의 선언, 제어자와 접근성
- 변수가 선언된 위치에 따라 인스턴스 변수, 클래스변수(static변수), 지역변수로 나뉘듯이 내부 클래스도 이와 마찬가지로 선언된 위치에 따라 나뉜다.
- 각 내부 클래스 선언위치에 따라 같은 선언위치의 변수와 동일한 유효범위와 접근성을 갖는다.
- 외부 클래스에 선언된 내부클래스는 외부 클래스의 멤버와 같이 간주되고, 인스턴스멤버와 static멤버 간의 규칙이 내부클래스에도 동일하게 적용된다.
- 내부 클래스도 abstract, final 등 제어자를 사용할 수 있을 뿐만 아니라, 멤버변수들처럼 private, protected과 같은 접근제어자도 사용 가능하다.
/* 위치별로 선언한 변수들 */
class Outer {
private int iv = 0; // 인스턴스변수
protected static int cv = 0; // static변수
void myMethod() {
int lv = 0; // 지역변수
}
}
/* 위치별로 선언한 내부 클래스들 */
class Outer {
private class InstanceInner {} // 인스턴스 클래스
protected static class StaticInner {} // static 클래스
void myMethod() {
class LocalInner {} // 지역 클래스
}
}
※ 내부 클래스 중에서 Static클래스만 Static멤버를 가질 수 있다. 다만 final과 static이 동시에 붙은 변수는 상수이므로 내부클래스의 종류에 상관없이 모든 내부클래스에서 정의가 가능하다.
* 내부 클래스에서 외부 클래스의 변수들에 대한 접근성을 보여주는 예제
class InnerEx {
private int outerIv = 0; // 외부 인스턴스 멤버 선언
static int outerCv = 0; // 외부 static 멤버 선언
class InstanceInner { // 인스턴스클래스 선언
int iiv = outerIv; // 외부 클래스의 private멤버도 접근가능하다.
int iiv2 = outerCv;
}
static class StaticInner { // Static클래스 선언
// int siv = outerIv; -- static 클래스는 외부 클래스의 인스턴스멤버에 접근할 수 없다.
static int scv = outerCv;
}
// 인스턴스멤버 간에는 서로 직접 접근이 가능하다.
InstanceInner iv = new InstanceInner();
// static 멤버 간에는 서로 접근이 가능하다.
static StaticInner cv = new StaticInner();
static void staticMethod() {
// InstanceInner obj1 = new InstanceInner(); -- static멤버는 인스턴스멤버에 직접 접근할 수 없다.
StaticInner obj2 = new StaticInner();
// 객체를 만든후에는 인스턴스변수에 접근가능.
InnerEx outer = new InnerEx();
InstanceInner obj1 = outer.new InstanceInner();
}
void instanceMethod() {
// 인스턴스메소드에서는 인스턴스멤버와 static멤버 모두 접근 가능하다.
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// Localinner lvc = new Localinner(); -- 메서드 내에서 지역적으로 선언된 내부 클래슨는 외부에서 접근 할 수 없다.
}
void myMethod() {
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; // 상수 접근 가능.
}
LocalInner lvc = new LocalInner(); // 선언 뒤 생성은 외부에서 접근 가능
}
}
class Main {
public static void main(String[] args) {
// 인스턴스 클래스의 인스턴스를 생성하려면 외부클래스의 인스턴스를 먼저 생성해야 한다.
InnerEx oc = new InnerEx();
InnerEx.InstanceInner ii = oc.new InstanceInner();
// 스태틱 내부 클래스의 인스턴스는 외부 클래스를 먼저 생성하지 않아도 된다.
InnerEx.StaticInner si = new InnerEx.StaticInner();
}
}
- 인스턴스 클래스는 외부클래스의 인스턴스멤버를 객체생성 없이 바로 사용가능하지만, 스테틱클래스는 외부 클래스의 인스턴스 멤버를 객체생성 없이 사용할 수 없다.
- 인스턴스클래스는 스태틱클래스의 멤버들을 객체생성없이 사용할 수 있지만, 스태틱 클래스에서는 인스턴스클래스의 멤버들르 객체생성없이 사용할 수 없다.
- 인스턴스클래스는 외부 클래스의 인스턴스멤버이기 때문에 인스턴스변수를 모두 사용할 수 있다. 접근제어자가 private이어도 상관없다.
- 스태틱클래스는 외부 클래스의 static멤버만 사용할 수 있다.
- 지역클래스는 외부 클래스의 인스턴스멤버와 static멤버를 모두 사용할 수 있으며, 지역클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다.
- 단, final이 붙은 지역변수만 접근 가능하는데 이유는 메서드가 수행을 마쳐서 지역변수가 소멸된 시점에도, 지역클래스의 인스턴스가 소멸될 지역변수를 참조하려는 경우가 발생할 수 있기때문이다.(JDK1.8부터는 컴파일러가 자동으로 final을 붙이기때문에 생략해도 된다.)
- 내부클래스의 객체를 만들때, 인스턴스의 경우는 외부 클래스의 객체를 먼저 생성한 후에 가능하지만 스태틱 내부 클래스는 먼저 생성하지않아도 된다.
내부 클래스의 파일명
- 내부 클래스를 컴파일 했을 때 생성되는 파일명은 '외부 클래스명$내부 클래스명.class' 형식으로 되어 있다.
- 지역 내부 클래스는 다른 메서드에 같은 이름의 내부 클래스가 존재할 수 있기 때문에 내부클래스명 앞에 숫자가 붙는다.
class Outer {
int value = 10; // Outer.this.value
class Inner {
int value = 20; // this.value
}
void myMethod() {
class LocalInner {}
}
void myMethod2() {
class LocalInner {}
}
}
/* 컴파일 */
/*
Outer.class
Outer$Inner.class
Outer$1LocalInner.class
Outer$2LocalInner.class
*/
※ 내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 때 변수 앞에 'this' 또는 '외부 클래스명.this'를 붙여서 서로 구별할 수 있다.
익명 클래스
- 이름이 없고 클래스의 선언과 객체의 생성을 동시에 한다.
- 단 한번만 사용될 수 있으며 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.
- 이름이 없기 때문에 생성자도 가질 수 없다.
- 단 하나의 클래스를 상속받거나 단 하나의 인터페이스만을 구현할 수 있다.
- 익명 클래스는 '외부 클래스명$숫자.class'의 형식으로 클래스파일명이 결정된다.
/* 익명클래스 생성*/
new 조상클래스이름() {
// 멤버 선언
}
또는
new 구현인터페이스이름() {
// 멤버 선언
}
class AnonyEx {
Object iv = new Object(){ void method(){} }; // 익명 클래스
static Object cv = new Object(){void method(){} }; // 익명 클래스
void myMethod() {
Object lv = new Object(){ void method(){} } ; // 익명 클래스
}
}
728x90
반응형
'개발 공부 > Java & Spring' 카테고리의 다른 글
8. StringBuffer 클래스와 StringBuilder 클래스 (0) | 2022.12.06 |
---|---|
7. 예외처리(exception handling) (0) | 2022.11.12 |
5. 제어자(modifier) (0) | 2022.10.24 |
4. package와 import (0) | 2022.10.23 |
3. 오버로딩(overloading) (0) | 2022.09.28 |