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

发布于 2024-07-15 01:09:00 字数 375 浏览 8 评论 0原文

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

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

程序员匿名扩展 ArrayList 只是为了插入实例初始化块。

问题是:如果程序员的唯一意图仅仅是实现以下目标:

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

那么第一种方式会产生什么意想不到的后果?

This is a question about Java code such as:

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

where the programmer has extended ArrayList anonymously just for the sake of shoving in an instance initialization block.

The question is: if the sole intention of the programmer is merely to achieve the same as:

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

then what are the unintended consequences of doing it the first way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

家住魔仙堡 2024-07-22 01:09:00

执行此类代码(一般情况下)的危险在于您可能会破坏 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() 方法,该方法仅检查另一个对象是否是接口 实例列表,所以你没问题。

然而,这是需要注意的事情。

我建议采取稍微不同的做法:

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

当然,它更冗长,但这样你不太可能遇到麻烦,因为生成的类是一个“纯”ArrayList。

The danger of doing that sort of code (in the general case) is that you might break equals() methods. That's because there are two general templates for equals():

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

and

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

The first will still work with the anonymous subclasses you're talking about but the second won't. Thing is, the second is considered best practice because instanceof isn't necessarily commutative (meaning a.equals(b) might not equal b.equals(a)).

Specifically in this case however ArrayList uses the AbstractList.equals() method which merely checks that the other object is an instanceof the interface List, so you're fine.

It is something to be aware of however.

What I would suggest is to do it slightly differently:

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

Sure it's more wordy but you're less likely to get in trouble this way as the resultant class is a "pure" ArrayList.

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

这通常不是问题。 但是,如果您序列化此对象(我特别考虑使用 XStream 因为我自己也遇到过这个问题) 那么序列化的形式将包含序列化的外部类。 这根本不是您通常所期望的,并且可能会导致奇怪的行为!

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

I think the big issue here is that you're creating an inner class of the surrounding class. The list you create will have an implicit this reference to the outer class.

This isn't normally a problem. However, if you serialise this object (I'm thinking particularly of using XStream since I've run into this myself) then the serialised form will contain the serialised outer class. Which isn't at all what you'd normally expect and can result in peculiar behaviour!

I use the above initialisation pattern a lot. So long as you're aware of the inner class mechanism then it's not a problem. bTW. I don't think the equality issue is an issue beyond that of equality implementations on derivations in general.

花开柳相依 2024-07-22 01:09:00

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

这里真正的打击是你让人们停下来思考“这个人在做什么?”

如果我在阅读你的代码时必须这样做 1,000 次,那就存在性能问题。

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

您很可能将成为维护代码的人。 善待未来的自己,让代码尽可能易于阅读。 如果您要做一些类似的奇特的事情,请有一个充分的理由并在代码中记录它。 如果唯一的原因是炫耀你作为程序员的能力,那么你就没有完成程序员的真正工作:让困难变得简单。

The impact on code performance and/or memory is negligible (if even measurable).

The real hit here is that you are making people stop, even for a beat, to think "what's this guy doing?"

If I have to do that 1,000 times while I read your code, THERE is the performance problem.

Code should be easy to read - so long as all performance, completeness, and standards requirements are met.

Most likely you are going to be the person maintaining your code. Be nice to your future self, and make the code as EASY TO READ as possible. If you're going to do some fancy schmancy stuff like that, have a good reason and document it in code. If the only reason is to show off your chops as a programmer, you have failed in the real job of a programmer: to make the difficult easy.

断爱 2024-07-22 01:09:00

第一种方法也不利于性能。 用大量匿名类扰乱内存是不好的。 而且启动时速度也会变慢。

The first approach is also bad for performance. Cluttering memory with lots of anonymous classes isn't good. Also it will be slower at startup.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文