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的像用反证法证数学题啊,有木有啊!)

晕了没,希望你没有。

相关文章
|
29天前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
53 9
|
3天前
|
Java 编译器 容器
Java——包装类和泛型
包装类是Java中一种特殊类,用于将基本数据类型(如 `int`、`double`、`char` 等)封装成对象。这样做可以利用对象的特性和方法。Java 提供了八种基本数据类型的包装类:`Integer` (`int`)、`Double` (`double`)、`Byte` (`byte`)、`Short` (`short`)、`Long` (`long`)、`Float` (`float`)、`Character` (`char`) 和 `Boolean` (`boolean`)。包装类可以通过 `valueOf()` 方法或自动装箱/拆箱机制创建。
21 9
Java——包装类和泛型
|
7天前
|
Java 编译器
Java——类与对象(继承和多态)
本文介绍了面向对象编程中的继承概念,包括如何避免重复代码、构造方法的调用规则、成员变量的访问以及权限修饰符的使用。文中详细解释了继承与组合的区别,并探讨了多态的概念,包括向上转型、向下转型和方法的重写。此外,还讨论了静态绑定和动态绑定的区别,以及多态带来的优势和弊端。
20 9
Java——类与对象(继承和多态)
|
6天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
3天前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
|
21天前
|
Java
用JAVA架建List集合为树形结构的代码方法
这段代码定义了一个表示树形结构的 `Node` 类和一个用于构建树形结构的 `TreeController`。`Node` 类包含基本属性如 `id`、`pid`、`name` 和 `type`,以及子节点列表 `children`。`TreeController` 包含初始化节点列表并将其转换为树形结构的方法。通过过滤和分组操作实现树形结构的构建。详情可见:[代码示例链接1](http://www.zidongmutanji.com/zsjx/43551.html),[代码效果参考链接2](https://www.257342.com/sitemap/post.html)。
28 5
|
26天前
|
安全 Java Go
Java&Go泛型对比
总的来说,Java和Go在泛型的实现和使用上各有特点,Java的泛型更注重于类型安全和兼容性,而Go的泛型在保持类型安全的同时,提供了更灵活的类型参数和类型集的概念,同时避免了运行时的性能开销。开发者在使用时可以根据自己的需求和语言特性来选择使用哪种语言的泛型特性。
35 7
|
21天前
|
存储 Java 程序员
Java中的集合框架:从入门到精通
【8月更文挑战第30天】在Java的世界里,集合框架是一块基石,它不仅承载着数据的存储和操作,还体现了面向对象编程的精髓。本篇文章将带你遨游Java集合框架的海洋,从基础概念到高级应用,一步步揭示它的奥秘。你将学会如何选择合适的集合类型,掌握集合的遍历技巧,以及理解集合框架背后的设计哲学。让我们一起探索这个强大工具,解锁数据结构的新视角。
|
22天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
23天前
|
安全 Java 编译器
Java多态
Java多态
13 2