Java-泛型-类的显式转换和转换方法;类别<&燃气轮机&引用;

Java-泛型-类的显式转换和转换方法;类别<&燃气轮机&引用;,java,generics,casting,effective-java,Java,Generics,Casting,Effective Java,为什么对Class类使用cast方法会在编译时产生未检查的警告 如果查看cast方法内部,您会发现以下代码: public T cast(Object obj) { if (obj != null && !isInstance(obj)) throw new ClassCastException(cannotCastMsg(obj)); return (T) obj; // you can see there is a generic cast

为什么对
Class
类使用
cast
方法会在编译时产生未检查的警告

如果查看cast方法内部,您会发现以下代码:

public T cast(Object obj) 
{
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj; // you can see there is a generic cast performed here
}
如果我执行泛型转换,编译器会抱怨说存在
未选中的警告


其他背景资料 你可以在《有效Java 2版》第166页(pdf)中找到一个我如何解决这个问题的例子

作者编写了这段代码

public <T> T getFavorite(Class<T> type) 
{
    return type.cast(favorites.get(type));
}
public T getFavorite(类类型)
{
返回类型.cast(收藏夹.get(类型));
}
vs

public T getFavorite(类类型)
{
return(T)(favorites.get(type));
}

我不明白为什么编译器会抱怨未检查的警告。最后,这两段代码都显式转换了
(T)对象,不是吗?

为了加强内存安全,Java确保引用类型的变量实际上包含对该类型对象(或其子类型)的引用。强制转换指令可能违反此不变量,即我们可以写入:

Object o = new Integer(42);
String s = (String) o;  // compiles, but throws ClassCastException at runtime
为了防止这种情况,cast指令将检查引用的对象的类型,如果不是,则抛出ClassCastException

在将泛型引入Java语言之前,上述方法适用于所有类型转换。但是,对于使用类型擦除实现的泛型,运行时不知道类型参数代表哪个类,因此如果涉及类型参数,则无法执行此检查

这就是规范区分选中强制转换(只有在类型正确的情况下才会在运行时成功)和未选中强制转换(即使类型不正确也可能成功,导致堆污染,并且可能在以后出现类型错误)的原因。例如:

class C<T> {
    final T field;

    C(Object o) {
        this.field = (T) o; // unchecked. Will never throw a ClassCastException.
    }
}

boolean test() {
    C<String> c = new C<String>(42);
    return c.field.startsWith("hello"); // throws ClassCastException, even though there is no cast in the source code at this line!
}

这就是为什么当强制转换涉及类型参数时,反射强制转换比普通强制转换更可取的原因。

如果没有
@SuppressWarnings(“unchecked”)
注释,
java.lang.Class
的源代码将在编译期间产生警告。不会产生警告,因为JDK类位于已编译的库中。我相信自己编译JDK会产生一些警告

@Bohemian关于这是一个“官方乱码”的评论基本上是正确的,并且有很多这样的代码示例。(另一个例子是
java.lang.Enum#getDeclaringClass
)使用它是安全的,因为它所编写的逻辑是正确的,并且它是存在的,所以您不必自己编写这种难看的东西


我的建议是不要过多地考虑这个实现:重要的是
java.lang.Class#cast
符合选中cast的语义。

不是您正在铸造的类,而是
对象
…对不起,fge,我不明白。请考虑重新阅读这个问题。我添加了传统背景。谢谢在第一个代码段中,方法的参数是
对象
;在返回之前,您需要将其转换为正确的类型。好的,但是。。。我还是不明白:(.对不起,啊,当你说
@SuppressWarnings
注释在
cast()上不存在时,我也很怀疑。)
之前。虽然我不确定,但无论如何,你比我更正确。所以,有一个隐含的抑制警告@user3580294@Victor不,不会生成任何警告,因为您的编译器从未编译源代码。我的答案出错,这就是我删除它的原因。我明白了。虽然很棘手..非常。所以我将保留此a答案是正确的?(这里太离谱了,我必须睡觉,明天我会做决定!)谢谢!!@Victor据我所知,这是正确的。试图提供一个不好的类比,这就像写一本百科全书,它的措辞有点可疑(例如,包含未经检查的强制转换)。如果你给你的编辑器(编译器),草稿(源代码),您的编辑(编译器)可能会在将草稿(代码)发送到打印机(生成最终产品(字节码)之前向您抱怨可能有错误(发出警告)。但是,如果给打印机提供了直接包含的成品(字节码)(
import\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
),则编辑(编译器)从未涉及,因此不会生成警告。我同意Class.cast()方法在运行时执行检查,因为您正在运行时传递有关要强制转换的所需类的信息。但我有两个观察结果,第一个代码段没有编译为
String s=o
是一个缩小转换,因此在这之前,o引用的对象不是100%与字符串兼容的对象。关于第二个snipped classCastException发生在MagicCast调用中,这是jvm在运行时所说的
java.lang.Integer不能转换为java.lang.String
,关于第一个示例,我修复了它。第二个示例确实抛出了它,但是如果您查看堆栈跟踪,不是在MagicCast中,而是在调用方中。我修改了第二个示例以显示t调用程序可能不会立即检测到hat heap污染。我明白了,这是一个很好的解释,您可以离开这里。但是在最后,当“编译器”看到´´´return(T)时obj;'''r我们都认为它必须抱怨遵循Java lenguaje规范。好吧,你问为什么使用cast方法不会导致编译错误。如果你想知道cast方法可以在没有警告的情况下编译,你应该问另一个问题。谢谢你的更正。关于这个问题,我想,有一件事会导致错误另外。就个人而言,我认为这两个答案都是正确的,并引导我们找到一个有效的答案。我也会将其标记为正确的,但stackoverlow残酷的积分系统不允许我这样做。就个人而言,我非常感谢您的意图,以及所有其他在答案中友好合作的用户。
class C<T> {
    final T field;

    C(Object o) {
        this.field = (T) o; // unchecked. Will never throw a ClassCastException.
    }
}

boolean test() {
    C<String> c = new C<String>(42);
    return c.field.startsWith("hello"); // throws ClassCastException, even though there is no cast in the source code at this line!
}
public T cast(Object obj) 
{
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}