2015-10-22 34 views
7

我的代码:即使我知道它正确返回,为什么我必须转换为泛型类型T?

private static <T> T get(Class<T> clazz) throws IllegalAccessException, InstantiationException { 
     if (clazz.equals(String.class)) { 
      return (T) new String("abc");//line x 
     } else { 
      return clazz.newInstance(); 
     } 

    } 

正如你看到的,在line xT必须String.class并返回String。但编译失败而不会将结果投射到T

变化line x变为return new String("abc");结果Incompatible types

+1

这实际上不是模板的意思。当然,对你来说显然它会一直返回类型T的东西 - 但是编译器很明显吗?如果T不是字符串,仍然有一些途径(可以访问或不可访问)返回错误的类型。 – JArkinstall

回答

5

编译器没有考虑到if语句。

所以它看到的是,你需要返回一个T(其中没有进一步的知识)。它并没有推断这里T必须是String

可避免你做

return clazz.cast("abc"); 
+0

这不会产生相同的结果。 OP的代码每次都会创建一个String的新实例,但是您的代码每次都返回相同的(被阻止的)String。也许'clazz.cast(new String(“abc”));'还应该注意的是调用cast()仍然涉及不安全的强制转换,但它被埋在了cast方法中。 – Bohemian

+0

@ Bohemian:我静静地自动修改了'new String()'部分。在大多数情况下,你不需要一个新的String实例。 'cast'在这里并不是不安全的,因为'if'语句已经检查过类型兼容性(这是这个问题的关键,我认为其他一些语言有更强的类型推断,将这种条件考虑在内)。 – Thilo

+0

对不起 - 由“不安全”我并不是说从实际的角度来看是不安全的,而是编译器认为它是不安全的并产生警告。具体来说,'cast()'方法会返回(T)obj;'并用'@SuppressWarnings(“unchecked”)进行注释' - 调用'cast()'只是将* *代码中的警告推入JDK的(我很酷 - 我经常合理地使用这种模式)。 – Bohemian

1

的原因是,你不能施放字符串对每个类别获得了“未投地擦除型”的警告。想想T是一个Number类,那你会抛出一个ClassCastException。

您可以尝试使用此方法解决问题:

return (T) ((Object) new String("abc")); 
0

可以避开投如下:

if (clazz.equals(String.class)) { 
    return clazz.getDeclaredConstructor(String.class).newInstance("abc"); 
} 
return clazz.newInstance(); 

你必须赶上(和忽略)少数例外。

相关问题