2012-07-05 162 views
2

在java中,经常存在的对象只能用于包装某个功能,并且没有任何状态。例如:创建空对象

class Foo { 
    void foo() { 
     System.out.println("foo"); 
    } 

    static public void main(String[] arg) { 
     Foo foo = new Foo(); 
     foo.foo(); 
    } 
} 

我想知道如果表达式new Foo()被优化以什么在C++中。将函数指针的分配。这似乎是一件显而易见的事情,但是当我考虑它时,编译器将不得不检查foo是否不用于同步(可能还有别的吗?)。标准是否对此有所说明?

+0

你在说什么编译器?从源代码编译为字节码,还是字节码JIT编译? – ControlAltDel 2012-07-05 13:46:06

+0

javac 1.7,源代码字节码 – 2012-07-05 13:55:32

+0

这是[specification](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9.4)必须说:“接下来,空间分配给新的类实例。” – 2012-07-05 14:02:09

回答

1

标准(虚拟机规范和JLS即是)对此没有任何说明,完全取决于虚拟机实现来处理优化。

所有标准都规定了一组需要观察的不变量。如果虚拟机保证你所做的将看起来像创建一个对象,然后调用一个方法,然后处置它,它可以做它想做的事情。

虽然优化的确切方式可能会有所不同,但在这个低层次上的事情是一个瓶颈,这是非常罕见的。但是,随着运行时优化的完成,您可以合理地确定只有在您的代码被调用时才会执行它们;不经常使用的代码被解释而不是编译成机器代码。 (但是,即使这可能会从虚拟机改变为虚拟机,并且可能取决于特定的命令行选项。)在您的情况下,可能发生的情况是,经过大量运行后,虚拟机完全将该方法内联,摆脱了对象创建和方法调用。

您可以绝对“优化”您的代码的一件事是声明Foo(和foo())final。

+0

'最终'会做​​什么? – 2012-07-05 14:00:48

+0

JLS在指定分配类实例的空间时是精确的。 – 2012-07-05 14:02:58

+0

@KarolisJuodelė'final'类不能再被扩展,'final'方法不能被覆盖,当VM决定进行优化时,会给虚拟机一个提示。 (尽管据我所知,HotSpot确实记录了哪些方法实际上被覆盖了。)真正好的是发出你的设计意图。 – biziclop 2012-07-05 15:25:29

0

据说,创建一个对象只需要约10条指令。所以这是一个非常非常便宜的操作。

here

太阳估计,大约十机器指令分配成本。

因此,创建新对象几乎没有开销。如果您将所有内容都设置为静态,并且只将其放入一个类中,则可能会很快出现混乱。

0

如果你没有任何状态,那么你可以使这些方法static。我不认为java编译器会按照你的想法优化它,即使这会改变语义。如果一个对象是通过new创建的,那么将它转换成别的东西会改变语义。

我不认为使用函数指针的赋值的概念。

+0

你不能总是使用静态方法。考虑访问者模式(不是我现在正在使用它)。 – 2012-07-05 13:49:28

+0

我仍然无法想象一个你不能重构成静态方法的情况,但是允许建议的优化。如果您依赖动态分发(例如访问者或任何其他情况),那么此优化**不起作用。 – 2012-07-05 16:42:39

0

想象一下当您有大量静态辅助方法时的场景。如果你在课堂上使用它们,你的班级将会变得越来越大。

但是,如果您将它们写入单独的单例或静态类中,则只需保存一个引用,然后通过该方法调用方法,以便在处理多个实例时节省内存。

我可能是错的,但这是首先想到的东西。

0

新的Foo()将创建一个新的对象

在Java中,有对象,数组和原语,并没有别的

+0

但我们不是在这里谈论Java。 – biziclop 2012-07-05 13:47:29

0

不知道标准说的是什么。但我不认为像你提到的任何优化都已完成。我为什么认为我确定?因为它会破坏java.lang.Class的功能。来自API文档:

类的实例类表示正在运行的Java应用程序中的类和接口。