Java 如果大量使用匿名内部类,它对性能的影响有多大?
==结论=== 在哪个州找到了好的读物 当前的GC算法实际上是为创建许多短生命的小对象而优化的, 所以我认为在项目中大量使用匿名内部类对于性能来说并没有什么大不了的* ======================================================================== 因为函数不是当前Java(Java7)中的第一类公民,所以使用匿名内部类似乎是实现完全异步应用程序的唯一方法 我知道这在某种程度上会带来更大的内存占用和垃圾收集器负担,但我不知道这会有多严重?最近,我的同事和我争论,因为我的代码是利用匿名内部类以函数式编写的,他的反对意见完全是关于性能的。虽然我不同意,但我不能举出任何例子来证明我自己。我知道groovy是使用匿名类实现闭包的,但groovy的性能确实比java差(当然匿名应该只承担部分责任,因为groovy也大量使用反射) 所以我想知道在现实世界中,是否有任何项目仅仅因为性能而放弃匿名类?像swing这样的UI框架怎么样?它大量使用匿名类吗 没有匿名,我无法想象如何在java中优雅地实现异步。我们的项目已经使用了一种非常丑陋的方法,使类方法作为函数指针工作。我讨厌这样,我想让人们相信匿名课程是正确的选择 我的例子:Java 如果大量使用匿名内部类,它对性能的影响有多大?,java,Java,==结论=== 在哪个州找到了好的读物 当前的GC算法实际上是为创建许多短生命的小对象而优化的, 所以我认为在项目中大量使用匿名内部类对于性能来说并没有什么大不了的* ======================================================================== 因为函数不是当前Java(Java7)中的第一类公民,所以使用匿名内部类似乎是实现完全异步应用程序的唯一方法 我知道这在某种程度上会带来更大的内存占用和垃圾收集器负担,但我不知道这会有多
// basically, I use Completion interface to make normal java methods work in async manner
public interface Completion {
void success();
void fail(String reason);
}
void methodA(Completion completion) {
do_some_business_by_calling_remote_service ....
when remote_service_ack_success:
completion.success();
else:
completion.fail(remote_service_error);
}
void methodB() {
methodA(new Completion() {
public void success() {
continue to do something;
}
public void fail(String err) {
handle error
}
});
}
这里基本上有两个问题,它们都与匿名方面无关。匿名类实际上与常规内部类没有什么不同,只是它们没有名称。匿名内部类被编译成常规内部类,而常规内部类与静态嵌套类仍然没有什么区别 问题1是因为它们是内部的,所以它们保留了对封闭类的引用:
class Outer {
interface Inner {}
Inner inner = new Inner() {
{
System.out.println(Outer.this);
}
};
}
这并不是一个很大的问题,大多数情况下这是需要的,因为您正在做一些功能性的事情,并且希望在内部类中使用外部实例的成员。但是它可能会产生问题,因为只要内部类是活动的,外部类就不能被垃圾收集
问题2是它们确实是一个对象,所以每次调用methodB时,methodB都会创建一个新的对象
显而易见的解决方案是只创建一次:
class MyProcess {
final Completion myCompletion = new Completion() {
@Override
public void success() {}
@Override
public void fail(String err) {}
}
void methodA(Completion c) {}
void methodB() {
methodA(myCompletion);
}
}
看起来你喜欢的是语法,但是没有一个真正的解决方案来保持语法,而不是同时创建一个对象
我个人的意见是:如果你不经常调用这个方法,我同意语法可以很好而且清晰。如果您经常调用它,请切换到单个对象,因为这样会占用内存空间。如果它被调用1000次,那就是1000个对象。对象大小因平台而异,但通常是最小8或16字节+指向外部实例的指针。这不是一个巨大的影响,但它可能会,例如,提示垃圾收集运行,这可能会导致微妙的暂停
顺便说一下,我又在想这个问题,想到了以下想法:
Completion myLazyCompletion;
void methodB() {
methodA(myLazyCompletion != null ? myLazyCompletion :
(myLazyCompletion = new Completion() {
// overrides
})
);
}
我会说不要那样做,但我觉得这很有趣 你能举一个例子说明你是如何使用匿名类的,以及你担心的性能问题是什么吗?@Dolda2000:看我的更新你不是第一个问这个问题的人:@J.p:不,这是不同的。您发布的线程在性能上没有什么不同,因为不管使用匿名类还是内部类,它都将创建一个对象。我的情况不同,它为每个方法调用创建匿名对象,这在同步调用中是不必要的manner@zx_wing没有“匿名对象”的概念是的。现在看来唯一的问题是匿名类可能会导致太多的对象。只是想知道UI框架项目是如何处理它的,在方法范围之外定义它似乎不是一个使可读性良好的好方法。如果Java的内存管理更明确一点就好了,因为这是堆栈分配的一个明显场景。据推测,JVM可以进行逃逸分析,但这将是一种无声的优化。堆栈分配将使对象相对自由。@Radiodef:延迟创建不正确。匿名类的优点不仅是用作回调,而且还具有对同一范围内定义的变量(本地或类范围)的隐藏引用。这种引用绑定非常方便,人们经常使用它作为功能样式。使用内部类而不是匿名类无法绑定到通常创建匿名类的方法的局部变量。使用lazy creating方法会让事情变得更糟,因为对象只在第一次创建时绑定到变量。@zx_-wing我从来没有说过这是完全一样的事情——实际上我说过不要这样做。