铸造一个通用类。 (演员)vs Class.cast()

时间:2016-03-08 06:47:50

标签: java generics casting

我搜索了我的用例并找到了一些有趣的答案,但它们并不像我需要的那样合适。适当的方法是什么:

@SuppressWarnings("unchecked")
public <T> T newInstance(String name) throws ClassCastException, InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (T) loadClass(name).newInstance();
}

或稍微不同:

public <T> T newInstance(String name, Class<T> c) throws ClassCastException, InstantiationException, IllegalAccessException, ClassNotFoundException {
    return c.cast(loadClass(name).newInstance());
}

我认为这两种方法都是一样的。从我的观点来看,方法1因为参数较少而更好。两人都抛出一个ClassCastException对我来说没问题。确实,@SuppressWarnings("unchecked")注释并不好。

有人能告诉我一种方法对另一种方法有什么好处吗?

修改:Jon Skeet's answer是正确的。以下代码段可以提供额外的说明。

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        // Exception at c.cast(o)
        Test.<String>realCast(o, String.class);
    }

    private static <T> T realCast(Object o, Class<T> c) {
        return c.cast(o);
    }
}

realCast()无法转换为o时,使用c会产生异常。与fakeCast()相比,只给出了方法的结果类型为T的承诺。

2 个答案:

答案 0 :(得分:8)

  

我认为这两种方法都是一样的。

不,他们没有。因为在执行时,第一个代码不知道由type erasure引起的T类型。这意味着演员在方法中基本上什么都不做。 调用代码可能会隐式转换为它指定的T,但如果调用者是另一个泛型方法(此处使用T作为另一个类型参数),即使是不想要。

以下是一个简单的例子:

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        // No exception
        Test.<String>fakeCast(o);
        // Exception at the point of assignment:
        // the code is effectively String x = (String) ...;
        String x = Test.<String>fakeCast(o);
    }

    private static <T> T fakeCast(Object o) {
        return (T) o;
    }
}

第二个代码以T的形式知道Class<T>的类型,因此可以在执行时执行实际演员,正好你正在执行的那一点。

答案 1 :(得分:2)

韦恩(Jon Skeet)解释了答案。我想在此处添加示例,以便可以清楚地观察到差异

Class.cast()

public class Test{
      public static void main(String[] args){
            Object o = new Object();
            Test.castMethod(o, String.class); //Exception is thrown here
      }

      public static <T> T castMethod (Object o, Class<T> tClass){
             return tClass.cast(o)
      }
}

输出:

Exception in thread "main" java.lang.ClassCastException: Cannot cast java.lang.Object to java.lang.String
at java.base/java.lang.Class.cast
at com.test.Test.castMethod

Object.class对象向下广播到String.class是非法的,因为它们不兼容。

通过使用Class.cast()确实在castMethod()中进行了投射,因此抛出了ClassCastException这就是 Real Casting 如乔恩所说。


强制转换运算符

public class Test{
     public static void main(String[] args){
          Object o = new Object();
          Test.<String>castMethod(o); //No Exception
          String x = Test.<String>castMethod(o); //Exception is thrown here
     }
     public static <T> T castMethod(Object o){
          return (T) o;
     }
}

输出:

Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.Object cannot be cast to java.base/java.lang.String
at com.test.Test.main

从输出中,您可以看到ClassCastException被抛出到main(),而Class.cast()则将异常抛出到了castMethod()。这就是Jon将其命名为 Fake Casting 的原因,因为在castMethod的结果分配给String变量时,转换实际上是完成的。如果在调用castMethod的情况下忽略了结果,则不会看到任何异常。

此外,return (T) o会给短毛猫一个丑陋的Unchecked Cast警告