这一篇,我们从编程中最简单的概念说起:变量声明。 unsetunsetJava 变量声明的演化unsetunset如何在 Java 里声明一个键和值都是 String 类型的 map?如果是 Java 5之前,你可能会这么做: 这里我们声明了一个 map,虽然我明确地说明了键和值的类型,但在这个声明里,我们根本看不到这方面的信息。在这种声明下,map 里存放的键和值都是 Object 类型,也就是任何类型。要保证键和值都是 String,我们只能自己去做相应的转换,尤其是在取出的时候: Java 5 引入了泛型,代码变成了这样: 这里出现了键和值的类型,我们从 map 中取出数据的时候,就不再需要转换了: Java 5 虽然解决了类型信息的问题,但是,这个声明变得很长,尤其是还存在重复信息,比如,前面 Map 类型里已经有了键和值的类型,后面在初始化 HashMap 时,还要把类型再写一遍,这就是一种重复。于是,Java 7 引入了钻石操作符(<>)简化变量的声明: 钻石操作符之所以可行,因为键和值的类型信息已经在前面声明过了,编译器可以根据前面的 Map 声明“推断”出后面 HashMap 键和值的类型。 其实,无论是泛型还是钻石表达式,它们对 Java 的运行时都没有什么影响,主要的工作都是在编译过程中完成。编译器知道很多上下文信息,利用这些信息,它可以“推断”出很多事情,就像前面说的钻石操作符一样。那还能不能再进一步呢?答案是肯定的,Java 10 推出了 var。 unsetunset局部变量类型推断:varunsetunset我们先来看一个例子: 在这个例子里,把 1 赋值给 value。在这里,我们没有声明 value 的类型,但是,我们知道,在 Java 中,字面量 1 是一个 int。我们把一个 int 赋值给 value,那 value 应该是什么类型呢?它当然应该也是一个 int。所以,虽然我们没有声明 value 的类型,但是,编译器已经“推断”出了它的类型。 或许你没觉得这里 var 比 int 节省了什么,那我们回到前面的 map 声明: 按照前面讲的逻辑,编译器很容易“推断”出 map 的类型是 HashMap<String, String>,这里的重点是,我不再需要手工声明这个 map 的类型,取而代之的是 var。 或许,这个简单的例子你觉得也没什么,但在真实的项目中,很多代码会出现层层嵌套的情况,比如,下面就是一个 Map 套 Map 的情况: 用 var 就可以简化一些: 下面这段代码使用 var,优势就更明显了: 这是一段典型的 for-each 遍历集合元素的代码,在这里,entry 的类型是 Map.Entry<String, String>,使用 var 就会简化很多。 你现在已经了解了 var 的基本逻辑,就是根据上下文来推断类型信息。这样你就能知道,有些地方 var 是不能用的,比如,它不能用作方法参数和返回值,也不能当作成员变量,因为在这些情况下,没有供编译器推断的信息。所以,var 这个特性在 JEP(JDK Enhancement Proposal)中叫局部变量类型推断。 unsetunset实践 varunsetunset即便是局部变量,也有些情况 var 是不能用的,比如,未初始化的变量,或初始化为 null 的变量,总而言之,你看不出类型的地方,编译器也看不出。在这种情况下,var 就不能用。 问题来了,var 能不能和钻石操作符一起用呢?就像下面这样: 它们两个都是等着别人告诉自己类型信息,按道理来说,应该是不行的。但是,这段代码是可以通过编译的,只不过,编译器会按照最宽泛的类型进行推断,所以,它的类型本质上等价于 HashMap<Object, Object>,这个声明就回退到最原始的状态,完全颠覆掉了 Java 辛辛苦苦建立起的类型系统。所以,在实际的工作中,不要写这种代码。 有一点需要记住,用 var 声明的变量也是有类型的,我们可以把理解为编译器替我们声明了类型。一旦声明好了,它的类型就不能轻易改动了,所以,你会明白下面的代码错在哪了: 明白了这一点,你就可以理解一些不易察觉的错误: 请注意:obj 的类型是并不是 Object,而是这里声明的一个匿名类,所以,当我们用 Object 对象给它赋值时,就会出现问题。 var 的优点在于简化代码编写,所以,如果能让代码变得清晰,使用 var 就是好的,比如: 但如果需要别人猜测类型信息,var 就不是一个好的选择,比如: 所以,变量名就变得非常重要,它最好能够承载类型信息: unsetunset小结unsetunset类型推断本来是动态语言(比如 Python 和 Ruby 等)的强项,因为它们的类型往往是在运行时决定的。但更多人看到是类型推断可以简化代码的编写,随着编译技术的发展,越来越多的静态语言也开始把类型推断纳入到语言特性之中。当然,细微之处也是有差别的,比如,前面提到的用 var 声明的变量类型是不能改动的,而在动态语言里,这是可以的。 关于 var,我们讨论了这么多,都在说 var 在简化代码编写上起到的作用。但 var 本身并不是 Java 的关键字。这是向后兼容的考量,肯定有不少程序里已经有了作为变量名或函数名的 var。所以,如果你身处一个老项目,准备升级到 Java 10 以后的版本,先清理一下代码里的 var,以便更好地迎接真正 var 的到来。 查看详情:https://www.toutiao.com/article/7604470041899237888 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
|手机版|小黑屋|梦想之都-俊月星空
( 粤ICP备18056059号 )|网站地图
GMT+8, 2026-2-11 07:00 , Processed in 0.041849 second(s), 17 queries .
Powered by Mxzdjyxk! X3.5
© 2001-2025 Discuz! Team.