资讯专栏INFORMATION COLUMN

Java™ 教程(类型推断)

JerryC / 2803人阅读

类型推断

类型推断是Java编译器查看每个方法调用和相应声明的能力,以确定使调用适用的类型参数,推理算法确定参数的类型,如果可用,还确定分配或返回结果的类型,最后,推理算法尝试查找适用于所有参数的最具体类型。

为了说明最后一点,在下面的示例中,推断确定传递给pick方法的第二个参数是Serializable类型:

static  T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList());
类型推断和泛型方法

泛型方法向你介绍了类型推断,它使你能够像普通方法一样调用泛型方法,而无需在尖括号之间指定类型,考虑以下示例BoxDemo,它需要Box类:

public class BoxDemo {

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

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

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

以下是此示例的输出:

Box #0 contains [10]
Box #1 contains [20]
Box #2 contains [30]

泛型方法addBox定义了一个名为U的类型参数,通常,Java编译器可以推断泛型方法调用的类型参数,因此,在大多数情况下,你不必指定它们,例如,要调用泛型方法addBox,可以使用类型见证指定类型参数,如下所示:

BoxDemo.addBox(Integer.valueOf(10), listOfIntegerBoxes);

或者,如果省略类型见证,Java编译器会自动推断(从方法的参数)类型参数是Integer

BoxDemo.addBox(Integer.valueOf(20), listOfIntegerBoxes);
类型推断和泛型类的实例化

只要编译器可以从上下文中推断出类型参数,就可以用一组空的类型参数(<>)替换调用泛型类的构造函数所需的类型参数,这对尖括号被非正式地称为菱形。

例如,请考虑以下变量声明:

Map> myMap = new HashMap>();

你可以使用一组空的类型参数(<>)替换构造函数的参数化类型:

Map> myMap = new HashMap<>();

请注意,要在泛型类实例化期间利用类型推断,必须使用菱形,在以下示例中,编译器生成未经检查的转换警告,因为HashMap()构造函数引用HashMap原始类型,而不是Map>类型:

Map> myMap = new HashMap(); // unchecked conversion warning
类型推断和泛型与非泛型类的泛型构造函数

请注意,构造函数在泛型和非泛型类中都可以是泛型的(换句话说,声明它们自己的形式类型参数),考虑以下示例:

class MyClass {
   MyClass(T t) {
    // ...
  }
}

考虑以下MyClass类的实例化:

new MyClass("")

此语句创建参数化类型MyClass的实例,该语句显式指定泛型类MyClass的形式类型参数X的类型Integer,请注意,此泛型类的构造函数包含形式类型参数T,编译器为此泛型类的构造函数的形式类型参数T推断类型String(因为此构造函数的实际参数是String对象)。

Java SE 7之前版本的编译器能够推断泛型构造函数的实际类型参数,类似于泛型方法,但是,如果使用菱形(<>),Java SE 7及更高版本中的编译器可以推断出要实例化的泛型类的实际类型参数,考虑以下示例:

MyClass myObject = new MyClass<>("");

在此示例中,编译器为泛型类MyClass的形式类型参数X推断类型Integer,它推断出此泛型类的构造函数的形式类型参数T的类型String

值得注意的是,推理算法仅使用调用参数、目标类型以及可能明显的预期返回类型来推断类型,推理算法不使用程序后面的结果。
目标类型

Java编译器利用目标类型来推断泛型方法调用的类型参数,表达式的目标类型是Java编译器所期望的数据类型,具体取决于表达式的显示位置,考虑方法Collections.emptyList,声明如下:

static  List emptyList();

考虑以下赋值语句:

List listOne = Collections.emptyList();

此语句期望List的实例,此数据类型是目标类型,因为方法emptyList返回List类型的值,所以编译器推断类型参数T必须是值String,这适用于Java SE 7和8,或者,你可以使用类型见证并指定T的值,如下所示:

List listOne = Collections.emptyList();

但是,在这种情况下,这不是必需的,不过,在其他情况下这是必要的,考虑以下方法:

void processStringList(List stringList) {
    // process stringList
}

假设你要使用空列表调用方法processStringList,在Java SE 7中,以下语句不编译:

processStringList(Collections.emptyList());

Java SE 7编译器生成类似于以下内容的错误消息:

List cannot be converted to List

编译器需要类型参数T的值,因此它以值Object开始,因此,Collections.emptyList的调用返回List类型的值,该值与方法processStringList不兼容,因此,在Java SE 7中,你必须指定类型参数值的值,如下所示:

processStringList(Collections.emptyList());

Java SE 8中不再需要这样做,什么是目标类型的概念已经扩展为包括方法参数,例如方法processStringList的参数,在这种情况下,processStringList需要一个List类型的参数,方法Collections.emptyList返回List的值,因此使用List的目标类型,编译器推断类型参数T的值为String,因此,在Java SE 8中,以下语句编译:

processStringList(Collections.emptyList());

有关详细信息,请参阅Lambda表达式中的目标类型。

上一篇:泛型、继承和子类型 下一篇:泛型通配符

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72919.html

相关文章

  • Java教程(泛型类型

    泛型类型 泛型类型是通过类型参数化的泛型类或接口,修改以下Box类以演示此概念。 一个简单的Box类 首先检查一个对任何类型的对象进行操作的非泛型Box类,它只需要提供两个方法:set,它将一个对象添加到box中,get,它将检索它: public class Box { private Object object; public void set(Object object) ...

    Crazy_Coder 评论0 收藏0
  • Java 10 实战第 1 篇:局部变量类型推断

    摘要:就等于局部变量类型推断使用示例既然叫局部变量类型推断,以只能用在局部变量中,下面给出更多使用示例。,本次局部变量类型推断实战文章就到这里了,后续带来更多的的实战方面的文章。 现在 Java 9 被遗弃了直接升级到了 Java 10,之前也发过 Java 10 新特性的文章,现在是开始实战 Java 10 的时候了。 今天要实战的是 Java 10 中最重要的特性:局部变量类型推断,大家...

    HollisChuang 评论0 收藏0
  • Java教程(泛型通配符捕获和Helper方法)

    泛型通配符捕获和Helper方法 在某些情况下,编译器会推断出通配符的类型,例如,列表可以定义为List,但是在评估表达式时,编译器会从代码中推断出特定类型,此场景称为通配符捕获。 在大多数情况下,你不必担心通配符捕获,除非你看到包含短语capture of的错误消息。 WildcardError示例在编译时产生捕获错误: import java.util.List; public class ...

    ChristmasBoy 评论0 收藏0
  • Java教程(泛型方法)

    泛型方法 泛型方法是引入其自己的类型参数的方法,这类似于声明泛型类型,但类型参数的范围仅限于声明它的方法,允许使用静态和非静态泛型方法,以及泛型类构造函数。 泛型方法的语法包括类型参数列表,在尖括号内,它出现在方法的返回类型之前,对于静态泛型方法,类型参数部分必须出现在方法的返回类型之前。 Util类包含一个泛型方法compare,它比较两个Pair对象: public class Util { ...

    PingCAP 评论0 收藏0
  • Java 11 教程

    摘要:原文链接已于成功发布,不过目前绝大多数人在生产环境仍旧使用的是。这篇以案例为主的教程涵盖了从到的绝大多数重要的语法与特性。当编译器不能正确识别出变量的数值类型时,将不被允许使用。同步请求将会阻塞当前的线程,直到返回响应消息。 showImg(https://segmentfault.com/img/remote/1460000016575203); 原文链接:https://wangw...

    douzifly 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<