내부 클래스
내부 클래스는 클래스 안에 만들어진 또 다른 클래스로 중첩 클래스라고도 한다. 클래스에 다른 클래스를 선언하는 이유는 두 개의 클래스가 서로 긴밀한 관계를 맺고 있기 때문이다. 내부 클래스는 다음과 같은 장점이 있다.
- 두 클래스 멤버들 간에 손쉽게 접근할수 있다.
- 불필요한 클래스를 감춰서 코드의 복잡성을 줄일 수 있다.
public class OuterClass { // 외부 클래스
...
class InnerClass { // 내부 클래스
...
}
}
내부 클래스의 종류
내부 클래스는 클래스 안에서 선언된 위치에 따라 인스턴스 클래스, 정적 클래스, 지역 클래스, 익명 클래스로 구분된다.
| 메서드 | 설명 |
| 인스턴스 클래스 | 외부 클래스의 멤버 변수와 같은 위치에 선언 주로 외부 클래스의 멤버 변수와 관련된 작업에 사용될 목적으로 선언 |
| 정적 클래스 | 외부 클래스의 클래스 변수와 같이 static 키워드 부여 |
| 지역 클래스 | 외부 클래스의 메서드 내부에서 선언하여 사용 메서드 영역에서 선언되기 때문에 메서드 내부에서만 사용 가능 |
인스턴스 클래스는 외부 클래스 내부에서 생성하고, 선언되어 사용하는 클래스를 의미한다. 인스턴스 변수와 같은 위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언된다.
public class Outer {
pirvate String name; // 인스턴스 멤버
...
public class Inner { // 인스턴스 클래스
private String name;
...
}
}
인스턴스 클래스는 기본적인 내부 클래스이다. 외부 클래스 안에 생성되기 때문에, 클래스를 사용하려면 외부 클래스 객체가 생성된 상태에서 객체 생성을 할 수 있다.
Outer outer = new Outer(); // 외부 클래스 객체 생성
Outer.Ineer in = outer.net Inner(); // 외부 클래스를 이용해 내부 클래스 객체 생성
클래스 안에 정적 변수를 선언할 수 있는 것처럼 클래스도 정적 클래스를 만들 수 있다. 인스턴스 변수와 마찬가지로 static 키워드를 사용해 클래스를 선언한 후 정적 내부 클래스를 생성한다. 주로 외부 클래스의 static 메서드에서 사용될 목적으로 선언된다.
public class Outer {
private String name; // 인스턴스 멤버
public static class Ineer { // 정적 내부 클래스
private String name;
...
}
}
클래스 앞에 static 키워드를 사용해 정적 내부 클래스를 선언했다. 정적 변수와 마찬가지로 클래스에 속하지만 독립적으로 존재한다. 또한 외부 클래스의 존재와 상관없이 정적 변수를 사용할 수 있다. 그러나 외부 클래스의 인스턴스 변수 또는 메서드를 정적 내부 클래스 안에서는 사용할 수 없다.
지역 클래스는 외부 클래스의 메서드 내에서 선언되어 사용하는 클래스이다. 메서드 내에서 선언되기 때문에 해당 클래스는 메서드 내에서만 사용할 수 있다. 또한 메서드의 실행이 끝나면 해당 클래스도 사용이 종료된다.
public class LocalClass {
...
public void print(){
...
class A { // 지역 클래스 선언
...
}
A a = new A(); // 메서드 내에서 사용
}
}
내부 클래스의 접근 제한
내부 클래스도 클래스이기 때문에 접근 제한자를 붙여서 사용할 수 있다. 우리가 앞에서 배웠던 접근 제한자들을 사용해 외부에서의 접근을 제한할 수 있다.
지역 클래스는 메서드 내에서 선언되어 사용한다. 보통 메서드가 종료되면 클래스도 함께 종료되지만 메서드와 실행되는 위치가 다르기 때문에 종료되지 않고 남아 있을 수도 있다. 그래서 지역 클래스에서 메서드 내의 변수를 사용할 때는 변수를 복사해 사용한다. 이러한 이유로 지역 클래스에서 메서드의 변수를 사용할 때 해당 변수가 변경되면 오류가 발생한다.
익명 클래스
다른 내부 클래스와는 달리 이름이 없는 클래스를 의미한다. 익명 클래스는 클래스의 선언과 객체의 생성을 동시에 하므로 단 한 버만 사용할 수 있으며 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다. 따라서, 생성자를 선언할 수도 없으며, 둘 이상의 인터페이스를 구현할 수도 없다. 오직 단 하나의 클래스를 상속받거나 단 하나의 인터페이스를 구현해야만 한다.
[부모 클래스 생성]
public class Person {
pulic void mySelf(){
System.out.println("나는 인간입니다.");
}
}
[자식 클래스 생성]
public class Student extends Person {
@Override
public void myself(){
System.out.println("I'm child");
}
}
위 코드처럼 Person 클래스를 확장하기 위해서 자식 클래스를 만들어 사용한다. 그런데 만약 Person을 상속받아 처리해야 하는 클래스가 또 필요하다면 매번 하위 클래스를 만들어야 할까? 하위 클래스를 한 번만 사용하고 말 것이라면 굳이 상속할 필요가 없다. 이때, 유용하게 사용할 수 있는 것이 바로 익명 클래스이다.
Person p = new Person();
익명 클래스를 선언하고 객체를 생성하는 방법은 다음과 같다.
Person p = new Person(){
@Override
void method(){
}
...
};
클래스 생성자 뒤에 코드블럭{...}이 추가되고, 해당 클래스가 가진 메서드들을 override 하여 구현하는 방식이다. 해당 클래스 자체를 재정의하여 구현한다. 구현된 문법 마지막에는 세미콜론(;)을 붙인다. 익명 클래스는 보통 인터페이스의 기능을 구현할 때 사용한다. 인터페이스를 상속하여 하위 클래스를 통해 구현하는 것이 아니라 인터페이스를 익명 클래스로 선언해 기능을 직접 구현한다
'BOOK' 카테고리의 다른 글
| [JAVA] MENTOR JAVA SECTION 15 (1) | 2025.01.22 |
|---|---|
| [JAVA] MENTOR JAVA SECTION 14 (1) | 2025.01.21 |
| [JAVA] MENTOR JAVA SECTION 12 (2) | 2025.01.19 |
| [JAVA] MENTOR JAVA SECTION 11 (2) | 2025.01.18 |
| [JAVA] MENTOR JAVA SECTION 10 (2) | 2025.01.17 |