valuetype_Java中的新ValueType

valuetype

在本文中,我将讨论对象的问题,这些问题使Java中必须具有值类型。 之后,我将讨论什么是值类型,最后,我将讨论值类型存在的问题。 是的,值类型也有问题,其原因非常根本。 你不可能一生拥有所有美好的事物。 你不能吃蛋糕和吃东西。 使用值类型比对象有优势,但是在应用程序,编程构造中,对象更适合。 在本文的最后一部分,您还将理解为什么对值类型有限制,例如没有继承,缺少泛型和不变性。

Java中的对象

Java中的对象是小的内存部分,通常存储在称为堆的内存段中。 在创建对象时分配内存,在不再使用对象并收集对象时释放内存。 在对象的生存期内,代表对象的内存可能会在垃圾回收过程中从一个位置移动到另一位置。 这就是Java管理内存的方式,并确保无论对象如何创建和销毁,内存都不会分段。 其他收集垃圾但不进行压缩的语言面临着长时间运行的进程对内存进行分段的风险。 有用的东西:压缩是CPU密集型过程,因此Java GC几乎无法与Go语言垃圾收集的速度竞争。 但是,最重要的是,对象在内存中移动这一事实使指针无用。 它们指向内存中的某个位置,但是数据在GC的压缩阶段之后可能已经位于其他位置。 这就是Java不使用指针的原因。 Java使用引用。

您可以询问指针和引用之间的区别是什么。 好吧,引用是管理的指针。 当GC将对象移动到内存中时,它必须更新所有引用,以便它们都知道该时刻对象在哪里。 与本机代码的集成也很麻烦。 Java GC无法知道本机代码将指针复制到本机代码管理的内存中的位置。 另外,Java中没有指针算法。 有数组,但是除此之外,您可以忘记使用C或C ++进行编程时可能习惯的漂亮指针算法。 好处是您还可以忘记由于错误的指针值计算而导致的内存损坏。

还请参见:

但是,对象位于内存中,并且当处理器需要对其进行一些计算时,对象必须从主内存传输到处理器。 当CPU运行4MHz时,这不是问题。 内存访问的速度与处理器的速度相当。 如今,处理器运行于4GHz,并且内存访问几乎没有以前那样快。 这不是坏技术,而是物理。 计算从CPU到内存再以光速返回所需的时间-就是这样。 只有一种方法可以加快速度:将内存放在处理单元附近。 实际上,这就是现代CPU所做的:它们在CPU本身上具有内存缓存。 不幸的是,不仅提高了CPU速度,而且还需要内存。 在过去,我们的计算机上只有640kB,每个人都必须足够。 今天,我的Mac有16GB。 物理又来了:您不能在CPU上放置16GB或更多空间,因为没有空间,也没有有效的方法来冷却系统,我们想使用CPU来计算而不是做饭。

当CPU需要内存位置时,它将读入高速缓存。 当程序需要内存中的某些内容时,很可能很快它将需要下一个内存位置中的某些内容,依此类推。 因此,CPU继续运行并将整个内存页面读入高速缓存。 高速缓存中可能有来自不同存储区的许多页面。 当我们有一个数组并访问第一个元素时,它可能很慢(以CPU术语来说,慢意味着几十纳秒),但是当我们需要数组中的第二个元素时,它已经在缓存中了。 这是非常有效的,除非这是一个对象数组。 对于对象数组,数组本身是引用的连续区域。 访问数组第二个元素的CPU将在高速缓存中具有引用,但是对象本身可能与第一个对象所在的页面位于完全不同的页面上。 有一些内存布局优化技术可以部分解决此问题,但真正的解决办法是,将对象像狩猎后的the一样排列在内存中。 但事实并非如此。 即使它们在内存中一个接一个地排列,它们也会被所谓的对象标头分隔开。

对象标头比描述对象的对象存储器要早几个字节。 它拥有synchronized语句中使用的锁以及对象的类型。 当我们在变量中拥有一个引用(例如,可Serializable类型)时,我们将不会从变量本身知道对象的实际类型。 我们必须访问该对象,并且Java运行时将读取该对象的实际类型。 对于Java,此对象标头有助于继承和多态。 同样,在32位实现中的几个字节总计为12个字节,而在64位体系结构上则为16个字节。 这意味着一个Integer存储一个32位的int值以及另外的128位的额外管理位。 那是4:1的比例。

值类型

值类型试图解决这些问题。 就值类型而言,它可以具有字段和方法,就好像是一个类。

在JEP 169下的Valhalla项目中,正在为Java开发值类型。目前,有一个早期访问版本可以尝试。 此版本是Java 11版本的分支,并具有一些限制。 语法是初步的,有些关键字以双下划线开头,而该关键字不能在最终版本中出现,而某些功能尚未实现。 尽管如此,仍然可以尝试一下。

