Java将引入新的对象类型来解决内存利用问题

2022年Java将有什么新的特性和改进,我相信很多Java开发者都想知道。结合Java语言架构师布莱恩·格茨Brian Goetz)最近的一些分享,胖哥给大家爆个料。老规矩,点赞走起。

Valhalla

布莱恩·格茨在去年底发表了一篇名为State of Valhalla的文章,里面信息量非常大,里面提到早在2014年Java项目组就启动了一个名叫Valhalla的项目,这个项目将为JVM平台带来更加灵活的、扁平化的数据类型。在2021年该项目将有进一步的动作,值对象(value objects)原始类(primitive classes)专用泛型(specialized generics)即将引入JVM平台。今天先来聊聊这个值对象是个啥。

我们知道什么是“值”,什么是“对象”,但是什么是“值对象”呢?不光你们懵逼,我也懵逼,来一起研究研究。

Java类型系统的不足

Java的类型系统

Java类型系统由内置的10种类型组成,这10种类型无法直接表达复杂的数据结构,例如字符串、三维坐标、空间向量等等,但是开发者可以用这10种类型来为业务实体建模,Java的类型体系是非常有用的。

但是Java类型仍然存在“缺陷”, 同一个类的两个对象包含完全相同的属性,但是它们的内存寻址是不一样的。

所以从某种意义上说,他们有自己的身份标识。

但是对于原始类型就不一样了,如果一个int类型的变量值为7,另一个也为7,区分它们有意义吗?这个7还是那个7?显然是无意义的。

让我们再来举一个现实中的例子,两件相同尺寸、材质的红色衣服肯定是两件不同的衣服,但是它们的材质肯定是一种材质,颜色肯定是一种颜色,不会有傻子认为这是两种颜色。这里面的尺寸当然可以通过Java中的原始类型去描述,但是材质和颜色不行(虽然颜色可以用十六进制表示),这里的尺寸、材质、颜色都应该被认为是原语。

这个痛点促使了Valhalla项目的诞生。

对象头

为了理解Valhalla引入的 Value Object / ClassPrimitive Object / Class 概念能够给我们带来了什么,我们需要看看JVM是如何将对象保存在内存中的。

对象头对类的对象非常重要,决定哪个线程可以访问对象、垃圾收集器标记、对象hash;更重要的还有对象的类型指针,它能够在运行时动态访问对象的类,并从其类到该对象的详细信息,比如继承多态、反射。

但是凡事都有两面性,Java对象内存占用的大小取决于它所包含的信息的总和,对象头在 64 位系统上至少需要 16 个字节,在 32 位系统上至少需要 8 个字节(当然JVM可以通过配置项去设置如何保存对象头)。很多对象不需要多线程,也不需要什么对象标识,就像上面提到的衣服的颜色,只有颜色的值才是我们关心的事。这种冗余的内存占用让Java为人诟病。

Value Class

对于许多对象来说,它属性值的相等性是我们关心的,其它类信息没什么用,而且只为保存值和对这些值进行操作而编写的类在所有类中所占的比例非常大。Valhalla项目为这样的场景引入了一个新的类类型:Value Class。目前还只是JEP草案,但是已经初具形态:

value class Substring implements CharSequence {
    private String str;
    private int start;
    private int end;
    
    public Substring(String str, int start, int end) {
        checkBounds(start, end, str.length());
        this.str = str;
        this.start = start;
        this.end = end;
    }
    
    public int length() {
        return end - start;
    }
    
    public char charAt(int i) {
        checkBounds(0, i, length());
        return str.charAt(start + i);
    }
    
    public Substring subSequence(int s, int e) {
        checkBounds(s, e, length());
        return new Substring(str, start + s, start + e);
    }
    
    public String toString() {
        return str.substring(start, end);
    }
    
    private static void checkBounds(int start, int end, int length) {
        if (start < 0 || end < start || length < end)
            throw new IndexOutOfBoundsException();
    }
}

Value Class和我们常见的类差不多,但是它可能(这里依然在讨论中)具有下面一些特性:

  • 值对象是没有身份的对象,通常情况下我们用==运算符检查身份,这里可能和equals()不再有区别。

  • 值类本身和它的所有字段默认都是final的。

  • 该类不直接或间接地实现java.lang.IdentityObject(有身份标识类的新超类)。这意味着超类要么是无状态抽象类,要么Object是无状态抽象类。

  • 值类都是java.lang.ValueObject的隐式实现。

  • 没有构造super函数调用构造函数。将在不执行任何超类初始化代码的情况下创建实例。

  • 无法在值类中使用synchronized关键字。

  • (可能)该类没有声明finalize()方法。

  • (可能)构造函数不使用this来设置构造函数主体中的字段,或者可能在所有字段都明确内存分配之后。

其它的操作和普通的类应该差别不大,但是要注意的是,JDK标准库中的一些原有类如果被认定为Value Class需要做兼容性处理。

value要成为保留字还是关键字?

这不是全部

Value Class对Java类对象头进行了阉割,有利于降低Java的内存消耗,但是这不是Valhalla计划的全部。对于这一部分过于超前的内容,我写起来其实是很有困难的,构思了好几天,从场景出发来了解一门编程语言的设计有利于从根本提高自己。如果你想了解更多关于Valhalla的东西,可以关注我,我会继续分享相关的知识。

关注公众号:码农小胖哥,获取更多资讯

个人博客:https://felord.cn

你可能感兴趣的:(Java将引入新的对象类型来解决内存利用问题)