【问题标题】:Type-safe way to cast object to Class将对象转换为 Class 的类型安全方法
【发布时间】:2016-04-02 12:23:27
【问题描述】:

我想取消对未经检查的转换警告的抑制。我怎样才能完全保证将o 转换为T

注意:此 sn-p 中的 ResultSet 是与源无关的专有包装器。它与 java.sql.ResultSet 非常相似,但又不一样。此外,将 Eclipse Mars.1 与 Java 8 u45 一起使用,IDE 和 javac 都会发出警告。我意识到,由于它包含在 if 声明中,因此从技术上讲这不是问题,但我绝对讨厌压制警告。而且我觉得必须有一种完全类型安全的方式来执行这种转换。

public class ResultSetQuery {
    public static <T> List<T> collectValues(ResultSet rs, String keyName, Class<T> tclass) {

        List<T> result = new LinkedList<>();

        while(rs.next()) {
            Object o = rs.getData(keyName);

            if (tclass.isAssignableFrom(o.getClass())) {

                @SuppressWarnings("unchecked")
                T v = (T)o;

                result.add(v);
            } else {
                result.add(null);
            }
        }

        return result;
    }
}

【问题讨论】:

  • 你为什么要打扰?测试isAssignableFrom 确保强制转换不会失败,因此理论上编译器可能足够聪明,不会发出警告,但无论如何抑制警告是安全的。
  • ResultSet 是来自java.sql 包吗?我在官方文档中没有找到getData方法。
  • while (rs.next()) 可以抛出SQLException,因此您需要在方法中声明throws SQLException,或者用while 代码包围try-catch。 --- rs.getData(keyName)java.sql.ResultSet,对吧?验证.getData(String)方法是否存在;因为看起来没有。也许您的意思是 getDate
  • @wero 我不知道其他编译器,但是 NetBeans (8) 使用的 JDK, 足够聪明,不会发出一个警告。 =)
  • @AlmightyR 很有趣。我尝试使用 JDK 8 中的javac,但它会抱怨。 NetBean 不使用javac?。

标签: java casting type-conversion


【解决方案1】:

你可以写:

            if (tclass.isAssignableFrom(o.getClass())) {
                result.add(tclass.cast(o));
            }

(见https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#cast(java.lang.Object)。)


编辑添加:顺便说一句,正如埃里克森在评论中指出的那样,您可能应该写 tclass.isInstance(o) 而不是 tclass.isAssignableFrom(o.getClass()):它更简单、更清晰,并且在 @ 时避免了 NullPointerException 987654325@ 为空。

【讨论】:

  • 删除警告并完成我打算做的事情。这么简单!
  • @liltitus27:你的评论让我很难过。您现在有 2 个本机方法调用而不是 1 个,并且转换仍然存在于 Class#cast 中。眼不见,心不烦。
  • @liltitus27 真的吗?为什么?我在该答案中看不到任何支持您使用isAssignableFrom() 的内容。你有一个对象。您想测试它是否是特定类型的实例。这正是isInstance() 的功能。 isAssignableFrom() 是做同样事情的迂回方式,并且该迂回包括NullPointerException 的可能性。
  • @liltitus27:我认为你没有“惹恼 [erickson]”。我认为他/她的评论表达了困惑而不是愤怒。 (FWIW,我也有同样的困惑。你链接到的答案解释了这个用例是 isInstance 的确切目的,我不明白你怎么能以不同的方式解释它。)
  • @liltitus27 是的,ruakh 是对的,我没有生气,只是感到困惑。链接答案的段落,“... obj is an instance of MyClass or its subclasses...” 意味着 obj “is-a” MyClass---它要么是 MyClass 要么实现或扩展MyClass。在您想要编写的静态类型代码中:if (o instanceof T) result.add((T) o);,对吧? isInstance() 方法是反射等效方法:当目标 Class 是由参数实现的接口或者是参数的超类时,它返回 true
【解决方案2】:

您不盲目地使编译器警告静音的意图是值得尊敬的,但您的代码示例是合理使用 @SupressWarnings 的一个很好的示例。您的代码不会失败,编译器仍然会抱怨,因此@SupressWarnings 是要走的路。

查看java.lang.Class#cast,它与您的示例具有相同的模式。它还抑制了警告:

@SuppressWarnings("unchecked")
public T cast(Object obj) {
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}

【讨论】:

  • 好的,这就是我的预期。我想看看社区是否知道在不抑制警告的情况下处理该问题的方法,但是您的示例很明显地表明这种方法是可以的。感谢您的意见!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-15
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
相关资源
最近更新 更多