【问题标题】:Java genericsJava 泛型
【发布时间】:2009-03-11 17:52:35
【问题描述】:

我想实现一个将Object 作为参数的方法,将其转换为任意类型,如果失败则返回null。到目前为止,这是我所拥有的:

public static void main(String[] args) {
    MyClass a, b;
    a = Main.<MyClass>staticCast(new String("B"));
}

public static class MyClass {
}

public static <T> T staticCast(Object arg) {
    try {
        if (arg == null) return null;
        T result = (T) arg;
        return result;
    } catch (Throwable e) {
        return null;
    }
}

不幸的是,类转换异常从未在staticCast() 函数的主体中抛出/捕获。 Java 编译器似乎生成了函数String staticCast(Object arg),其中有一行String result = (String) arg;,尽管我明确说模板类型应该是MyClass。有什么帮助吗?谢谢。

【问题讨论】:

  • 顺便说一句,您应该只捕获 ClassCastException,而不是 Throwable。捕获 Throwable 可能会导致严重问题。

标签: java generics casting


【解决方案1】:

因为泛型类型信息在运行时会被删除,所以转换为泛型类型的标准方法是使用 Class 对象:

public static <T> T staticCast(Object arg, Class<T> clazz) {
    if (arg == null) return null;
    if (!clazz.isInstance(arg))
        return null;
    T result = clazz.cast(arg);
    return result;
}

然后这样称呼它:

a = Main.staticCast("B", MyClass.class);

【讨论】:

  • 使用 Class.isInstance 会更直接。
  • 嗯,笨蛋?是不是像个班?
  • isInstance 仅在对象是 clazz 的实例时才有效,如果它是 clazz 的子类则无效。 isAssignableFrom 将适用于任何可以转换为 clazz 的东西,甚至是子类。
  • @Paul:Javadocs 说,“此方法是 Java 语言 instanceof 运算符的动态等效项。如果指定的 Object 参数为非 null 并且可以转换为引用类型,则该方法返回 true由这个 Class 对象表示,而不引发 ClassCastException。"
【解决方案2】:

你不能做你想做的事……至少不能这样。编译器删除了所有信息,因此您最终将 (T) 变成了演员表中的 Object - 这很有效。

问题是你稍后会做 MyClass = (String)object;这是不允许的。

您已绕过编译器检查并使其在运行时失败。

那么,您到底想要做什么?如果您告诉我们为什么要这样做,我们可能会告诉您 Java 的做法。

根据您的评论,您可以尝试以下操作:

public class Main
{
    public static void main(String[] args)
    {
        String a;
        MyClass b;
        a = staticCast(new String("B"), String.class);
        b = staticCast(new String("B"), MyClass.class);
        System.out.println(a);
    }

    public static class MyClass
    {
    }

    public static <T> T staticCast(Object arg, final Class clazz)
    {
        // edit - oops forgot to deal with null...
        if(arg == null)
        {
            return (null);
        }

        // the call to Class.cast, as mmeyer did, might be better... probably is better... 
        if(arg.getClass() != clazz)
        {
            // Given your answer to Ben S...
            return (null);

            // throw new ClassCastException("cannot cast a " + arg.getClass() + " to a " + clazz);
        }

        return ((T)arg);
    }
}

【讨论】:

  • 我明白了,所以 T 是演员表中的一个对象。我希望每个 T 有一个单独的方法,它将参数转换为 (T),如果失败,则会捕获异常而不抛出异常。根据 Paul Tomblin(下文)的说法,这不会发生。
【解决方案3】:

你的意思是Class&lt;T&gt;.cast(Object obj)

类似:

Class.forName("YourClass").cast(obj);

应该做你想做的。

请注意,这很臭,可能是设计不佳的标志。

【讨论】:

  • 谢谢。问题是如果失败,这将抛出类转换异常。它与代码相同: (YourClass) 对象,并且每次使用该行代码时都必须检查错误引发的异常。我想在 cast() 方法中捕获并隐藏该异常。
  • 你想要 asSubclass 还是 getConstructor().newInstance().cast?
【解决方案4】:

不要将 Java 泛型误认为 C++ 模板。只会有一个使用不同类型擦除调用的 staticCast 方法,而不是每个 T 一个。

根本不使用泛型,我会这样写:

public static void main(String[] args) {
    MyClass a, b;
    a = (MyClass)Main.staticCast(new String("B"), MyClass.class);
}

public static class MyClass {
}

public static staticCast(Object arg, Class class) {
        if (arg != null && class.isAssignableFrom(arg))
          return arg;
        return null;
}

或者从另一个答案中窃取,使用泛型:

public static <T> T staticCast(Object arg, Class<T> class) {
        if (arg != null && class.isAssignableFrom(arg))
        {
           T result = class.cast(arg);
           return result;
        }
        return null;
}

【讨论】:

  • 我忘记了 CCE 是一个 RuntimeException 并且不需要 catch 块,或者我本来会像你的第二种方法那样做。
  • 你能详细说明为什么 Java 编译器不生成函数 MyClass staticCast(Object arg);当我在该行中明确指定类型 T 时: a = Main.staticCast(new String("B"));我明确告诉它......我认为链接到一些阅读会很棒。
  • @Budric:试试java.sun.com/docs/books/tutorial/java/generics/erasure.html。此外,搜索标记为 [java] [generics] 的问题。周围有一些非常有趣的。
  • isAssignableFrom 应该是isInstance,不需要检查是否为null。
  • 如果我错了,请纠正我,但我认为 isAssignableFrom 会找到给定类的子类,而不仅仅是那种类型的子类?
【解决方案5】:

我同意 Ben 的观点,但是,我更喜欢以下表示法:

MyClass.class.cast(obj);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    • 2010-12-18
    相关资源
    最近更新 更多