Java集合中的泛型与多态问题

简介: Java集合中泛型指的是在创建集合的时候要同时指定集合中存放的对象类型,这样做主要是基于类型安全方面的考虑。

Java集合中泛型指的是在创建集合的时候要同时指定集合中存放的对象类型,这样做主要是基于类型安全方面的考虑。

比如假设我们要创建一个用于存放字符串的ArrayList,我们通常使用如下的方式:

ArrayList<String> list = new ArrayList<String>();

注意尖括号及其里面的内容,这样我们的这个 list 中就只能存放 String 类型的对象,当我们试图向这个 list 中添加非 String 类型的对象(引用)的时候,会编译不通过,提示“找不到符号”(我觉得提示“找不到方法”更准确)。原因就是我们已经声明 ArrayList 中存放的 String 类型,当我们向这个 ArrayList 中添加对象(引用)的时候,编译器就会检查你存放的是否是 String 类型,如果不是,便会编译不通过,这就是所谓的类型安全问题。

在数组中存放对象(引用)的时候,编译器也会进行检查,当添加其他类型的对象的时候,编译不会通过,提示“不兼容的类型”。

上面介绍的是集合中的泛型问题,下面看一下集合中的多态问题,这才是本文的核心所在。

我们知道Java中的多态指的是:在程序中定义的某个引用变量具体所指向的类型和调用的方法在编码时并不能确定,而只有在运行的时候才能确定。简单来说就是这样的情况:你定义的引用变量是父类型,而你创建的对象是子类型,用这个父类型的引用变量指向这个子类型的对象,然后当你调用这个对象的方法的时候,具体是调用的父类的还是子类的方法只有在运行的时候才能确定,可能调用的是父类的方法也有可能调用的子类的方法,这样不用修改代码,就可以让成徐选择多个运行的状态,这就是多态。(关于多态,不明白的去查书。)

关于多态,简单理解就是适合父类的,必定也适合子类,即父类存在的地方也可以用子类来替换(而这其实对应一种设计原则,你也知道是吧,对,就是里氏替换原则。这里不介绍这个原则哈,只是顺便提一下。)

基于此,我们考虑集合中多态的情况。

先假设有一个方法如下(Animal为某类,Dog是其一个子类):

public void method(Animal anim){}

根据多态,我们知道我们可以用子类替换父类,而 Dog Animal 的子类即我们可以用一个 Dog 类型的对象作为该方法的参数,这没问题吧。是没问题的,我们继续。

我们引入集合及泛型,假设有某方法如下:

public void method(ArrayList<Animal> anim){}

则按照多态,理论上我们可以传递如下参数:一个 ArrayList<Dog> 类型的对象( Dog Animal 的子类),理论上没问题吧,而实际上却是大有问题的,会编译不通过。

这是为什么呢?DogAnimal的子类,父类存在的地方,子类就可以存在,这应该是没错的啊,这确实是没有错的,错不在多态。我们可以反向思考一下,假设允许上面的情况发生,就是在需要一个ArrayList<Animal>对象的地方你传入了ArrayList<Dog>对象,但接下来发生的情况是否会发生你就无法预料了,就是你在method中调用了anim.add(new Cat()),这是可以理解的吧(假设CatAnimal的另一子类),因为方法的参数类型是ArrayList<Animal>类型的,即这个ArrayList中存放的是AnimalCatAnimal的子类所以可以调用anim.add(new Cat()),但事实上你传递的确实ArrayList<Dog>类型的,即你向一个存放DogArrayList中存放了其他的对象,根据泛型安全性问题,这是不允许的啊。所以假设不成立,即你不能向一个参数类型为ArrayList<Animal>的方法中传递ArrayList<Dog>类型的对象。(真TM的像用反证法证数学题啊,有木有啊!)

晕了没,希望你没有。

相关文章
|
15天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
25 2
|
15天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
19天前
|
存储 Java
判断一个元素是否在 Java 中的 Set 集合中
【10月更文挑战第30天】使用`contains()`方法可以方便快捷地判断一个元素是否在Java中的`Set`集合中,但对于自定义对象,需要注意重写`equals()`方法以确保正确的判断结果,同时根据具体的性能需求选择合适的`Set`实现类。
|
19天前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
19天前
|
Java 开发者
|
1月前
|
安全 Java 程序员
深入Java集合框架:解密List的Fail-Fast与Fail-Safe机制
本文介绍了 Java 中 List 的遍历和删除操作,重点讨论了快速失败(fail-fast)和安全失败(fail-safe)机制。通过普通 for 循环、迭代器和 foreach 循环的对比,详细解释了各种方法的优缺点及适用场景,特别是在多线程环境下的表现。最后推荐了适合高并发场景的 fail-safe 容器,如 CopyOnWriteArrayList 和 ConcurrentHashMap。
58 5
|
30天前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
25 0
[Java]泛型
|
1月前
|
安全 Java 程序员
Java集合之战:ArrayList vs LinkedList,谁才是你的最佳选择?
本文介绍了 Java 中常用的两个集合类 ArrayList 和 LinkedList,分析了它们的底层实现、特点及适用场景。ArrayList 基于数组,适合频繁查询;LinkedList 基于链表,适合频繁增删。文章还讨论了如何实现线程安全,推荐使用 CopyOnWriteArrayList 来提升性能。希望帮助读者选择合适的数据结构,写出更高效的代码。
59 3
|
1月前
|
存储 Java 测试技术
Java零基础-多态详解
【10月更文挑战第10天】Java零基础教学篇,手把手实践教学!
24 4
|
19天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
18 0
下一篇
无影云桌面