值类型与对象的不同之处在于,值类型没有对象标头或标识,没有对值类型的引用,值类型是不可变的,并且值类型之间没有继承。为此原因,没有多态性。 其中一些(如缺少对象标头)是实现细节,而其他一些则是设计决策。 让我们看一下值类型的这些功能。

没有身份

值类型没有身份。 当我们处理对象时,两个对象可以是相同的。 本质上,我们只谈论同一对象两次,而对象可以相等。 在后一种情况下,我们有两个不同的对象,但是它们是同一类的实例,并且当我们比较它们时equals()方法返回true。 如前所述,使用Java中的==运算符检查身份,并使用equals()方法检查是否equals() 。 诸如bytecharshortintlongfloatdoubleBoolean也没有标识。 在这种情况下,这是显而易见的。 说两个布尔值都为true但实例仍然不同是胡说八道。 作为逻辑值,数字(如零,一或pi)也没有实例。 它们是价值。 我们可以使用==运算符比较它们是否相等,而不是相同。 值类型的想法是用程序员定义的类型(也表示值)来扩展这八个原始值的集合。

没有参考

值存储在变量中,而不存储在堆中。 当值的位表示形式位于变量中时,编译器将知道类型,就像知道变量的类型为int时应将变量中的位作为32位带符号整数处理一样。 还必须注意,当将值类型作为参数传递给方法时,该方法将接收原始值类型的“副本”。 这是因为Java通过值而不是通过引用传递所有参数。 随着值类型的引入,这不会改变。 将值类型作为参数传递给方法调用时,该值类型的所有位都将复制到方法的本地参数变量中。

没有对象标题

由于值类型是值,存储在变量中而不是堆中,因此它们不需要标头。 编译器只知道变量的类型,程序应以哪种方式处理该变量中的位。 当值类型数组进入图片时,这至关重要。 就像使用原语一样,当我们创建一个值类型的数组时,这些值将一个接一个地包装在内存中。 这意味着使用值类型,我们将不会遇到对象数组所具有的问题。 没有对数组中各个元素的引用,它们不能分散在内存中。 当CPU加载第一个元素时,它将加载同一内存页上的所有元素,并且访问连续元素将利用处理器缓存的优势。

没有继承

值类型之间可能存在继承,但是编译器将很难管理它,并且不会带来很多好处。 我敢说,允许继承不仅会给编译器造成问题,还会诱使没有经验的程序员创建弊大于利的构造。 在即将发布的支持值类型的Java版本中,值类型之间或类与值类型之间将没有继承。 这是一个设计决策,在解释众多原因中,让我们看一些简单的示例。

当类C包含另一个类P的类型的字段时,它包含对该另一个类的引用。 也可能CP父类的子代。 这不是问题。 例如,有一个P实例的链接列表。 有一个名为next的字段,该字段为null或保留对列表中下一个P的引用。 如果列表还可以包含C实例(请记住: C扩展了P ),则C也具有对下一个P的引用。 该列表可以包含C实例,因为正如继承所暗示的, C也是P

如果P是值类型,情况如何? 我们不能将元素链接在一起。 没有对下一个P引用,因为不存在对值类型的引用。 类可以通过字段值相互引用。 值类型仅实现包含。 当一个值类型具有另一个值类型的字段时,它将包含该另一值类型的所有位。 因此,值类型永远不能包含其自身类型的字段。 这意味着值类型包含自身,并且这是类型定义的无限递归。 这样的类型将无限大,因此在规范中明确禁止。 如果值类型可以彼此继承,则限制将更加复杂。 在那种情况下,我们不能简单地说一个值类型一定不能包含它自己。 我们应该禁止任何其他值类型成为当前值类型的后代。

另外,尝试想象一个类型为V的变量。 这样的变量应该足够大以容纳V所有位。 但是,如果有可能扩展值对象,并且假设K会扩展V那么它还应该足够大以容纳K所有位。 在这种情况下, K将包含V所有位以及它自己的更多位。 V型变量应具有多少位? V的位数 然后我们无法在其中存储K值, K将不适合。 所有V类型的变量都应足够大以容纳K 但是我们不应该停止在K因为可能会有更多的值类型扩展K ,但仍假定存在继承,而没有继承。 在这种情况下,该类型的变量V应该有一样多的位的最大后代V可以有,这是在编译时未知。 仅在加载所有值类型时才知道。

没有多态

