简体   繁体   English

Effective Java - 第25项 - 泛型类转换异常混合列表和数组

[英]Effective Java - Item 25 - Generics class cast exception Mixing List and Arrays

I'm reading Effective Java 2nd edition from Joshua Bloch, item 25 (page 122). 我正在阅读Joshua Bloch撰写的Effective Java第2版,第25项(第122页)。 As you read further into the chapter, you get to a point where the author writes the following code : 当您进一步阅读本章时,您会发现作者编写以下代码:

// 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;
}

Then the author states that the compiler won´t compile this because you need to add an explicit cast to the line where is the assignment E[] snapshot = list.toArray(); 然后作者声明编译器不会编译它,因为你需要在赋值E[] snapshot = list.toArray();的行中添加一个显式的E[] snapshot = list.toArray(); , resulting on this E[] snapshot = (E[]) list.toArray(); ,导致这个E[] snapshot = (E[]) list.toArray(); , and after this you well get a warning saying that there is [unchecked] unchecked cast . ,在此之后你会得到一个警告,说有[unchecked] unchecked cast


Q1: I know that the book was taking into account changes up to Java 6 (and we are at Java almost 8 right now). 问题1:我知道这本书考虑到了Java 6的变化(我们现在的Java几乎是8)。 However, I wrote the same method, a get the same error from the compile. 但是,我写了相同的方法,从编译中得到相同的错误。 This is because I am required to add the explicit cast. 这是因为我需要添加显式强制转换。 There is however no warning. 但是没有警告。 So what is that warning about? 那个警告是什么?


Q2: The author states the following method will work but it turns out that it isn't type safe . Q2:作者声明以下方法可行但事实证明它不是类型安全的

With minor modifications, you could get it to throw a ClassCastException on a line that doesn't contain an explicit cast. 通过微小的修改,您可以让它在不包含显式ClassCastException的行上抛出ClassCastException

Okay, I understand that... but how can I get it to throw a ClassCastException ? 好的,我理解......但是如何让它抛出ClassCastException呢?


I leave this post with a ready to run example, if you want to check the things for yourselves: 如果你想为自己检查一下,我将这篇文章留下准备好运行的例子:

import java.util.Arrays;
import java.util.List;

public class Main
{

    public static void main(String[] args)
    {
        List<Integer> ints = Arrays.asList(10,20,30);
        Integer result = reduce (ints,new Function<Integer>() {

            @Override
            public Integer apply(Integer arg1, Integer arg2)
            {
                return arg1 + arg2;
            }
        },0);
        System.out.println(result);
    }

    static <E> E reduce(List<E> list, Function<E> f, E initVal)
    {
        E[] snapshot = (E[]) list.toArray(); // Locks list
        E result = initVal;
        for (E e : snapshot)
        {
            result = f.apply(result, e);
        }
        return result;
    }

    interface Function<T>
    {
        public T apply(T arg1, T arg2);
    }
}
E[] snapshot = list.toArray();

list.toArray() returns Object[] instead of E[] . list.toArray()返回Object[]而不是E[] So you need an explicit cast there. 所以你需要一个明确的演员。 But the presence of the explicit (or dynamic) cast like that means that compiler could not guarantee the type-safety there. 但是这样的显式(或动态)转换的存在意味着编译器无法保证那里的类型安全性。 Instead your are telling the compiler that everything is fine and it will actually be an E[] at runtime. 相反,你告诉编译器一切都很好,它在运行时实际上是一个E[] So, it gives you a warning about it saying - unchecked cast . 因此,它会给你一个关于它的警告 - 未经检查的演员 Note, that if the compiler was able to guarantee the type-safety there, then it would be a static/checked cast (performed implicitly by the compiler itself) there, instead. 注意,如果编译器能够保证那里的类型安全性,那么它将是静态/检查的强制转换(由编译器本身隐式执行)。

Question one: Why is E[] snapshot = (E[]) list.toArray(); 问题一:为什么E[] snapshot = (E[]) list.toArray(); warning about unsafe check? 关于不安全检查的警告?

The reason is that, in java, arrays keep their type information, while generics get erased. 原因是,在java中,数组保留其类型信息,而泛型则被删除。 At runtime all List<String> , List<Dog> and List<NuclearBomb> are effectively List<Object> . 在运行时,所有List<String>List<Dog>List<NuclearBomb>都是有效的List<Object>

Therefore: 因此:

List<E> list becomes List<Object> List<E> list变为List<Object>

And

E[] array = (E[]) list.toArray();

Is unsafe. 不安全。

Question two: How can that fail at runtime? 问题二:如何在运行时失败?

If java lets you do 如果java允许你这样做

E[] array = (E[]) list.toArray();

with a list of Object s, it will also let you do: 使用Object列表,它还可以让您:

String[] array = (String[]) list.toArray();

Since strings are objects after all. 因为字符串毕竟是对象。 That line would compile (with a warning) and on runtime you'd get a cast exception. 该行将编译(带有警告),在运行时,您将获得强制转换异常。

I think the compiler when it sees an explicit cast raises a warning where generics and arrays are combined . 我认为编译器在看到显式转换时会引发一个警告,其中泛型和数组被组合在一起。 if you remember the earlier example in Bloch effective java page 117 如果你还记得Bloch有效的java第117页中的早期例子

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

In the above scenario also the compiler generates a warning : [unchecked] unchecked cast. 在上面的场景中,编译器也会生成一个警告:[unchecked] unchecked cast。 Although we are pretty much sure at the runtime that array returned will always be of type T. But it is suppressed by using @SuppressWarnings annotation. 虽然我们在运行时非常确定返回的数组将始终为T类型但是它通过使用@SuppressWarnings注释来抑制。

For Question2, I try to understand the author by codes below. 对于Question2,我尝试通过以下代码了解作者。

caller: 呼叫者:

List<String> list = Arrays.asList("string");
reduce(list, new Function<String>() {
    @Override
    public String apply(String arg1, String arg2) {
        return "";
    }
}, "");

the "reduce" mothod: “减少”方法:

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;
}

Maybe it's not such "With minor modifications", but it is an appropriate expaination. 也许它不是“经过微小修改”,但它是一个适当的表达。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM