如果您创建字符串"codecodecode"在现实中,它只存在一次。,因为JVM是这样优化的。
但是这个类呢:
final public class ImmutReuseTest {
final public int num;
final public SomeImmutableThing thing;
public ImmutReuseTest(final int num, final SomeImmutableThing thing) {
this.num = num;
this.thing = thing;
}
}
final public class SomeImmutableThing {
final public int nomm;
final public String text;
public SomeImmutableThing(final int nomm, final String text) {
this.nomm = nomm;
this.text = text;
}
}
如果我创建数千个ImmutReuseTest实例,其中一些将具有100%等于值,JVM会像对String那样优化这些相等的值吗?("Equal"含义:实例之间的单个字段是相等的,这是关于类型为"someimmutablething"的字段。意思是:那些thing字段在那些thing实例之间也是相等的。)
如果实例具有完全相同的怎么办?价值观?("Identical"含义:SomeImmutableThing实例是相同的,而不仅仅是相等)
如果我们改变SomeImmutableThing来使用一个被认为是不可变的类,但有内部可变值(像String一样,但String是一个糟糕的例子,因为专门的JVM优化)?例如,让我们使用一个具有公共可变字段但"有效的final"。或者只有"有效终结"的私有可变字段。
执行环境必须保留Java编程语言的语义,即new
操作符的语义:
类实例创建表达式的值是对指定类的新创建对象的引用。每次对表达式求值时,都会创建一个新的对象。
这并不依赖于你的类的可变性,只要Java没有提供除了new
之外的其他方法来实例化你的类,就不会有实例共享,除非你自己实现了它。
您将(或可能)最终使用重用对象的已知情况不涉及new
,例如
String s = "foo";
Integer i = 42;
Runnable r = () -> System.out.println("hello");
此外,对于有意未指定对象标识的类型,如基于值的类,实例总是通过工厂方法获得,因此它们实际实例化的方式对应用程序是不可见的。
对于真值类型,正如计划在未来的Java版本中添加的那样,我们需要一个用于创建/获取实例的新语法结构或关于new
操作符的语言规范更改。
JVM仍然可以做任何优化,只要它不改变程序逻辑,所以如果它可以证明应用程序从未对某些对象执行身份敏感的操作,或者可以假装这些操作仍然具有相同的效果(例如new Foo() == new Foo()
可以被false
取代),它可以将相同的对象合并为一个。这显然很难或几乎不可能证明。
目前,当整个生命周期在优化器的范围内时,可以对短生命周期对象执行此操作。然而,在这些情况下,JVM将完全消除分配,而不是搜索相同的对象进行重用。参见HotSpot Wiki/Escape Analysis…
如果我创建了数千个ImmutReuseTest实例,其中一些实例将具有100%相等的值,JVM会像字符串一样优化这些相等的实例吗?
答案是否定的。将类编写为不可变的不会影响JVM管理其实例的方式。Java的值类型,作为Valhalla项目的一部分,旨在解决这个问题。String
优化是一个特例。
如果实例具有完全相同的值怎么办?("Identical"含义:SomeImmutableThing实例是相同的,而不仅仅是相等)
是,在这种情况下,只有一个实例具有该标识。
我不太明白你最后一个问题,但它似乎和第一个没有什么不同。