为了添加实例初始化块而创建的匿名类的意外后果

时间:2009-03-22 21:31:37

标签: java anonymous-class

这是一个关于Java代码的问题,例如:

List<String> list = new ArrayList<String>() {{add("hello"); add("goodbye");}}

程序员为了在实例初始化块中推迟而匿名扩展了ArrayList。

问题是:如果程序员的唯一目的只是为了达到以下目的:

List<String> list = new ArrayList<String>();
list.add("hello");
list.add("goodbye");    

然后第一种方式做出的意外后果是什么?

4 个答案:

答案 0 :(得分:15)

执行这种代码(在一般情况下)的危险在于您可能会破坏equals()方法。那是因为equals()有两个通用模板:

public boolean equals(Object ob) {
  if (!(ob instanceof MyClass)) return false;
  ...
}

public boolean equals(Object ob) {
  if (ob.getClass() != getClass()) return false;
  ...
}

第一个仍然适用于您正在谈论的匿名子类,但第二个不会。事实上,第二个被认为是最佳实践,因为instanceof不一定是可交换的(意思是a.equals(b)可能不等于b.equals(a))。

特别是在这种情况下,ArrayList使用AbstractList.equals()方法只检查另一个对象是instanceof接口List,所以你很好。< / p>

但是要注意这一点。

我建议的做法略有不同:

List<String> list = new ArrayList<String>(
    Arrays.asList("hello", "goodbye")
);

当然这更加冗长,但你不太可能以这种方式遇到麻烦,因为结果类是“纯粹的”ArrayList

答案 1 :(得分:5)

我认为这里的一大问题是你正在创建周围类的内部类。您创建的列表将具有对外部类的隐式 this 引用。

这通常不是问题。但是,如果你序列化这个对象(我特别考虑使用XStream,因为我自己遇到过这个),那么序列化的表单将包含序列化的外部类。这根本不是你通常所期望的,可能导致特殊的行为!

我经常使用上面的初始化模式。只要您了解内部类机制,那么它就不是问题。 BTW。我不认为平等问题超出了一般推导的平等实现的问题。

答案 2 :(得分:2)

对代码性能和/或内存的影响可以忽略不计(甚至可以测量)。

真正的打击是,你让人们停下来,即使是一个节拍,也要想“这个人在做什么?”

如果我在阅读代码时必须这样做1000次,那就是性能问题。

代码应易于阅读 - 只要满足所有性能,完整性和标准要求。

您很可能会成为维护代码的人。对未来的自我保持友好,并使代码尽可能易于阅读。如果你打算做一些像这样的花哨的schmancy东西,有充分的理由并在代码中记录它。如果唯一的原因是作为程序员炫耀你的排骨,那么你在程序员的实际工作中就失败了:让困难变得容易。

答案 3 :(得分:0)

第一种方法对性能也不利。包含大量匿名类的内存混乱并不好。它在启动时也会变慢。