Java高级特性-泛型类型推断

Java高级特性-泛型类型推断

Java泛型类型推导是Java 7中引入的一种新特性,指 Java 编译器根据上下文推断出泛型类型参数的类型。

类型推导的目的

类型推导的目的是简化泛型编程,减少代码中的冗余。在 Java 7 之前,需要在定义泛型类型或调用泛型方法时显式指定泛型类型。使用类型推导后,可以让编译器根据上下文推断出泛型类型的实际类型,从而简化代码。

Java 7 以前的要创建一个列表类型:

List<String> list = new ArrayList<String>();

在有了类型推到后,上面的代码可以改写为:

List<String> list = new ArrayList<>();

类型推导和泛型方法

类型推导使得一个泛型方法的调用就像普通方法调用一样,可以省略尖括号(<>)。

public class BoxDemo {

  public static <U> void addBox(U u, java.util.List<Box<U>> boxes) {
    Box<U> box = new Box<>();
    box.set(u);
    boxes.add(box);
  }

  public static <U> void outputBoxes(java.util.List<Box<U>> boxes) {
    int counter = 0;
    for (Box<U> box: boxes) {
      U boxContents = box.get();
      System.out.println("Box #" + counter + " contains [" +
             boxContents.toString() + "]");
      counter++;
    }
  }

  public static void main(String[] args) {
    java.util.ArrayList<Box<Integer>> listOfIntegerBoxes =
      new java.util.ArrayList<>();
    BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes);
    BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes);
    BoxDemo.addBox(Integer.valueOf(30), listOfIntegerBoxes);
    BoxDemo.outputBoxes(listOfIntegerBoxes);
  }
}

上述代码中,BoxDemo.addBox(Integer.valueOf(10), listOfIntegerBoxes);调用泛型方法时显示指定了类型参数为 Integer。紧接着的下面2行代码并没有显示指定类型参数类型,但不影响执行结果,因为在方法调用时,Java编译器使用类型推导根据参数类型可以指导泛型方法的类型参数的类型。

泛型类的类型推导和实例化

泛型类的推导规则

  • 如果泛型类只有一个泛型类型参数,则编译器会将该参数的类型作为泛型类型的实际类型。
  • 如果泛型类有多个泛型类型参数,则编译器会根据参数之间的关系推导出泛型类型的实际类型。
  1. 泛型类只有一个泛型类型参数,则编译器会将该参数的类型作为泛型类型的实际类型。

    public class MyClass<T> {
      public void doSomething(T t) {
        System.out.println(t);
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        MyClass<Integer> myClass = new MyClass<>();
        myClass.doSomething(10); // 编译器推导出泛型类型的实际类型是Integer
    
        // 使用类型推导
        MyClass myClass2 = new MyClass();
        myClass2.doSomething("Hello, world!"); // 编译器推导出泛型类型的实际类型是String
      }
    }
    

    这个示例代码中,myClass实例创建时指定了类型参数是Integer,编译器推导出泛型类型参数的实际类型是IntegermyClass2示例的创建会引发Java编译器报错,因为语句MyClass myClass2 = new MyClass();使用的是原始类型,未指定明确的类型,因此泛型类MyClass中类型参数 T 在编译时变为 Object 被对待,在语句myClass2.doSomething(“Hello, world!”);进行方法调用时,传入的参数类型是String,编译时给出的信息有所不同。

    在IDEA中给出的是 unchecked call 警告。

    Unchecked call to 'doSomething(T)' as a member of raw type '...MyClass'
    

    在vscode提示类型安全提示。

    Type safety: The method doSomething(Object) belongs to the raw type MyClass. References to generic type MyClass<T> should be parameterized
    
  2. 泛型类有多个泛型类型参数,则编译器会根据参数之间的关系推断出泛型类型的实际类型。

    public class MyClass<T, U> {
      public void doSomething(T t, U u) {
        // 编译器会根据参数之间的关系推断出泛型类型的实际类型
        System.out.println(t);
        System.out.println(u);
      }
    }
    
    public class Main {
      public static void main(String[] args) {
        MyClass<Integer, String> myClass = new MyClass<>();
        myClass.doSomething(10, "Hello, world!"); // 编译器推导出泛型类型的实际类型是Integer和String
    
        // 使用类型推导
        MyClass myClass2 = new MyClass();
        myClass2.doSomething(10, "Hello, world!"); // 编译器推导出泛型类型的实际类型是Integer和String
      }
    }
    

类型推导有以下几个注意事项:

  • 类型推导只能在编译时进行,不能在运行时进行。
  • 类型推导不能推断出原始类型。
  • 类型推导不能推断出通配符类型。(通配符后面文章讲述)

目标类型

Java 编译器利用目标类型在泛型方法调用时推导类型参数。拿Collections.emptyList()方法举例,它的声明

static <T> List<T> emptyList();

使用这个方法来进行赋值:

List<String> listOne = Collections.emptyList();

这面这个赋值语句中期望的类型是List,而Collections.emptyList()方法返回的数据类型是List,这里Java编译器会推导类型TString。这在Java 7和Java 8中都可以通过编译。或者使用显示的类型指名需要的类型。

List<String> listOne = Collections.<String>emptyList();

但不是所有情况下都能通过编译。

void processStringList(List<String> list) {
    // ...
}

在Java 7中,向方法中传入Collections.emptyList()就无法通过编译。

提示的错误信息类似:List cannot be converted to List。因为Collections.emptyList()方法返回的数据类型List不是List的子类型,无法转换。因此Java 7中使用上面的方法时需要显示执行泛型类型。

这种情况,在Java 8中不再需要显示指定泛型类型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VoidHope

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值