Java中的值类型:为什么它们不可变?

值类型不必是不变的。 但是他们是。

在上一篇文章中,我讨论了Java中指针与引用之间的区别以及如何传递方法参数(按值传递或按引用传递)。 这些与Java中尚不存在的值类型密切相关(尚未)。

John Rose,Brian Goetz和Guy Steele 提出了一项建议 ,详细介绍了值类型将如何/可能在Java中工作,并且还有一些不错的文章。 我已经阅读了我非常喜欢的“值类型:改造Java的类型系统” ,我建议阅读。 如果建议过于密集,以至于您无法关注该主题,则可以先阅读该文章。 它非常概括了背景,值类型是什么,优点,为什么Java不实现值类型是一个问题以及为什么它不是琐碎的问题。 即使术语“值类型”也可以用来表示不同的东西,我也会在提案和文章中使用它。

我们如何传递参数与我们在变量中存储什么

您可能还记得上一篇文章,我详细介绍了Java根据引用的类型或引用或值传递方法参数:

  • 当参数是对象时传递引用
  • 参数为原始值时按值排序。

在原始帖子上以及在JCG重新发布 都有一些评论,这些评论抱怨了我关于通过引用传递论点的术语。 注释指出,参数始终按值传递,因为变量已包含对对象的引用。 但实际上,变量包含位。 即使了解我们如何想象这些位以及在交流时使用什么术语,这一点很重要。 我们可以说

  1. 类变量包含对象,在这种情况下,我们通过引用将这些对象传递给方法
  2. 或者我们可以说变量包含引用,在这种情况下,我们传递变量的值。

如果我们遵循思想#1,则根据参数(对象或基元)的实际性质,参数传递是按值和/或按引用。 如果我们遵循思想#2,则变量将根据其类型的性质存储参考和/或值。 我个人想写的时候

Triangle triangle;

则可变triangle是三角形,而不是对三角形的引用。 但这与我的大脑到底有什么关系并不重要。 在情况#1或#2中,对于类类型和基元有不同的方法。 如果我们在语言中引入值类型,则区别会变得更加普遍和易于理解。

值类型是不可变的

我解释说,基于类型的隐式参数传递不会引起任何问题,因为基元是不可变的,因此,当作为方法参数传递时,即使通过引用传递它们也无法更改。 所以我们通常不在乎。 值类型没有不同。 值类型也是不可变的,因为它们是值,并且值不变。 例如,PI的值为3.145926…,并且它永远不会改变。

但是,这种不变性在编程中意味着什么? 值可以是实数,整数或复合值类型,它们在内存中均以位表示。 可以更改内存中的位(除非内存是ROM)。

在对象不可变的情况下,相当简单。 宇宙中某个地方有一个我们无法改变的物体。 可能有许多保存对象的变量(对其有一个引用),并且代码可以依赖于这样一个事实,即表示对象实际值的存储位置中的位不变(或多或少)。

在值类型的情况下,这有点不同,并且这种差异是由于相同位在表示对象时对表示值类型的位的解释不同。

值类型没有身份

值类型没有身份。 您不能有两个保存值3 int变量并区分另一个。 它们具有相同的价值。 当类型更复杂时,也是如此。

假设我有一个具有两个字段的值类型,例如

ValueType TwoFields {
  int count;
  double size;
  }

说我有两个变量

Twofields tF1 = new TwoFields(1,3.14)
 Twofields tF2 = new TwoFields(1,3.14)

我不能从其他变量告诉tF1tF2 。 如果他们的对象,他们是equals彼此但不==对方。 对于值类型,没有==因为它们没有身份。

如果TwoFields是不可变的类,我不能或不应该写

TwoFields tF;
  ...
 tF.count++;

或一些类似的结构。 但我仍然可以写

TwoFields tF;
  ...
 tF = new TwoFields(tF.count+1, tF.size)

使原始对象保持完整。 如果TwoFields是值类型,则无论哪种构造,都将创建一个新值。

值类型作为参数

值类型如何作为方法参数传递呢? 可能将值复制到参数变量。 可能会传递一些参考。 但是,这取决于编译器(是Java还是其他语言)。 为什么?

  • 值类型通常很小。 至少它们应该很小。 巨大的值类型失去了值类型提供的优点,但有缺点。
  • 值类型是不可变的,因此像原语一样复制它们没有问题。 它们可以按值传递,就像“ Java中的所有值都按值传递”一样。
  • 它们没有身份,不能引用它们。

但这不仅是将它们作为参数传递。 这也是分配变量的方式。 看代码

Twofields tF1 = new TwoFields(1,3.14)
 Twofields tF2 = new TwoFields(1,3.14)

比较一下

Twofields tF1 = new TwoFields(1,3.14)
 Twofields tF2 = tF1

如果TwoFields是值类型,则两个版本之间应该没有区别。 它们必须产生相同的结果(尽管在编译时可能不会通过相同的代码)。 在这方面,参数传递和变量赋值之间没有真正的区别。 即使实际变量作为位包含对存储值的某些存储位置的某些引用,也会复制值。

摘要

在我开始撰写本文时:值类型不必是不变的。 这不是语言设计师决定的事情。 他们可以自由地实现可变的东西,但是在那种情况下,它将不是值类型。 值类型是不可变的。

翻译自: https://www.javacodegeeks.com/2016/01/value-types-java-immutable.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值