java8新特性--类型推断的理解(泛化目标类型推断)

简单理解泛型

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。通俗点将就是“类型的变量”。这种类型变量可以用在类、接口和方法的创建中。

理解Java泛型最简单的方法是把它看成一种便捷语法,能节省你某些Java类型转换(casting)上的操作:

List<Apple> box = new ArrayList<Apple>();

box.add(new Apple());

Apple apple =box.get(0); 

上面的代码自身已表达的很清楚:box是一个装有Apple对象的List。get方法返回一个Apple对象实例,这个过程不需要进行类型转换。没有泛型,

面的代码需要写成这样:Apple apple = (Apple)box.get(0); 

泛型的尴尬

泛型的最大优点是提供了程序的类型安全同时可以向后兼容,但也有尴尬的地方,就是每次定义时都要写明泛型的类型,这样显示指定不仅感觉有些冗长,最主要是很多程序员不熟悉泛型,因此很多时候不能够给出正确的类型参数,现在通过编译器自动推断泛型的参数类型,能够减少这样的情况,并提高代码可读性。

java7的泛型类型推断改进

在以前的版本中使用泛型类型,需要在声明并赋值的时候,两侧都加上泛型类型。例如:

Map<String, String> myMap = new HashMap<String, String>(); 

你可能觉得: 在声明变量的的时候已经指明了参数类型,为什么还要在初始化对象时再指定?幸好,在Java SE 7中,这种方式得以改进,现在可

以使用如下语句进行声明并赋值:Map<String, String> myMap = new HashMap<>(); //注意后面的"<>" 

在这条语句中,编译器会根据变量声明时的泛型类型自动推断出实例化HashMap时的泛型类型。再次提醒一定要注意new HashMap后面的“<>”,只

有加上这个“<>”才表示是自动类型推断,否则就是非泛型类型的HashMap,并且在使用编译器编译源代码时会给出一个警告提示。

但是:Java SE 7在创建泛型实例时的类型推断是有限制的:只有构造器的参数化类型在上下文中被显著的声明了,才可以使用类型推断,否则不行。例如:下面的例子在java 7无法正确编译(但现在在java8里面可以编译,因为根据方法参数来自动推断泛型的类型):

List<String> list = new ArrayList<>();   
    list.add("A");// 由于addAll期望获得Collection<? extends String>类型的参数,因此下面的语句无法通过   
    list.addAll(new ArrayList<>());   

Java8的泛型类型推断改进

java8里面泛型的目标类型推断主要2个:

1.支持通过方法上下文推断泛型目标类型

2.支持在方法调用链路当中,泛型类型推断传递到最后一个方法

我们来看看过去泛型使用的示例:

classList<E> {
  static<Z> List<Z> nil() {..}
  static<Z> List<Z> cons(Z head, List<Z> tail) {..}
  E head() {..}
}

在上述例子,在JEP:101中声称可以用下面的方法更好地表示:

// 建议写法:
List.cons(42, List.nil());
String s = List.nil().head();
 
// 不推荐的写法:
List.cons(42, List.<Integer>nil());
String s = List.<String>nil().head();

着实令人激动。这些令人兴奋的变化究竟包含了什么?让我来更加详细地说明:
// 通过赋值语句推断泛型的类型
List<String> l = List.nil();
 
// 更好的办法是让编译器从函数的参数类型中直接推断
List.cons(42, List.nil());
 
// 或者从“链式调用”中推断
String s = List.nil().head();
因此在上面的链式方法调用中,会延迟到整个赋值表达式完成时才进行类型推断。通过赋值语句左边,编译器会为head()调用推断;为String。然后,再次推断nil()调用的String 。 在我看来这真的很神奇。 对nil() 方法的AST计算会延迟到“关联”子节点计算时才最后完成。
这是一个很棒的主意,不是吗?
自己的测试:

package generics;
class List<E> {
	  static <Z> List<Z> nil() {
		return null;}
	  static <Z> List<Z> cons(Z head, List<Z> tail) {
		return tail;}
	  E head() {
		return null;}
	}
public class InferenceTest {
	public static void main(String[] args) {
        List<String> ls = List.nil();
        List.cons(42, List.nil());
        String s = List.nil().head();
    }
}


基于该方法参数的类型推断已经实现了(因此编译通过了),但是链式方法调用中的类型推断还没有实现。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值