[java] Java에서 익명의 내부 클래스를 정적으로 만들 수 있습니까?

Java에서 중첩 클래스는 둘 중 하나 일 수도 있고 static아닐 수도 있습니다 . 인 경우 static포함하는 인스턴스의 포인터에 대한 참조를 포함하지 않습니다 (더 이상 내부 클래스라고도 부르지 않고 중첩 클래스라고 함).

static참조가 필요하지 않을 때 중첩 클래스를 만드는 것을 잊으면 가비지 수집 또는 이스케이프 분석에 문제가 발생할 수 있습니다.

익명의 내부 클래스 static도 만들 수 있습니까? 아니면 컴파일러가이를 자동으로 파악합니까 (하위 클래스가 없기 때문에 가능함)?

예를 들어 익명의 비교기를 만들면 외부에 대한 참조가 거의 필요하지 않습니다.

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }



답변

아니, 당신은 할 수 없으며 컴파일러는 그것을 알아낼 수 없습니다. 이것이 FindBugs static가 암시 적 this참조를 사용하지 않는 경우 항상 익명 내부 클래스를 명명 된 중첩 클래스 로 변경하도록 제안하는 이유 입니다.

편집 : Tom Hawtin-tackline에 따르면 익명 클래스가 정적 컨텍스트 (예 : main메서드)에서 생성되는 경우 익명 클래스는 실제로 static. 그러나 JLS는 동의하지 않습니다 .

익명 클래스는 절대 없습니다 abstract(§8.1.1.1). 익명 클래스는 항상 내부 클래스 (§8.1.3)입니다. 절대 아닙니다 static(§8.1.1, §8.5.1). 익명 클래스는 항상 암시 적입니다 final(§8.1.1.2).

Roedy Green의 Java Glossary에 따르면 익명 클래스가 정적 컨텍스트에서 허용된다는 사실은 구현에 따라 다릅니다.

코드를 유지하는 사람들을 당황하게 만들고 싶다면 언어 사양이 익명 클래스가 결코라고 말하지 않더라도 init 코드 및 메서드 javac.exe내에서 익명 클래스를 허용한다는 것을 wags가 발견했습니다 . 물론 이러한 익명 클래스는 개체의 인스턴스 필드에 액세스 할 수 없습니다. 나는 이것을 권장하지 않습니다. 이 기능 은 언제든지 가져올 수 있습니다.staticstaticstatic

편집 2 : JLS는 실제로 §15.9.2 에서보다 명시 적으로 정적 컨텍스트를 다룹니다 .

하자 C는 인스턴스화하는 클래스, 그리고하자 내가 인스턴스가 생성되는 수. 경우 C는 내부 클래스 다음 직접 둘러싸 인스턴스를 가질 수있다. i 의 즉시 둘러싸는 인스턴스 (§8.1.3)는 다음과 같이 결정됩니다.

  • 경우 C는 다음 익명 클래스입니다 :
    • 클래스 인스턴스 생성식이 정적 컨텍스트 (§8.1.3)에서 발생하면 i 에는 즉시 둘러싸는 인스턴스가 없습니다.
    • 그렇지 않으면 i 의 즉시 둘러싸는 인스턴스는 입니다 this.

따라서 정적 컨텍스트의 익명 클래스는 static기술적으로 static클래스가 아니지만 둘러싸는 클래스에 대한 참조를 유지하지 않는다는 점에서 중첩 클래스 와 거의 동일합니다 .


답변

거의. 정적 메서드에서 생성 된 익명의 내부 클래스는 외부 this에 대한 소스가 없기 때문에 분명히 효과적으로 정적입니다.

정적 컨텍스트의 내부 클래스와 정적 중첩 클래스 간에는 몇 가지 기술적 차이점이 있습니다. 관심이 있으시면 JLS 3rd Ed.


답변

나는 여기의 명명법에 약간의 혼란이 있다고 생각합니다. 이것은 너무 어리 석고 혼란 스럽습니다.

무엇이라고 부르든 이러한 패턴 (및 가시성이 다른 몇 가지 변형)은 모두 가능하고 정상적인 합법적 인 Java입니다.

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

그것들은 언어 사양에서 제공됩니다 (정말로 신경 쓰이는 경우 정적 메서드 내부의 섹션 15.9.5.1 참조).

그러나이 인용문은 명백히 잘못되었습니다 .

javac.exe는 언어 사양에서 익명 클래스가 결코 정적이 아니라고 말하더라도 정적 초기화 코드 및 정적 메서드 내에서 익명 클래스를 허용합니다.

인용 된 저자가 static 키워드 와 static context를 혼동하고 있다고 생각합니다 . (당연히 JLS도이 점에서 약간 혼란 스럽습니다.)

솔직히, 위의 모든 패턴은 괜찮습니다 (당신이 “중첩”, “내부”, “익명”이라고 부르는 것 …). 실제로, Java의 다음 릴리스에서이 기능을 갑자기 제거하는 사람은 없습니다. 솔직히!


답변

내부 클래스는 정적 일 수 없습니다. 정적 중첩 클래스는 내부 클래스가 아닙니다. 여기에서 Java 튜토리얼에 대해 설명합니다 .


답변

익명의 내부 클래스는 절대 정적이 아니지만 (정적 메서드 또는 최종 정적 필드가 아닌 필드를 선언 할 수 없음) 정적 컨텍스트 (정적 메서드 또는 정적 필드)에서 정의 된 경우에는 불가능하다는 점에서 정적으로 작동합니다. (정적 컨텍스트의 다른 모든 것과 마찬가지로) 둘러싸는 클래스의 비 정적 (즉 인스턴스) 멤버에 액세스


답변

익명의 내부 클래스를 정적 ​​메서드 내에서 호출하여 정적으로 만드는 것에 유의하십시오.

이것은 실제로 참조를 제거하지 않습니다. 익명 클래스를 직렬화하고 바깥 쪽 클래스를 직렬화 가능하게 만들지 않음으로써이를 테스트 할 수 있습니다.


답변