由于没有继承,因此不能有值类型多态性。 但是,还有更多的原因表明对值类型实施多态是不合理的。 让我们看一下上面的示例,想象一下可以容纳V最大后代的所有位的变量。 在此变量上调用方法时,应在运行时调用哪个方法? 该变量不包含有关实际值类型的类型的信息。 是V ,是K还是其他后代? 编译器必须知道要调用的方法,因为没有标头信息会指示当时变量中的类型。

不变性

不变性是设计决定,但这是自然的方式。 Java中的值类型是不可变的。 不变性通常是一件好事。 不变的对象以干净且线程安全的方式对编码有很大帮助。 不变性并不能解决所有问题,但是很多时候它很方便。 同样,如果您将int视为数字,则很明显您无法更改其值。 如果变量保留整数值2,则可以更改存储在变量中的值,但不能将值本身更改为3。如果可以,则突然之间2乘以2将是整个Universe中的9。 类似的理念适用于价值类型。 您可以更改保存值类型的变量的内容,但不能更改值类型本身。 当您更改一个位之后,实际上,根据哲学,您创建了一个新的值类型并存储了新值来代替旧值。 看一下下面的简单示例(清单1):

package javax0.valuetype;

public __ByValue class Point {
    public int x;
    public int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Point pushedRight(int d) {
        return __WithField(this.x, x+d);
    }

    public String toString() {
        return "[" + x + "," + y + "]";
    }
}

这是一个简单的值类型,使用的初步语法是使用早期访问Java的build 11-lworldea+0-2018-07-30-1734349.david.simms.valhalla版本build 11-lworldea+0-2018-07-30-1734349.david.simms.valhalla编译的。 可以沿X轴“推”一个点。 使用它的主程序可以做到这一点,如清单2所示:

package javax0.valuetype;

public class Main {

    public static void main(String[] args) {
        Point a = new Point(3,4);
        a = a.pushedRight(1);
        System.out.println(a);
    }
}

当我们调用pushedRight ,变量a获得了一个新值。 但是,点(3,4)没有移动,二维空间也没有变形。 该点将永远存在,仅更改变量值。 如果现在尝试更改行a = a.pushedRight(1);ax = 4; ,我们得到一个编译错误,指出(清单3):

/.../src/javax0/valuetype/Main.java:7: error: cannot assign a value to final variable x

请注意,字段x并未声明为final,但由于它是值类型,因此它自动为final。

不变性是一种特性,与不能引用值类型这一事实密切相关。 从理论上讲,Java可以允许我们修改值类型的字段。 结果本质上是相同的:我们获得了不同的值。 这样,在值类型的情况下不变性不受限制。 这仅取决于我们如何编写程序以及如何考虑值类型。 从本质上讲,将它们视为诸如数字之类的值是本质上不变的,被认为是一种健康的思维方式。

试试看

您可以下载抢先体验版。 JEP主页是https://openjdk.java.net/jeps/169 ,您可以从https://jdk.java.net/valhalla/下载EA版本。 这些构建适用于x64平台的Linux,macOS和Windows。 安装可能不像商业产品那样简单,但是对于经验丰富的Java开发人员而言,某些环境变量设置,手动文件提取以及移至正确位置应该不成问题。

您可以尝试使用Eclipse,IntelliJ或记事本来编辑源代码,但至少在IntelliJ 2019.EA版本中,我无法构建代码。 即使该代码是Java 11的源代码,IntelliJ仍将其识别为Java 13,顺便说一句,这是一个提示,说明在发行版本中可以期望值类型。 可以手动执行命令行javac命令,然后通过java命令启动JVM,完成代码的编译。 即使我对Maven的了解比对ANT的熟悉,我仍可以设法与IntelliJ提取的ANT脚本相处。

还请参见:

玩耍时,我以为代码中没有错误时遇到了莫名其妙的编译错误。 然后,更改代码,编译正常。 其他时候,当错误无疑在我这一边时,错误消息是描述性的并且易于理解。

摘要

Java发展Swift。 在过去的两年中出现了许多新事物,并且正在酝酿中的许多新事物将在未来提供。 值类型功能是其中之一。 本文介绍了此功能的主要特征,并简要介绍了这项新技术。 Java还是一种主要的编程语言,也许它是在专业环境中仅次于COBOL的第二广泛使用的编程语言。 就就业而言,成为Java开发人员几乎是一件肯定的事情。 但是,要专业且与时俱进,就需要不断学习。 幸运的是,Java是开放源代码,并且有免费的开放式邮件列表,文档和源代码,并且即将发布版本的试用版可在发行日期之前很长时间获得。 敏锐的开发人员必须仔细研究这些内容,使用EA版本进行试验,并准备知道发行版本成为商业用途GA时的可能性。 快来,获取Java的Valhalla EA版本并进行实验!

翻译自: https://jaxenter.com/java-value-type-163446.html

valuetype

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值