Java 5 引入了泛型,这是一次重大的改进,从此集合中的东西不需要每次显式的去转型。不过 Java 5 还不具备类型推断的能力,所以声明泛型必须写成
List<String> list = new ArrayList<String>();
一直到 Java 6 也是如此。自 Java 7 起泛型增强为可根据声明类型进行推断,所以 Java 7 中可以这么写
List<String> list = new ArrayList<>(); //<> 中的参数可省略,如果类型参数多, 或多层嵌套时很省事
或
List<String> list = Collections.emptyList(); //见 Java 泛型 -- 依据声明的变量类型自动推断
Java 8 开始对泛型类型推断又进一步增强:可根据方法上下文进行推断,例如下面的代码在 Java 7 下编译不过
1 2 |
List<String> list = new ArrayList<>(); list.addAll(new ArrayList<>()); //根据 list.addAll() 上下文推断要创建的类型是 new ArrayList<String>() |
报编译错误:
Test.java:10: error: no suitable method found for addAll(ArrayList<Object>)
list.addAll(new ArrayList<>());
^
method List.addAll(int,Collection<? extends Integer>) is not applicable
(actual and formal argument lists differ in length)
method List.addAll(Collection<? extends Integer>) is not applicable
(actual argument ArrayList<Object> cannot be converted to Collection<? extends Integer> by method invocation conversion)
method Collection.addAll(Collection<? extends Integer>) is not applicable
(actual argument ArrayList<Object> cannot be converted to Collection<? extends Integer> by method invocation conversion)
1 error
也就 addAll() 的参数 new ArrayList<>() 无法推断出类型,被假定类型为默认的 Object, 所以无法把 ArrayList<Object> 加到 List<String> 中去。
但是用 Java 8 编译上面的代码是没问题的,也就是 Java 8 在编译 list.addAll(new ArrayList<>()) 推断为 list.addAll(new ArrayList<String>()),即通过方法参数上下文推断出实际创建的类型。
上面的代码有还一种很怪异的写法
1 2 |
List<String> list = new ArrayList<>(); list.addAll(new <String>ArrayList()); //不能写成 new <String>ArrayList<>() |
不过不管是 Java 7 还是 Java 8 编译这段代码都会有警告
Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
就像是写成 List<String> list = new ArrayList() 省略了 <> 一样的编译警告。但基本可以保证我们没有机会搞出 new <String>ArrayList() 这种玩法。
最后一句,其实可别忽视了 Java 8 对类型推断的增强,它的主要工作重点是在如何根据上下文, 把一个 Lambda 表达式经由 SAM 的映射关系, 推断出对就的对象类型来。
本文链接 https://yanbin.blog/java-8-generic-enhance/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
Nice work.