캡슐화 강화: 중첩 클래스를 사용하면 외부 클래스의 내부에서만 사용되는 클래스를 외부로부터 숨길 수 있습니다. 이로써 구현의 세부 사항을 캡슐화하고 외부에서의 접근을 제한할 수 있습니다.
가독성 향상: 관련된 클래스를 함께 그룹화하면 코드의 가독성이 향상됩니다. 외부 클래스와 관련이 깊은 클래스들이 함께 정의되어 있으면, 코드를 이해하고 유지보수하는 데 도움이 됩니다.
네임스페이스 관리: 중첩 클래스를 사용하면 클래스의 이름 충돌을 방지하고 명확한 네임스페이스를 유지할 수 있습니다. 중첩 클래스의 이름이 외부 클래스와 관련이 있으면, 그 관계가 명확해집니다.
코드의 논리 구조 강조: 중첩 클래스를 사용하면 클래스 간의 논리적인 관계를 코드 구조에 반영할 수 있습니다. 특히 특정 클래스가 다른 클래스와 강하게 결합되어 있을 때, 중첩 클래스로 표현하면 더 명확하게 표현할 수 있습니다.
인스턴스 멤버 클래스(Instance Member Class)는 다른 클래스의 멤버로 선언되어, 해당 클래스의 인스턴스를 생성할 때만 사용할 수 있는 클래스를 의미합니다. 이 클래스는 주로 외부 클래스의 인스턴스와 관련이 깊고, 해당 인스턴스의 속성이나 메서드에 접근해야 할 때 유용하게 사용됩니다.
일반적으로 인스턴스 멤버 클래스는 외부 클래스 내부에서만 사용되기 때문에 private 접근 제한을 갖는 것이 일반적입니다. 이렇게 함으로써 외부에서 직접적으로 접근할 수 없고, 외부 클래스의 메서드나 속성을 통해서만 사용할 수 있게 됩니다. 이는 캡슐화를 강화하고 외부에서의 클래스의 내부 구현 세부사항을 감추는 데 도움이 됩니다.
예시로 보면:
public class OuterClass {
private int outerField;
// 인스턴스 멤버 클래스
private class InnerClass {
private int innerField;
public InnerClass(int innerField) {
this.innerField = innerField;
}
public void doSomething() {
// 외부 클래스의 인스턴스 변수에 접근 가능
System.out.println("Outer field: " + outerField);
// 내부 클래스의 인스턴스 변수에 접근 가능
System.out.println("Inner field: " + innerField);
}
}
// 외부 클래스의 메서드에서 내부 클래스 사용 예시
public void useInnerClass() {
InnerClass innerInstance = new InnerClass(42);
innerInstance.doSomething();
}
}
위의 예제에서 InnerClass
는 OuterClass
의 인스턴스 멤버로 선언되어 있고, private
로 접근 제한되어 있습니다. 그리고 useInnerClass
메서드에서 외부에서 내부 클래스의 인스턴스를 생성하고 활용하고 있습니다.
정적 멤버 클래스(Static Member Class)는 static
키워드와 함께 클래스의 멤버로 선언되어, 해당 클래스의 인스턴스와 독립적으로 사용할 수 있는 클래스를 나타냅니다. 이 클래스는 외부 클래스의 인스턴스에 종속되지 않으며, 정적으로 선언된 클래스이므로 외부 클래스의 static 멤버에 접근할 수 있습니다.
아래는 정적 멤버 클래스의 간단한 예제입니다:
public class OuterClass {
private static int outerStaticField;
// 정적 멤버 클래스
public static class StaticInnerClass {
private int innerField;
public StaticInnerClass(int innerField) {
this.innerField = innerField;
}
public void doSomething() {
// 외부 클래스의 정적 변수에 접근 가능
System.out.println("Outer static field: " + outerStaticField);
// 내부 클래스의 인스턴스 변수에 접근 가능
System.out.println("Inner field: " + innerField);
}
}
// 외부 클래스의 메서드에서 정적 내부 클래스 사용 예시
public static void useStaticInnerClass() {
StaticInnerClass innerInstance = new StaticInnerClass(42);
innerInstance.doSomething();
}
}
로컬 클래스(Local Class)는 주로 생성자 또는 메서드 내부에서 선언되어 사용되는 클래스를 의미합니다. 이 클래스는 특정 메서드나 생성자 내에서만 유효하며, 해당 메서드나 생성자의 지역 변수에 접근할 수 있습니다.
로컬 클래스는 메서드 내에 선언되므로 해당 메서드 내에서만 인스턴스를 생성하고 사용할 수 있습니다. 이로써 클래스의 유효 범위가 제한되어 메서드 외부에서는 직접적인 접근이 불가능하며, 해당 메서드의 기능을 보조하거나 특정 구현을 위한 클래스를 제한된 범위에서 사용할 때 유용합니다.
예를 들어서:
public class OuterClass {
public void someMethod() {
// 로컬 클래스
class LocalInnerClass {
private int innerField;
public LocalInnerClass(int innerField) {
this.innerField = innerField;
}
public void doSomething() {
System.out.println("Inner field: " + innerField);
}
}
// 메서드 내에서 로컬 클래스 사용 예시
LocalInnerClass localInstance = new LocalInnerClass(42);
localInstance.doSomething();
}
}
중첩 클래스(Inner Class)에서 바깥 클래스(Outer Class)의 객체를 얻기 위해서는 바깥 클래스의 이름에 this
를 붙여주면 됩니다. 이는 중첩 클래스 내부에서 바깥 클래스의 인스턴스에 접근할 때 사용됩니다.
예를 들어, 내부 클래스에서 바깥 클래스의 인스턴스 변수에 접근하려면 다음과 같이 사용할 수 있습니다:
public class OuterClass {
private int outerField = 10;
// 내부 클래스
public class InnerClass {
private int innerField = 20;
public void accessOuterField() {
// 바깥 클래스의 객체를 얻어서 바깥 클래스의 인스턴스 변수에 접근
int result = OuterClass.this.outerField;
System.out.println("Outer field: " + result);
}
public void accessInnerField() {
System.out.println("Inner field: " + innerField);
}
}
public static void main(String[] args) {
OuterClass outerInstance = new OuterClass();
InnerClass innerInstance = outerInstance.new InnerClass();
innerInstance.accessOuterField(); // 바깥 클래스의 인스턴스 변수에 접근
innerInstance.accessInnerField(); // 내부 클래스의 인스턴스 변수에 접근
}
}
중첩 인터페이스(Nested Interface)는 클래스 내부에서 선언된 인터페이스를 나타냅니다. 이러한 인터페이스는 주로 특정 클래스와 강하게 결합되어 있으며, 해당 클래스의 기능을 보완하거나 특정한 용도로 사용될 때 유용합니다.
중첩 인터페이스는 외부 클래스의 멤버로 선언되므로, 접근 제어자를 사용하여 외부에서의 접근을 제한할 수 있습니다. 이는 캡슐화의 개념을 강화하고, 해당 인터페이스가 특정 클래스와 밀접한 관련이 있다는 것을 나타낼 수 있습니다.
예를 들어:
public class OuterClass {
// 중첩 인터페이스
public interface NestedInterface {
void someMethod();
}
// 외부 클래스의 멤버 메서드
public void useNestedInterface(NestedInterface nestedInstance) {
nestedInstance.someMethod();
}
}
익명 객체(Anonymous Object)는 이름이 없는 객체를 말하며, 익명 자식 객체(Anonymous Child Object)는 부모 클래스를 상속받아 생성된 익명 객체를 나타냅니다. 이러한 익명 객체는 주로 한 번만 사용되어 다른 객체와의 간단한 상호작용이 필요한 경우에 사용됩니다.
익명 객체는 주로 인터페이스나 추상 클래스의 인스턴스를 생성할 때 유용하게 사용됩니다. 익명 객체를 사용하면 코드를 간결하게 작성할 수 있고, 필요한 로직을 직접 정의하여 인스턴스를 생성할 수 있습니다.
예를 들어, 익명 자식 객체를 생성하는 경우:
// 부모 클래스 또는 인터페이스 정의
interface MyInterface {
void someMethod();
}
public class Main {
public static void main(String[] args) {
// 익명 자식 객체 생성
MyInterface myObject = new MyInterface() {
@Override
public void someMethod() {
System.out.println("Anonymous child object's implementation of someMethod");
}
};
// 익명 자식 객체의 메서드 호출
myObject.someMethod();
}
}
익명 구현 객체(Anonymous Implementation Object)는 주로 인터페이스를 구현하여 생성되는 객체를 말합니다. 이는 주로 인터페이스의 메서드를 구체적으로 정의하고 해당 인터페이스를 구현한 객체를 생성할 때 사용됩니다.
익명 구현 객체는 특정 클래스의 새로운 서브클래스를 생성하지 않고도 간단한 인터페이스 구현을 제공할 수 있습니다. 주로 한 번만 사용되어야 하는 간단한 구현체를 생성할 때 효과적입니다.
예를 들어:
// 부모 인터페이스 정의
interface MyInterface {
void someMethod();
}
public class Main {
public static void main(String[] args) {
// 익명 구현 객체 생성
MyInterface myObject = new MyInterface() {
@Override
public void someMethod() {
System.out.println("Anonymous implementation of someMethod");
}
};
// 익명 구현 객체의 메서드 호출
myObject.someMethod();
}
}