代码之家  ›  专栏  ›  技术社区  ›  Henry B

类泛型的类型不匹配

  •  20
  • Henry B  · 技术社区  · 16 年前

    我有以下代码无法编译,尽管有一种方法可以让它编译,但我想了解它为什么不编译。有人能告诉我为什么我会收到我最后会发布的错误消息吗?

    public class Test {
        public static void main(String args[]) {
            Test t = new Test();
            t.testT(null);
        }
    
        public <T extends Test> void testT(Class<T> type) {
            Class<T> testType = type == null ? Test.class : type; //Error here
            System.out.println(testType);
        }
    }
    

    Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>

    通过铸造 Test.class Class<T> 这与 Unchecked cast 警告,运行良好。

    3 回复  |  直到 11 年前
        1
  •  23
  •   laz    11 年前

    原因是test.class属于类型class<test>。不能将类型class<test>的引用分配给类型class<t>的变量,因为它们不是同一回事。然而,这是有效的:

    Class<? extends Test> testType = type == null ? Test.class : type;
    

    通配符允许将类<t>和类<test>引用分配给testtype。

    有大量关于Java泛型行为的信息。 Angelika Langer Java Generics FAQ . 我将根据使用 Number 类继承了Java的核心API。

    考虑以下方法:

    public <T extends Number> void testNumber(final Class<T> type)
    

    这将允许成功编译以下语句:

    testNumber(Integer.class);
    testNumber(Number.class);
    

    但以下内容无法编译:

    testNumber(String.class);
    

    现在考虑这些陈述:

    Class<Number> numberClass = Number.class;
    Class<Integer> integerClass = numberClass;
    

    第二行未能编译并产生此错误 Type mismatch: cannot convert from Class<Number> to Class<Integer> . 但是 Integer 延伸 ,那为什么失败了?请看下面的两个语句,了解原因:

    Number anumber = new Long(0);
    Integer another = anumber;
    

    很容易理解为什么第二行不能在这里编译。无法分配的实例 到类型的变量 整数 因为没有办法保证 实例的类型兼容。在这个例子中, 实际上是 Long ,它当然不能分配给 整数 . 实际上,错误也是类型不匹配: Type mismatch: cannot convert from Number to Integer .

    规则是不能将实例分配给实例类型的子类变量,因为不能保证该变量是兼容的。

    仿制药的行为方式相似。在泛型方法签名中, T 只是一个占位符,用于指示该方法允许编译器使用什么。当编译器遇到 testNumber(Integer.class) 它基本上取代了 T 具有 整数 .

    通配符增加了额外的灵活性,因为下面将编译:

    Class<? extends Number> wildcard = numberClass;
    

    自从 Class<? extends Number> 表示任何类型 这是完全合法的,在许多情况下可能有用。

        2
  •  4
  •   erickson    16 年前

    假设我扩展测试:

    public class SubTest extends Test {
      public static void main(String args[]) {
        Test t = new Test();
        t.testT(new SubTest());
      }
    }
    

    现在,当我调用 testT ,类型参数 <T> SubTest ,这意味着变量 testType 是一个 Class<SubTest> . Test.class 属于类型 Class<Test> ,不能分配给类型为的变量 类<子测试> .

    声明变量 测试类型 作为一个 Class<? extends Test> 是正确的解决方案;铸造 Class<T> 隐藏着一个真正的问题。

        3
  •  1
  •   Ken    16 年前

    去掉条件,错误就更好了…

    public class Test {
        public static void main(String args[]) {
            Test t = new Test();
            t.testT(null);
        }
    
        public <T extends Test> void testT(Class<T> type) {
        Class<T> testClass = Test.class;
            System.out.println(testClass);
        }
    }
    
    
    Test.java:10: incompatible types
    found   : java.lang.Class<Test>
    required: java.lang.Class<T>
            Class<T> testClass = Test.class;