不存储新对象而创建新对象是不好的做法吗?


23

我见过用Java代码创建的对象,但没有存储对该对象的引用。例如,在eclipse插件中,我看到了SWT Shell的创建过程,如下所示:

new Shell();

这个新的Shell对象没有存储在变量中,但是将一直保持引用状态,直到处理完该窗口为止(默认情况下,关闭该窗口时会发生[我相信?])。

创建这样的对象而不存储对它们的引用是不好的做法吗?还是图书馆设计不当?如果我不需要引用,而只想要对象的“副作用”怎么办?我是否仍应存储参考?

更新:

诚然,我上面的例子很差。虽然我看到过这样创建的UI元素,但是创建这样的SWT Shell可能毫无意义,因为您需要在Shell实例上调用open方法。有由AIX提供更好的例子,如从以下Java并发教程

(new HelloThread()).start();

在许多情况下都可以看到这种做法,因此问题仍然存在。这是好习惯吗?


2
存储参考的目的是什么?
Daniel R Hicks

(从概念上讲,Shell.createTopLevelShell()在这种情况下,使用静态方法(诸如此类)与使用构造方法相比可能会更好。但是从功能上讲,两者之间没有什么区别。)
Daniel R Hicks 2012年

这个问题是关于创建对象而不引用它们,创建需要这种实践的类的实践,还是关于SWT使用这种模式的方式的问题?
StriplingWarrior 2012年

1
SWT对象必须是dispose()d: 规则1:如果创建了它,则将其处置。 eclipse.org/articles/swt-design-2/swt-design-2.html
jbindel 2012年

2
我将使用一个变量来保存引用以进行调试。如果此方法有断点,则可以使调试器通过局部变量查询对象。没有参考资料,我相信这是可能的,但可能会困难得多。
马丁·约克

Answers:


12

有一个个人喜好因素,但是我认为不存储参考并不一定是一个坏习惯。

考虑以下假设示例:

new SingleFileProcessor().process(file);

如果需要为每个文件创建一个新的处理器对象,并且在process()调用后不需要该对象,则没有必要存储对它的引用。

这是取自Java 并发性教程的另一个示例:

(new HelloThread()).start();

当引用未存储时,我还看到了许多其他示例,这些示例在我看来非常好,例如:

String str = new StringBuilder().append(x).append(y).append(z).toString();

StringBuilder不保留该对象。)

有类似的模式涉及common.lang HashCodeBuilder等。


2
@BalusC:相对而言,我看不出是什么使它变得可疑,以何种方式拥有工厂方法更好(我假设您的示例类似于我的示例,并且getInstance()是工厂而不是单例)。
NPE 2012年

是否使用单例取决于工厂。工厂的调用者不应该考虑太多。
Donal Fellows 2012年

在您的示例中,语句完成后(大概)不需要FileProcessor实例,而在OP的示例中,Shell实例(在幕后)被另一个对象引用,并且该引用(并因此是Shell对象)在声明的持续时间。
Daniel R Hicks 2012年

@BalusC:FileProcessor可能具有其他方法来更改的行为process
凯文·克莱恩


5

通常,优良作法是尽可能合理地释放引用。我认为两者之间没有区别:

HelloThread thread = new HelloThread();
thread.start();
// where thread is never used for the rest of the method

(new HelloThread()).start();

就代码而言,您只是避免使用变量名,这可能是积极的事情。JIT编译器通常足够聪明,可以识别出它可以在上次使用后对其进行垃圾回收,因此从性能的角度来看,可能没有什么区别。

唯一需要避免的实际问题是Constructor Anti-Pattern中代码,但这听起来并不像您要的那样。


3

如果您使用的是SWT,这可能会很糟糕,因为您必须在此之后自行清理(调用dispose()方法)。但是对于其他类(非SWT)也可以。

这是有关管理操作系统资源的文章


循环引用不会阻止在Java中对对象进行垃圾回收。任何现代Java VM都会根据对象是否可访问来确定对象是否可GC,并且不使用引用计数。
jbindel 2012年

2
实际上,它不使用引用计数。但是SWT是一种特殊情况,尽管不需要先调用任何keep(),但我们确实需要调用dispose()。
亚历克斯(Alex)2012年

我的意思是仅指非SWT案件。
jbindel 2012年

这是一篇有关管理操作系统资源的文章eclipse.org/articles/swt-design-2/swt-design-2.html
Alex

2
在这种情况下,请编辑您的答案以删除有关“ GC不可能”的陈述,因为这会误导您。
Donal Fellows 2012年

1

首先,您会惹恼那些在Java之前学过C或C ++的人。我将其留给读者练习,以决定是赞成还是反对。

尽管在某些情况下对象被设计为寿命很短,但在大多数情况下,如果某事物足够复杂,无法为其创建对象,则它足够复杂,因此有充分的理由保留引用,因此不应将其保留在至少要警告您,如果您错过了一些东西,请仔细检查。

例如,在一个教程中,没有人关心保留线程引用,但是在现实生活中,如果某件事花费了足够长的时间来生成一个线程,那么它通常花费足够长的时间就可以取消该线程。或者,如果寿命较短,通常join在继续操作之前会生成一堆您想要的线程。或者,您想确保线程创建实际上已成功。或者您要确保线程在退出之前干净地完成。您得到图片。


2
担心来自其他语言的令人讨厌的程序员真的是头等大事吗?
Buttons840 2012年

根据团队的组成,它使它成为易读性/熟悉性/样式问题,因为这是很多人都会继承的样式。即使是从未使用C ++编程的人,也经常采用那些曾经做过的指导者的风格。
Karl Bielefeldt 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.