java有值类型吗ITeye - 亚美娱乐

java有值类型吗ITeye

2019年04月03日11时40分30秒 | 作者: 智阳 | 标签: 类型,引证,指向 | 浏览: 3027

转自:http://www.yinwang.org/blog-cn/2016/06/08/java-value-type

 

Java 有值类型吗?

有人看了我之前的文章『Swift 言语的规划过错』,问我:“你说 Java 只要引证类型(reference type),可是依据 Java 的官方文档,Java 也有值类型(value type)和引证类型的差异的。比方 int,boolean 等原始类型便是值类型。” 现在我来解释一下这个问题。

Java 有值类型,原始类型 int,boolean 等是值类型,其实是长久以来的一种误解,它混杂了完成和语义的差异。不要以为 Java 的官方文档那样写便是威望结论,就能够说“王垠不了解” :) 当你以为王垠不了解一个初级问题的时分,都需求三思,由于他可能是大巧若拙…… 看了我下面的论说,或许你会发现自己应该置疑的是,Java 的规划者究竟有没有搞了解这个问题 :P

瞎说完毕,现在来说正事。Java,Scheme 等言语的原始类型,比方 char,int,boolean,double 等,在“完成”上确实是经过值(而不是引证,或许叫指针)直接传递的,可是这彻底是一种为了功率的优化(叫做 inlining)。这种优化关于程序员应该是不可见的。Java 承继了 Scheme/Lisp 的衣钵,它们在“语义”上其实是没有值类型的。

这不是天方夜谭,为了了解这一点,你能够做一个很有意思的思想试验。现在你把 Java 里边全部的原始类型都“幻想”成引证类型,也便是说,全部的 int, boolean 等原始类型的变量都不包含实践的数据,而是引证(或许叫指针),指向堆上分配的数据。然后你会发现这样“改造后”的 Java,依然契合现有 Java 代码里能看到的全部现象。也便是说,原始类型被作为值类型仍是引证类型,关于程序员彻底没有差异。

举个简略的比方,假如咱们把 int 的完成变成彻底的引证,然后来看这段代码:

int x = 1; // x指向内存地址A,内容是整数1
int y = x; // y指向相同的内存地址A,内容是整数1
x = 2; // x指向另一个内存地址B,内容是整数2。y依然指向地址A,内容是1。

由于咱们改造后的 Java 里边 int 全部是引证,所以榜首行界说的 x 并不包含一个整数,而是一个引证,它指向堆里分配的一块内存,这个空间的内容是整数 1。在第二行,咱们定 int 变量 y,当然它也是一个引证,它的值跟 x 相同,所以 y 也指向同一个地址,里边的内容是同一个整数:1。在第三行,咱们对 x 这个引证赋值。你会发现一个很有意思的现象,尽管 x 指向了 2,y 却依然指向 1。对 x 赋值并没能改动 y 指向的内容,这种状况就跟 int 是值类型的时分一模相同!所以现在尽管 int 变量全部是引证,你却不能完成同享地址的引证能做的工作:对 x 进行某种操作,导致 y 指向的内容也发作改动。

呈现这个现象的原因是,尽管现在 int 成了引证类型,你却并不能对它进行引证类型所特有(而值类型没有)的操作。这样的操作包含:

deref。就像 C 言语里的 * 操作符。 成员赋值。就像对 C struct 成员的 x.foo = 2 。

在 Java 里,你无法写像 C 言语的 *x = 2 这样的代码,由于 Java 没有供给 deref 操作符 *。你也无法经过 x.foo = 2 这样的句子改动 x 所指向的内存数据(内容是1)的一部分,由于 int 是一个原始类型。最终你发现,你只能写 x = 2,也便是改动 x 这个引证自身的指向。x = 2 履行之后,本来数字 1 地点的内存空间并没有变成 2,只不过 x 指向了新的地址,那里装着数字 2 罢了。指向 1 的其它引证变量比方 y,不会由于你进行了 x = 2 这个操作而看到 2,它们依然看到本来那个1……

在这种 int 是引证的 Java 里,你对 int 变量 x 能做的工作只要两种:

读出它的值。 对它进行赋值,使它指向另一个当地。

这两种工作,就跟你能对值类型能做的两件工作没有差异。这便是为什么你无法经过对 x 的操作而改动 y 表明的值。所以不论 int 在完成上是传递值仍是传递引证,它们在语义上都是等价的。也便是说,原始类型是值类型仍是引证类型,关于程序员来说彻底没有差异。你彻底能够把 Java 全部的原始类型都想成引证类型,之后你能对它们做的工作,你的编程思路和方法,都不会因此有任何的改动。

从这个视点来看,Java 在语义上是没有值类型的。值类型和引证类型假如一起并存,程序员有必要能够在语义上感觉到它们的不同,可是不论原始类型是值类型仍是引证类型,作为程序员,你无法感觉到任何的不同。所以你彻底能够以为 Java 只要引证类型,把原始类型全都当成引证类型来用,尽管它们确实是用值完成的。

一个在语义上有值类型的言语(比方 C#,Go 和 Swift)有必要具有以下两种特性之一(或许两者都有),程序员才干感觉到值类型的存在:

deref 操作。这使得你能够用 *x = 2 这样的句子来改动引证指向的内容,导致同享地址的其它引证看到新的值。你无法经过 x = 2 让其他值变量得到新的值,所以你感觉到值类型的存在。 像 struct 这样的“值组合类型”。你能够经过 x.foo = 2 这样的成员赋值改动引证数据(比方 class object)的一部分,使得同享地址的其它引证看到新的值。你无法经过成员赋值让另一个 struct 变量得到新的值,所以你感觉到值类型的存在。

实践上,全部的数据都是引证类型便是 Scheme 和 Java 开始的规划原理。原始类型用值来传递数据仅仅一种功能优化(叫做 inlining),它关于程序员应该是通明(看不见)的。那些在面试时喜爱问“Java 是否全部数据都是引证”,然后当你答复“是”的时分纠正你说“int,boolean 是值类型”的人,都是本本主义者。

有人指出,Java 的引证类型能够是 null,而原始类型不可,所以引证类型和值类型仍是有差异的。可是其实这并不能否定本文指出的观念,你能够想想这是为什么吗?

版权声明
本文来源于网络,版权归原作者所有,其内容与观点不代表亚美娱乐立场。转载文章仅为传播更有价值的信息,如采编人员采编有误或者版权原因,请与我们联系,我们核实后立即修改或删除。

猜您喜欢的文章

阅读排行

  • 1

    内置jetty(转)ITeye

    一个,处理,运用
  • 2

    java有值类型吗ITeye

    类型,引证,指向
  • 3
  • 4

    spring aopITeye

    署理,结构,调用
  • 5
  • 6

    Shell 练习题(append)ITeye

    实例,文件,上述
  • 7

    获取checkbox复选框的值ITeye

    依据,获取,拿到
  • 8

    Redis的耐久化机制ITeye

    耐久,方法,内存
  • 9
  • 10

    记一次线程池的运用ITeye

    线程,运用,行列