简体   繁体   English

一些Java泛型问题

[英]A few Java Generics questions

I'm currently studying Java Generics from a book and there are a few things I don't quite understand. 我目前正在从一本书中学习Java Generics,有一些我不太了解的东西。

Suppose I have a parameterized class: 假设我有一个参数化类:

class MyClass<T> { 

    T item;

    public T getItem() { return item; }

    // ...
}

I understand it is forbidden to create arrays of a parameterized type because of type erasure. 据我所知,由于类型擦除,禁止创建参数化类型的数组。 Now the book says that I can use casts like so: 现在这本书说我可以像这样使用演员:

MyClass<String>[] foo = (MyClass<String>[]) new MyClass<?>[10];

but what is the difference to the following statement? 但是以下声明有什么区别?

MyClass<String>[] foo = new MyClass[10];

In both cases at runtime the JVM only knows that foo is of the raw type MyClass[] right? 在运行时的两种情况下,JVM只知道foo是原始类型MyClass[]对吗?

Now the book continues to say: 现在这本书继续说:

"The result is not safe. If you store a MyClass<OtherType> in foo[0] and then call a String method on foo[0].getItem() you get a ClassCastException . TIP: If you need to collect parameterized type objects, simply use an ArrayList : ArrayList<MyClass<String>> is safe and effective." “结果不安全。如果在foo[0]存储MyClass<OtherType>然后在foo[0].getItem()上调用String方法,则会得到ClassCastException 。提示:如果需要收集参数化类型对象,只需使用ArrayListArrayList<MyClass<String>>是安全有效的。“

In what way is the usage of ArrayList safer in this case? 在这种情况下, ArrayList的使用方式更安全吗? I can produce a ClassCastException by storing a MyClass<OtherType> in the list just as easily. 我可以通过在列表中存储MyClass<OtherType>来生成ClassCastException

Edit: I'm not really satisfied with any of the answers. 编辑:我对任何答案都不满意。 Still the question remains: In what way is the usage of an ArrayList safer here? 问题仍然存在:在这里, ArrayList的使用方式更安全吗? Can anyone give me specific examples that demonstrate that improved safety? 任何人都可以给我一些证明安全性提高的具体例子吗?

Taking up the following comment to my initial unedited post: 在我最初的未经编辑的帖子中收到以下评论:

"I think that either the book doesn't explain this well, or you've taken the quote out of context. The problem is when you try to create an array of a generic argument type, eg inside MyClass you do T[] items = (T[]) new Object[10]; " “我认为这本书不能很好地解释这一点,或者你已经脱离了上下文。问题是当你尝试创建一个泛型参数类型的数组时,例如在MyClass中你做T[] items = (T[]) new Object[10];

What's the problem with that? 有什么问题?

// Please don't comment about any problems related to bounds etc. This class should serve purely 
// for demonstration of the core issue I'm trying to understand
public class MyClass<T> {

    private T[] items = (T[]) new Object[10];

    private int size = 0;

    public void addItem(T item) {
        items[size++] = item;
    }

    public T getItem(int index) {
        return items[index];
    }
}

In what way specifically am I losing any type safety that an ArrayList can provide? 具体来说,我失去了ArrayList可以提供的任何类型安全性吗? Please note I'm not trying to make a case for using arrays with parameterized types, I'm sure that Collections in fact do perform better, I'm just trying to understand why they do and what problems arise from using arrays. 请注意我并不是要尝试使用带参数化类型的数组,我确信Collections实际上表现更好,我只是想了解它们为什么会这样做以及使用数组会产生什么问题。

The reason why is "safer" to use generic Collections vs naked arrays is because the compiler adds extra reassurance that your code will do what is intended as it is less likely that you will mix references to objects created with different type-arguments due to a coding error from your part. 使用泛型集合与裸数组“更安全”的原因是因为编译器增加了额外的保证,即您的代码将执行预期的操作,因为它不太可能混合对使用不同类型参数创建的对象的引用您的部分编码错误。

For example it is totally legal to add a mixture of MyClasses into a MyClass array: 例如,将MyClasses的混合添加到MyClass数组中是完全合法的:

MyClass<Integer> mcInt = new MyClass<Integer>();
MyClass<String> mcString = new MyClass<String>();
MyClass[] array = new MyClass[] { mcInt , mcString }; 
...
MyClass<String>[] typedArray = (MyClass<String>[]) array;

The above may compile ok (depending as to how you handle unsafe warnings), however, typedArray will contain an invalid reference to a MyClass<Integer> typed element. 以上可能编译好(取决于你如何处理不安全的警告),但是, typedArray将包含对MyClass<Integer>类型元素的无效引用。

With generic collections the equivalent code won't ever compile because the compiler, thanks to the added type safety provided by using generics, realizes that you are adding that invalid reference. 使用泛型集合时,等效代码将无法编译,因为编译器由于使用泛型提供的类型安全性增加,因此意识到您正在添加该无效引用。

MyClass<Integer> mcInt = new MyClass<Integer>();
MyClass<String> mcString = new MyClass<String>();
List<MyClass<String>> list = new ArrayList<MyClass<String>>(); 
list.add(mcString); // is ok.
list.add(mcInt); // won't compile.

You are welcome to use naked array but by doing that you are losing additional checks done by the compiler. 欢迎使用裸阵列,但这样做会导致编译器失去额外的检查。 In practice is is ok to use the unsafe arrays if these are private fields or local variables, you are extra careful and silence warnings using @SuppressWarnings("unchecked") when you are sure that your code is actually safe as far as the compiler would assured it to be if you were to use generics. 实际上可以使用不安全的数组,如果它们是私有字段或局部变量,当你确定你的代码实际上是安全的时,你会特别小心并使用@SuppressWarnings(“unchecked”)静音警告。如果你使用泛型,那就确定了。

In my experience, most of the time is best just to use generic collections whenever you can but sometimes you may get in situations in where the unsafe alternative is far more convenient due to performance or just because the safe alternative results in more cumbersome code. 根据我的经验,大多数时候最好只是随时使用通用集合,但有时您可能会遇到不安全的替代方案由于性能而更加方便的情况,或者仅仅因为安全的替代方案导致更繁琐的代码。

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

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