Java中的静态匿名类肯定是错误的吗?

时间:2009-08-07 08:56:46

标签: java

我在其他地方读过静态匿名类没有意义 - 所有匿名类都应该绑定到封闭类型的实例。但编译器允许你这样做。这是一个例子:

class Test {

    /*
     * What's the difference at between
     * Test.likeThis and Test.likeThat?        
     */

    // This is obviously okay:
    private static final class LikeThat {
        @Override
        public String toString() { return "hello!"; }       
    }
    public static Object likeThat = new LikeThat();

    // What about this - is it really any different? 
    public static Object likeThis = new Object() {
        @Override
        public String toString() { return "hello!"; }
    };
}

这里发生了什么?

9 个答案:

答案 0 :(得分:7)

我认为静态匿名类没什么问题

答案 1 :(得分:7)

来自the Java Language Specification, section 8.1.3

  

内部类 I 的实例,其声明发生在静态上下文中没有词法封闭的实例。但是,如果 I 立即在静态方法或静态初始化程序中声明,那么 I 确实有一个封闭块,这是词法最内层的块语句附上 I 的声明。

您的匿名类(likeThis是一个实例)发生在静态上下文中,因此它不依赖于封闭的实例。但是,似乎它可以引用其封闭块的最终变量(参见8.1.3节的其余部分,它们给出了一个例子)。

顺便说一句,你的措辞有点欺骗性,你实际上指的是一个匿名类的静态实例(它是静态的实例,而不是类)。

答案 2 :(得分:5)

就像任何语言中的任何语言一样,你应该只考虑为什么你正在做的事情。如果您有很多这些实例,那么我会质疑设计决策,但这并不一定意味着它应该从不遵循。

当然,始终考虑课程的可测试性以及是否可以在需要时提供测试双重

答案 3 :(得分:1)

我认为他们没有任何意义。如果您不需要引用封闭对象,那么最好将其保持静态。之后它可以轻松地在单独的课堂上进化。

广泛的枚举习惯用法(Java 5之前的版本)使用与枚举类的匿名静态继承者类似的方法。可能现在,对于这种情况,现在最好坚持使用Java 5 enum

如果您能够为匿名静态类找到足够的实际应用程序 - 为什么不使用它们呢?

答案 4 :(得分:1)

我一直这样做。它对于实用程序接口的特殊情况实现尤其方便,例如:

/** A holder for {@link Thing}s. */
public interface ThingsHolder {

    /** A {@link ThingsHolder} with nothing in it. */
    public static final ThingsHolder EMPTY_HOLDER = new ThingsHolder() {
        @Override
        public Iterable<Thing> getThings() {
            return Collections.emptySet();
        }
    };

    /** Provides some things. */
    Iterable<Thing> getThings();
}

您可以创建一个名为EmptyHolder的私有静态内部类,并且在某些情况下可能会使代码更具可读性,但您没有理由 来执行此操作。

答案 5 :(得分:1)

根据引用JLS的this answer,匿名类从不 static,但是当在“静态上下文”中创建时,它们没有“封闭实例”。 / p>

那就是说,

  • 如果您尝试引用Test.this非静态变量this无法从静态上下文引用),它们在编译时会出现相同的错误。
  • 在运行时,Class对象(除了名称)之间唯一明显的区别是Test$1是“匿名类”而Test$LikeThat是“成员类”。他们俩都有一个封闭的班级;它们都没有封闭的构造函数或方法。 (我只检查了看起来很可能的方法;可能还有其他差异。)
    • 编辑:根据getModifiers(),测试$ 1为staticTest$LikeThatstatic final!根据语言规范,Test$1实际应为final。嗯...
  • 根据javap -c -verbose -s -private -l

    • Test$1指定“EnclosingMethod”(可能是Test的静态初始值设定项?)
    • Test$LikeThat在“InnerClass”(#12; //class Test$1)和一个好奇的构造函数Test$LikeThat(Test$1)下有一个额外的条目。这似乎发生,因为LikeThatprivate,它构成了构造函数private,因此编译器生成一个“trampoline”以允许从Test调用它。

如果删除private,除了EnclosingMethod条目外,它们似乎编译成大致相同的东西。

Test$1没有在非静态上下文中定义的字段final Test this$0;

答案 6 :(得分:0)

对我来说似乎完全合法。由于匿名类是static,它不会引用任何封闭类,但不应该有任何恶意后果。

嗯,除了是一个隐藏的单身对象,这是非常邪恶的。

答案 7 :(得分:0)

当然他们不是。我总是使用静态嵌套类,除非我需要与封闭对象的隐式关联。

在java术语中嵌套类:=在另一个类(或接口)中声明的类。内部类是那些嵌套类,它们具有来自封闭类的关联实例。 (非静态成员类,本地类,匿名类)。

隐式关联有时可以防止垃圾收集。

答案 8 :(得分:-1)

这些可以非常方便,因为有可能做出循环引用:

class A
{ 
    public static final A _1 = new A() {
        public A foo()
        {
            return _2;
        }
    };

    public static final A _2 = new A() {
        public A foo()
        {
            return _1;
        }
    };
}

如果不使用匿名类,创建几个持有彼此引用的对象可能会非常尴尬。