为什么这个编译没有任何未经检查的类型警告?

时间:2014-02-04 20:36:37

标签: java generics

为什么以下代码在没有任何警告的情况下干净地编译,即使使用xlint:all

class A<V> {

    public V v;

    public <V> A() {
    }

    public static <V> A<V> create() {
        return new A<V>();
    }
}


public class FooMain {

    public static void main(String args[]) {
        A.create().v = 5;
        A.create().v = "a string";
    }
}

运行:

javac -Xlint:all src/FooMain.java

导致编译干净而没有任何警告(未选中等)。在第一行创建的泛型类A实例的类型参数化是什么,第二行是什么?编译器如何确定类型?通过查看r值的类型?

2 个答案:

答案 0 :(得分:4)

在这两个语句中,编译器没有足够的信息来推断V的类型参数。发生这种情况时,默认为V的上限,即Object

分配有效,因为5"a string"都可以分配给Object

我们可以通过尝试将其分配给更具体的类型来证明A.create().v的类型为Object

Integer i = A.create().v; // Type mismatch: cannot convert from Object to Integer

错误是相同的,即使我们首先指定一个更具体的类型(赋值表达式的结果是指定变量的类型):

Integer i = (A.create().v = 5); // same error

请注意&#34;类型见证&#34;可用于显式指定泛型类型参数,如果它们没有被推断:

Integer i = A.<Integer>create().v; // valid

A.<String>create().v = 5;           // incompatible types
A.<Integer>create().v = "a string"; //

这些是用于演示编译器行为的人为例子,但类型证人偶尔会有用,for example

static void m(List<String> list) { }

public static void main(String args[]) {

    m(Collections.emptyList());         // error
    m(Collections.<String>emptyList()); // valid
}

答案 1 :(得分:1)

由于这两个陈述

A.create().v = 5;
A.create().v = "a string";

编译器可以通过<V>

轻松解决第一种情况<Integer>

,在第二种情况下<V><String>