北京时间 3 月 21 日, Oracle 官方宣布 Java 10 正式发布这是 Java 大版本周期变化后的第一个正式发布版本关于 Java 10 , 最值得程序员关注的一个新特性恐怕就是本地变量类型推断 (local-variable type inference) 了
Java 10 推出之后, 很多文章也随之出来了, 告诉我们有哪些特性, 告诉我们本地变量类型推断怎么用但是, 知其然, 要知其所以然
Java 10 发布之后, 我第一时间下载了这个版本的 Jdk 并安装到我的电脑中, 然后写了一段代码, 并尝试着进行了反编译, 真正的感受一下本地变量推断到底如何这篇文章简单来谈一下我的感受
原理
关于本地变量类型推断的用法, 我的 Java 10 将于本月发布, 它会改变你写代码的方式中有介绍过主要可以用在以下几个场景中:
public class VarDemo { public static void main(String[] args) { // 初始化局部变量 var string = "hollis"; // 初始化局部变量 var stringList = new ArrayList<String>(); stringList.add("hollis"); stringList.add("chuang"); stringList.add("weChat:hollis"); stringList.add("blog:http://www.hollischuang.com"); // 增强 for 循环的索引 for (var s : stringList){ System.out.println(s); } // 传统 for 循环的局部变量定义 for (var i = 0; i <stringList.size(); i++){ System.out.println(stringList.get(i)); } }}
然后, 使用 java 10 的 javac 命令进行编译:
/Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home/bin/javac VarDemo.java
生成 VarDemo.class 文件, 我们对 VarDemo.class 进行反编译用 jad 进行反编译得到以下代码:
public class VarDemo{ public static void main(String args[]) { String s = "hollis"; ArrayList arraylist = new ArrayList(); arraylist.add("hollis"); arraylist.add("chuang"); arraylist.add("weChat:hollis"); arraylist.add("blog:http://www.hollischuang.com"); String s1; for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(s1)) s1 = (String)iterator.next(); for(int i = 0; i < arraylist.size(); i++) System.out.println((String)arraylist.get(i)); }}
这段代码我们就很熟悉了, 就是在 Java 10 之前, 没有本地变量类型推断的时候写的代码代码的对应关系如下:
本地变量类型推断写法 | 正常写法 |
---|---|
var string = "hollis"; | String string = "hollis"; |
var stringList = new ArrayList
| ArrayList
|
for (var s : stringList) | for (String s : stringList) |
for (var i = 0; i < stringList.size(); i++) | for (int i = 0; i < stringList.size(); i++) |
ArrayList arraylist = new ArrayList(); 其实是
ArrayList<String> stringList = new ArrayList<String>(); 解糖后, 类型擦除后的写法
for(Iterator iterator = arraylist.iterator(); iterator.hasNext(); System.out.println(s1)) 其实是 for (String s : stringList) 这种 for 循环解糖后的写法
所以, 本地变量类型推断, 也是 Java 10 提供给开发者的语法糖虽然我们在代码中使用 var 进行了定义, 但是对于虚拟机来说他是不认识这个 var 的, 在 java 文件编译成 class 文件的过程中, 会进行解糖, 使用变量真正的类型来替代 var(如使用 String string 来替换 var string)对于虚拟机来说, 完全不需要对 var 做任何兼容性改变, 因为他的生命周期在编译阶段就结束了唯一变化的是编译器在编译过程中需要多增加一个关于 var 的解糖操作
感兴趣的同学可以写两段代码, 一段使用 var, 一段不使用 var, 然后对比下编译后的字节码你会发现真的是完全一样的下图是我用 diff 工具对比的结果
语法糖(Syntactic Sugar), 也称糖衣语法, 是由英国计算机学家 Peter.J.Landin 发明的一个术语, 指在计算机语言中添加的某种语法, 这种语法对语言的功能并没有影响, 但是更方便程序员使用简而言之, 语法糖让程序更加简洁, 有更高的可读性
和 JavaScript 有啥区别
很多人都知道, 在 JavaScript 中, 变量的定义就是使用 var 来声明的所以, Java 10 的本地变量类型推断刚刚一出来, 就有人说了, 这不就是抄袭 JavaScript 的吗? 这和 JS 里面的 var 不是一样吗?
其实, 还真的不一样
首先, JavaScript 是一种弱类型 (或称动态类型) 语言, 即变量的类型是不确定的你可以在 JavaScript 中, 使用 5-4 这样的语法, 他的的结果是数字 1, 这里字符串和数字做运算了不信的话, 你打开你浏览器的控制台, 试一下:
但是, Java 中虽然可以使用 var 来声明变量, 但是它还是一种强类型的语言通过上面反编译的代码, 我们已经知道, var 只是 Java 给开发者提供的语法糖, 最终在编译之后还是要将 var 定义的对象类型定义成编译器推断出来的类型的
到底会不会影响可读性
本地变量类型推断最让人诟病的恐怕就是其可读性了, 因为在之前, 我们定义变量时候要明确指定他的类型, 所以在阅读代码的时候只要看其声明的类型就可以知道他的类型了, 但是全都使用 var 之后, 那就惨了毫无疑问, 这会损失一部分可读性的但是, 在代码中使用 var 声明对象同样也带来了很多的好处, 如代码更加简洁等
一个新东西刚刚出来之前, 总会有各种不习惯现在大家就会觉得这东西太影响我阅读代码的效率就像淘宝商城刚刚改名叫天猫的时候, 大家都觉得, 这是个什么鬼名字现在听习惯了, 是不是觉得还挺好的
如果大家都使用了 var 来声明变量以后, 那么变量的名字就更加重要了那时候大家就会更注重变量起名的可读性而且, 相信不久, 各大 IDE 就会推出智能显示变量的推断类型功能所以, 从各个方面, 都能弥补一些不足
总之, 对于本地变量类型推断这一特性, 我是比较积极的拥抱的
思考
最后, 再提出一个问题, 供大家思考, 本地变量类型推断看上去还是挺好用的, 而且, 既然 Java 已经决定在新版本中推出他, 那么为什么要限制他的用法呢现在已知的可以使用 var 声明变量的几个场景就是初始化局部变量增强 for 循环的索引和传统 for 循环的局部变量定义, 还有几个场景是不支持这种用法的, 如:
方法的参数
构造函数的参数
方法的返回值类型
对象的成员变量
那么, 我的问题是, Java 为什么做这些限制, 考虑是什么? 回答的靠谱的同学有奖励哦免费拉你进入我的知识星球关于这部分思考题的讨论及解答, 也会在知识星球进行
来源: https://juejin.im/entry/5ab308c2518825557005ea87