如果我有一个简单的数据类型,可以用单个原始值表示的东西,比如int,例如一个计数器,而我的类是不可变的(这很重要),我想定义所有的业务逻辑,包括诸如“不能为负”的前提条件,以便它的使用是安全的,并且它只能包含有效数据。对于这样的类型,你不能不小心地将乘客数量添加到乘客的数量(如果他们是不同的计数器类型),但如果两者都只是整数,你就可以。
所以我想要的是一种方法来将这些类型注释为“inlineable”,以便将实例的引用替换为状态的值,并且对实例方法的调用将被调用静态方法替换接受或接收国家,JIT也可以内联。一个限制是不能替换所有使用站点,例如将其中一个放入Java列表中。但阵列可以有效替换。
因此,主要的好处是“删除对象开销”,间接创建对象和GC成本,同时保持代码尽可能安全。
JIT为我们做了内联方法,在大多数情况下都没问题,但它(至少现在至少)没有删除对象开销,这就是为什么对象的状态通常由原始类型组成,而不是特定于业务模型的类型。特定于业务模型的类型使用起来更安全,并遵循DRY原则;你只需要定义一次前提条件。但是,在很多情况下,你必须为这么简单付出的代价就是很高。
理想情况下,我更喜欢字节码级工具,编译时或加载时,因为我正在进行混合Java-Scala编码。
我发现this question是相关的,海报想知道JIT何时自动内联,而我想要显式内联,即使是公共API的一部分。
最后一点:请不要告诉我“对象很便宜”。我已经在Java工作了10年,至少在过去的6年里一直在我的团队负责JVM分析,所以我很痛苦地知道对象的成本。
答案 0 :(得分:4)
你所说的听起来很像value types - 类型应该被视为“直接”值而不是对象(通过引用访问),就像原始类型一样。
Java没有用户可定义的值类型,并且很可能不会很快获得新版本的版本(可能在Java 9甚至更高版本中)。据我所知,JVM或JIT也不会自动将对象视为值类型(“全班内联”)。
请注意,C#确实有user-definable value types。
但是,方法的内联已经可以使您的代码非常高效。考虑一下:
class MyValue {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
当您调用它们时,JVM会内联getter和setter方法,因此调用这些方法与直接访问类的value
成员变量一样高效。然而,MyValue
的实例将占用比int
更多的内存,因为Java对象具有一些不可避免的开销(例如,您可以在Java中的任何对象上进行同步,因此每个对象都必须具有锁定与之关联 - 这个锁是对象状态的一部分。)
由于Java缺少值类型,因此无法创建保证在内存中连续布局的对象数组。具有非基本类型的元素类型的数组实际上是对象的引用数组,并且这些引用指向的对象原则上可以分散在整个堆中。这对于某些操作的性能来说并不好(例如,如果你遍历数组,如果内存访问模式是可预测的,那么CPU的缓存效率最高 - 如果对象分散在随机位置,则效率会降低。)
关于廉价的对象:最近的JDK中的一个优化是{{3}},这将导致在堆栈而不是堆上分配方法的本地临时对象,因此释放分配的内存基本上是免费的(垃圾收集器不必处理对象)。