Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有效的Java-项25-泛型类强制转换异常混合列表和数组_Java_Arrays_List_Generics_Effective Java - Fatal编程技术网

有效的Java-项25-泛型类强制转换异常混合列表和数组

有效的Java-项25-泛型类强制转换异常混合列表和数组,java,arrays,list,generics,effective-java,Java,Arrays,List,Generics,Effective Java,我正在阅读Joshua Bloch的《有效Java第二版》,第25项(第122页)。当您进一步阅读本章时,您会看到作者编写了以下代码: // Naive generic version of reduction - won't compile! static <E> E reduce(List<E> list, Function<E> f, E initVal) { E[] snapshot = list.toArray(); // Locks lis

我正在阅读Joshua Bloch的《有效Java第二版》,第25项(第122页)。当您进一步阅读本章时,您会看到作者编写了以下代码:

// Naive generic version of reduction - won't compile!
static <E> E reduce(List<E> list, Function<E> f, E initVal) {
    E[] snapshot = list.toArray(); // Locks list
    E result = initVal;
    for (E e : snapshot)
    {
        result = f.apply(result, e);
    }
    return result;
}
返回
Object[]
而不是
E[]
。所以你需要一个显式的强制转换。但这种显式(或动态)强制转换的存在意味着编译器无法保证那里的类型安全。相反,您告诉编译器一切正常,在运行时它实际上是一个
E[]
。所以,它给了你一个警告,说-未经检查的演员。请注意,如果编译器能够保证那里的类型安全,那么它将是一个静态/检查强制转换(由编译器本身隐式执行)。

问题一:为什么
E[]snapshot=(E[])list.toArray()关于不安全检查的警告?
原因是,在java中,数组保留其类型信息,而泛型则被删除。在运行时,所有
List
List
List
都有效地
List

因此:

列表列表
变为
列表

E[]数组=(E[])list.toArray()

这是不安全的

问题二:如何在运行时失败? 如果java允许您这样做

E[]数组=(E[])list.toArray()

有了
对象的列表
s,您还可以执行以下操作:

String[]数组=(String[])list.toArray()


因为字符串毕竟是对象。这行代码将被编译(带有警告),在运行时您将得到一个强制转换异常。

我认为编译器在看到显式强制转换时会在泛型和数组组合的地方发出警告。如果您还记得Bloch effective java第117页中前面的示例

return (T[]) Arrays.copyOf(elements, size, a.getClass());

在上述场景中,编译器还会生成警告:[未选中]未选中强制转换。虽然我们非常确定在运行时返回的数组总是T类型的。但是通过使用@SuppressWarnings注释可以抑制它。

对于问题2,我试图通过下面的代码来理解作者

来电者:

List<String> list = Arrays.asList("string");
reduce(list, new Function<String>() {
    @Override
    public String apply(String arg1, String arg2) {
        return "";
    }
}, "");
List List=Arrays.asList(“字符串”);
减少(列表,新函数(){
@凌驾
公共字符串应用(字符串arg1、字符串arg2){
返回“”;
}
}, "");
“减少”方法:

static E reduce(列表、函数f、E initVal){
// /*
列表快照;
已同步(列表){
快照=新阵列列表(列表);
}
snapshot.set(0,123);//此处编译错误
// */
/*Object[]objs=list.toArray();
objs[0]=123;//将在运行时导致ClassCastException
E[]快照=(E[])对象*/
E结果=初始值;
用于(E:快照){
结果=f。应用(结果,e);
}
返回结果;
}

也许不是“稍加修改”,但这是一个恰当的解释。

我得到一个警告。可能是您在IDE中关闭了特定警告?@LuiggiMendoza我确实读过这个问题。OP说没有任何警告。我是说我有一个。问题1是为什么会有这样的警告和/或它是什么意思,我知道我没有回答。@user3580294是的,我误解了问题的这一部分。不确定OP使用哪个编译器和/或他/她可能有什么设置。是的,我正在IDE中编译,它会默默地忽略该警告。从命令行编译,揭示了与本书作者所说的相同的情况。问题2的答案发生了什么?我不太确定这个小修改到底代表什么。但是您可以通过将行替换为
E[]snapshot=(E[])new Double[]{0d,1d}之类的内容来获得效果
@BheshGurung我相信这个小改动就是OP的第二个问题。“只要稍加修改,您就可以让它在不包含显式强制转换的行上抛出一个
ClassCastException
。@BheshGurung这是一个小修改,但不符合布洛赫的说法。他说的是一个修改,它会在没有显式强制转换的行上产生
ClassCastException
。非常确定你得到的是一个显式的强制转换。泛型是只编译类型的特性,所有的泛型信息都会被类型删除。如果没有那样的限制,那么
E
将变成
Object
。嗯,对不起,我的好朋友,我没有赶上。关于第一个问题,我了解类型擦除过程,该过程会删除类型信息,以便在java中留下可以使用遗留代码运行的代码。但为什么不安全呢?我认为,类型擦除后的列表也会变成一个原始列表,或者至少约书亚指出了这一点。列表不会变为列表,而是列表的内部参数化符号变为对象,但列表作为一个整体变为列表。读者们,如果我错了,请纠正我。请帮助我理解为什么不安全?谢谢我理解第二个答案,但我看不出在一段代码上这样做的逻辑,因为这段代码首先是关于泛型的。。。。我不明白约书亚的意图也许。。。另外,我要提醒他,他说问题可以在“不包含显式强制转换”的行中提出。我只理解了第一个和第二个示例。从第一个开始是不安全的,因为在编译时编译器不知道什么类型是E,所以编译器会看到这样的东西
E=(E)(Object[])
,并且知道
AnyType
perphaps在运行时不会完全是
Object
,因此之前不会准备好存储与运行时应用的实际类型参数不兼容的值,例如,类层次结构中位于Object和AnyType之间的所有类型的对象,第一个问题的答案是,运行时应用的实际类型参数位于类h中
return (T[]) Arrays.copyOf(elements, size, a.getClass());
List<String> list = Arrays.asList("string");
reduce(list, new Function<String>() {
    @Override
    public String apply(String arg1, String arg2) {
        return "";
    }
}, "");
static <E> E reduce(List<E> list, Function<E> f, E initVal) {
    // /*
    List<E> snapshot;
    synchronized (list) {
        snapshot = new ArrayList<>(list);
    }
    snapshot.set(0, 123);    // compile error here
    // */

    /*Object[] objs = list.toArray();
    objs[0] = 123;  // will cause ClassCastException on runtime
    E[] snapshot = (E[]) objs;*/
    E result = initVal;
    for (E e : snapshot) {
        result = f.apply(result, e);
    }
    return result;
}