java - 几个 Java 泛型问题

标签 java generics

我目前正在通过一本书学习 Java 泛型,有几件事我不太明白。

假设我有一个参数化类:

class MyClass<T> { 

    T item;

    public T getItem() { return item; }

    // ...
}

我知道由于类型删除,禁止创建参数化类型的数组。现在书上说我可以像这样使用强制转换:

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

但是下面的语句有什么区别呢?

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

在这两种情况下,在运行时 JVM 只知道 foo 是原始类型 MyClass[],对吗?

现在这本书继续说:

“结果不安全。如果将 MyClass<OtherType> 存储在 foo[0] 中,然后在 String 上调用 foo[0].getItem() 方法,则会得到 ClassCastException。 提示:如果您需要收集参数化类型对象,只需使用 ArrayList :ArrayList<MyClass<String>> 是安全有效的。”

在这种情况下,ArrayList 以何种方式使用更安全?我可以通过在列表中存储 ClassCastException 来轻松生成 MyClass<OtherType>

编辑:我对任何答案都不满意。问题仍然存在:在这里使用 ArrayList 以何种方式更安全?任何人都可以给我具体的例子来证明提高了安全性吗?

对我最初未经编辑的帖子发表以下评论:

“我认为这本书没有很好地解释这一点,或者你已经断章取义了。问题是当你试图创建一个通用参数类型的数组时,例如在 MyClass 中你做 T[] items = (T[]) new Object[10]; "

这有什么问题?

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

我具体以何种方式失去了 ArrayList 可以提供的任何类型安全性? 请注意,我并不是要证明使用参数化类型的数组,我确信 Collections 实际上确实表现得更好,我只是想了解它们这样做的原因以及有什么问题产生于使用数组。

最佳答案

使用泛型集合与裸数组相比“更安全”的原因是因为编译器增加了额外的保证,即您的代码将按预期执行,因为您不太可能混合对使用不同类型参数创建的对象的引用由于您的部分编码错误。

例如,添加 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;

上面的代码可能编译正常(取决于你如何处理不安全警告),然而,typedArray将包含对 MyClass<Integer> 的无效引用类型元素。

对于泛型集合,等效代码永远不会编译,因为编译器,由于使用泛型提供的附加类型安全,意识到您正在添加无效引用。

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.

欢迎您使用裸数组,但这样做会丢失编译器完成的额外检查。实际上,如果这些是私有(private)字段或局部变量,则可以使用不安全的数组,当您确定您的代码实际上是安全的,就编译器而言,您要格外小心并使用 @SuppressWarnings("unchecked") 静音警告如果您要使用泛型,请确保它是。

根据我的经验,大多数时候最好尽可能使用泛型集合,但有时您可能会遇到这样的情况:由于性能原因,不安全的替代方案要方便得多,或者仅仅因为安全的替代方案会导致更麻烦代码。

关于java - 几个 Java 泛型问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47959763/

相关文章:

java - Inno 安装程序 : Extending Windows default apps list

java - 如何在 junit 测试中将值初始化为字符串数组?

java - 为什么泛型类型不传播到所有类方法?

c# - .net 接口(interface)与泛型方法,实现中的错误

generics - 在什么条件下 unit 是一个类型?

java - 强制 JTextArea 中的 RTL 顺序

java - 如何配置 Kafka 使其表现得像一个 FiFo 队列?

java - Hibernate 不从连接池中释放连接

java - 当传递给带有可变参数的第二个泛型方法时,我在泛型方法中丢失了变量的类型

swift - 如何更新 Swift 中的作业?