(유효한 자바) 항목23. 태그가 지정된 클래스 대신 클래스 계층 구조를 사용하십시오.
중첩 클래스란 무엇입니까? 다른 클래스에 정의된 클래스말한다
중첩 클래스는 자신을 감싸는 외부 클래스에서만 사용해야 하며, 다른 용도가 있는 경우 최상위 클래스로 만들어야 합니다.
중첩 클래스 유형 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 로컬 클래스 네 가지가 있습니다.
정적 멤버 클래스를 제외하고 나머지 클래스는 내부 클래스입니다.
1⃣ 정적 멤버 클래스
: 정적 멤버 클래스는 다른 클래스에서 선언이 되다, 외부 클래스의 전용 멤버에 대한 액세스가능하다는 점을 제외하면 일반 수업과 같습니다.
예) 계산기가 지원하는 연산 타입을 정의하는 열거형 타입을 고려할 때 열거형 연산은 계산기 클래스의 public static 멤버 클래스여야 합니다. 그런 다음 계산기 클라이언트는 Calculator.Operation.PLUS 또는 Calculator.Operation.MINUS 형식으로 작업을 참조할 수 있습니다.
public class OuterClass
{
private static int number = 10;
// static 멤버 클래스
// static 필드에 접근 가능
// Outer class의 인스턴스를 필요로 하지 않는다. (static이라 outer class와 독립적)
static private class InnerClass {
void doSomething()
{
System.out.println("number = " + number);
}
}
public static void main(String() args)
{
InnerClass innerClass = new InnerClass();
innerClass.doSomething();
}
}
2⃣ 비정적 멤버 클래스
비정적 멤버 클래스의 인스턴스입니다. 외부 클래스의 인스턴스에 암시적으로 연결됨하다.
따라서 비정적 멤버 클래스의 인스턴스 메서드에서 정규화된 this를 사용하여 외부 인스턴스의 메서드를 호출하거나 외부 인스턴스의 참조를 가져올 수 있습니다. (제한적으로 이것은 classname.this 형식으로 외부 클래스 이름을 지정하는 사용을 나타냅니다.)
따라서 개념적으로 중첩된 클래스의 인스턴스가 외부 인스턴스와 독립적으로 존재할 수 있다면 정적 멤버 클래스로 만들어야 합니다.!!
(비정적 멤버 클래스는 외부 인스턴스 없이 만들 수 없기 때문에)
public class OuterClass
{
private int number = 10;
void printNumber()
{
InnerClass innerClass = new InnerClass();
}
// 비정적 멤버 클래스 (static이 없는 inner class)
// outer class의 인스턴스에 대한 참조가 암묵적으로 생긴다. -> 즉 outer class 없이는 inner class 사용 x
private class InnerClass {
void doSomething()
{
System.out.println("number = " + number);
OuterClass.this.printNumber(); // outer class의 멤버에 접근 가능
}
}
public static void main(String() args)
{
InnerClass innerClass = new OuterClass().new InnerClass();
innerClass.doSomething();
}
}
비정적 멤버 클래스의 인스턴스와 해당 인스턴스를 둘러싸는 인스턴스 간의 관계는 멤버 클래스가 인스턴스화되고 변경할 수 없을 때 설정됩니다.
이 관계는 일반적으로 외부 클래스의 인스턴스 메서드에서 비정적 멤버 클래스의 생성자가 호출될 때 자동으로 생성되지만 드물게 외부 인스턴스의 클래스 class.new MemberClass(args)를 직접 호출하여 수동으로 생성됩니다.
-> 이 관계 정보는 비정적 멤버 클래스의 인스턴스에서 생성됩니다. 디스크 공간을 차지하고 생성하는 데 시간이 오래 걸립니다.
public class MySet<E> extends AbstractSet<E>
{
@Override
public Iterator<E> iterator()
{
return new MyIterator();
}
@Override
public int size()
{
return 0;
}
private class MyIterator implements Iterator<E>
{
@Override
public boolean hasNext()
{
return false;
}
@Override
public E next()
{
return null;
}
}
}
어댑터를 정의할 때 비정적 멤버 클래스가 자주 사용됩니다.
한 클래스의 인스턴스를 다른 클래스의 인스턴스처럼 보이게 하는 방식으로 래핑하는 보기로 사용됩니다.
Set 및 List와 같은 컬렉션 인터페이스의 다른 구현은 종종 비정적 멤버 클래스를 사용하여 반복자를 구현합니다.
멤버 클래스에서 외부 인스턴스에 대한 액세스가 필요하지 않으면 무조건 static을 추가하여 정적 멤버 클래스로 만드십시오!!
static 을 생략하면 외부 인스턴스에 대한 외부 참조가 숨겨집니다. 이 참조를 저장하려면 시간과 메모리가 필요하며 더 나쁜 것은 가비지 수집이 외부 클래스의 인스턴스를 회수할 수 없는 경우 메모리 누수로 이어질 수 있다는 것입니다.
참조가 보이지 않기 때문에 문제의 원인을 찾기 어렵고 때로는 심각한 상황으로 이어집니다.
3⃣ 익명 클래스
: 외부 클래스의 구성원이 아님, 인스턴스는 선언 시 생성됩니다. 따라서 코드의 어느 위치에서나 생성할 수 있습니다.
익명 클래스는 비정적 컨텍스트에서 사용될 때만 외부 클래스의 인스턴스를 참조할 수 있습니다. 정적 컨텍스트에서도 상수 변수 이외의 정적 멤버를 가질 수 없습니다.
익명 클래스는 선언된 시점에서만 인스턴스화할 수 있으며 인스턴스 확인이나 클래스 이름이 필요한 작업을 수행할 수 없습니다.
Java에서는 람다가 지원되기 전에 익명 클래스를 사용하여 작은 함수 개체를 만들거나 즉시 개체를 처리했습니다.
익명 클래스의 또 다른 중요한 용도는 정적 팩터리 메서드를 만드는 것입니다.
public class IntArrays
{
static List<Integer> intArrayAsList(int() a)
{
Objects.requireNonNull(a);
return new AbstractList<>()
{
@Override
public Integer get(int index)
{
return a(index);
}
@Override
public Integer set(int index, Integer element)
{
int oldVal = a(index);
a(index) = element;
return oldVal;
}
@Override
public int size()
{
return a.length;
}
};
}
public static void main(String() args)
{
int() a = new int(10);
for (int i = 0; i < a.length; i++)
{
a(i) = i;
}
}
}
4⃣ 지역 수업
: 로컬 클래스는 4개의 중첩 클래스 중에서 가장 적게 사용됩니다.
지역 클래스는 지역 변수가 선언될 수 있는 거의 모든 곳에서 선언될 수 있으며 지역 변수와 동일한 범위를 가집니다.
public class MyClass
{
private int number = 10;
void doSomething()
{
// 멤버 클래스가 아닌 local class -> 거의 사용 x
class LocalClass {
private void printNumber()
{
System.out.println("number = " + number);
}
}
LocalClass localClass = new LocalClass();
localClass.printNumber();
}
public static void main(String() args)
{
MyClass myClass = new MyClass();
myClass.doSomething();
}
}
익명 클래스는 비정적 컨텍스트에서 사용될 때만 외부 인스턴스를 참조할 수 있고 정적 멤버를 가질 수 없으며 가독성을 위해 간결해야 합니다.
정리하다
정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스 및 로컬 클래스의 네 가지 유형의 중첩 클래스가 있으며 각각 용도가 다릅니다.
메서드 외부에서 사용해야 하고 메서드 내부에서 정의하기에는 너무 길다면 멤버 클래스로 만드세요.
멤버 클래스의 모든 인스턴스 외부 인스턴스를 참조하는 경우 비정적 멤버 클래스, 그렇지 않은 경우 정적해보자!!
중첩 클래스 메소드에서만 사용되고 인스턴스가 생성되는 지점이 하나뿐이고 해당 유형과 함께 사용하기에 적합한 클래스 또는 인터페이스가 이미 있는 경우 이를 익명 클래스 또는 하나의 로컬 클래스로 만드십시오.해보자!!
