首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Java泛型的类型强制

Java泛型的类型强制
EN

Stack Overflow用户
提问于 2018-06-10 03:35:40
回答 2查看 454关注 0票数 1

下面是我的代码:

代码语言:javascript
复制
public final class Generics {
    private Generics() {}

    public static <T> T unchecked(Object obj) {
        return (T)obj; //unchecked cast warning
    }

    public static void main(String[] args) {
        //correct
        ArrayList<String> str = new ArrayList<String>();
        str.add("Hello");
        str.add("World");
        System.out.println(str);

        //"correct" - not type safe at all but due to type erasure this is almost legal
        ArrayList<Object> obj = Generics.<ArrayList<Object>>unchecked(str);
        obj.add(1);
        System.out.println(obj);

        //obviously wrong but still compiles (ClassCastException at runtime)
        Exception except = Generics.<Exception>unchecked(str);
        System.out.println(except);
    }
}

通常,ArrayList<Object> obj = (ArrayList<Object>)str形式的强制转换将是一个致命的编译错误,因为这将违反使用该列表的预期。(您可以将非字符串的对象插入到仅限字符串的列表中)

此场景中的“未检查”警告是什么?unchecked()方法的使用与直接强制转换引用有何不同?这如何绕过编译器的类型检查呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-10 03:48:35

此方案中的“未选中”警告是什么

未经检查的强制转换是简单的强制转换,实际上不会在字节码中产生checkcast指令。

代码语言:javascript
复制
public static <T> T unchecked(Object obj) {
    return (T)obj; //unchecked cast warning
}

在这里,它是一个未经检查的强制转换,因为T的擦除是Object,所以它实际上是一个无操作,因为obj已经是一个Object

但有害的是,在调用位置插入了一个选中的强制转换:

代码语言:javascript
复制
Exception except = Generics.<Exception>unchecked(str);
               // ^ cast here!

在擦除时,有效执行的代码是:

代码语言:javascript
复制
Exception except = (Exception) Generics.unchecked(str);

但是您不会收到关于这方面的警告,因为该方法的返回类型表明这将是安全的,因此编译器相信它在调用位置是安全的。

在调用位置,没有办法知道unchecked方法正在做一些危险的事情。事实上,它能做的唯一安全的事情是返回null。但是编译器并不考虑它是否这样做:它只是简单地接受unchecked方法的声明。

未检查()方法的使用与直接强制转换引用有何不同?

唯一的区别是,您是通过Object隐式转换的。

代码语言:javascript
复制
Exception except = (Exception) str;

这样做:

代码语言:javascript
复制
Exception except = (Exception) (Object) str;

并且会在编译时使用相同的ClassCastException失败。

票数 4
EN

Stack Overflow用户

发布于 2018-06-10 04:05:20

通常,ArrayList<Object> obj = (ArrayList<Object>)str形式的强制转换将是一个致命的编译错误,因为这将违反使用该列表的预期。

该转换是一个编译错误,因为ArrayList<String>不是ArrayList<Object>的子类型-它与将Double转换为String时得到的编译错误相同。

实际上,您可以使用以下方法来避免使用unchecked方法

代码语言:javascript
复制
  // ArrayList<String> to ArrayList (raw) is legal
  ArrayList<Object> obj = (ArrayList<Object>)(ArrayList) str;
  // you can also cast to an interface-
  // at runtime, str could as well extend that interface!
  // and then Runnable can be downcasted to Exception
  // obviousy wrong, but still legal
  Exception except = (Exception)(Runnable)(str);

强制转换为不是ArrayList超类型的接口(Runnable)是合法的,因为我们很可能有一个扩展ArrayList并实现Runnable的类。(尽管这将是一个奇怪的类。)

这种类型的转换是“缩小引用转换”,如JLS, 5.1.6中所定义

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50777844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档