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

晕了没,希望你没有。

相关文章
|
14天前
|
Java 大数据 API
Java Stream API:现代集合处理与函数式编程
Java Stream API:现代集合处理与函数式编程
176 100
|
14天前
|
Java API 数据处理
Java Stream API:现代集合处理新方式
Java Stream API:现代集合处理新方式
183 101
|
27天前
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
7天前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
105 10
|
19天前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
2月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
163 23
|
2月前
|
存储 缓存 安全
Java集合框架(三):Map体系与ConcurrentHashMap
本文深入解析Java中Map接口体系及其实现类,包括HashMap、ConcurrentHashMap等的工作原理与线程安全机制。内容涵盖哈希冲突解决、扩容策略、并发优化,以及不同Map实现的适用场景,助你掌握高并发编程核心技巧。
|
2月前
|
安全 Java 开发者
Java集合框架:详解Deque接口的栈操作方法全集
理解和掌握这些方法对于实现像浏览器后退功能这样的栈操作来说至关重要,它们能够帮助开发者编写既高效又稳定的应用程序。此外,在多线程环境中想保证线程安全,可以考虑使用ConcurrentLinkedDeque,它是Deque的线程安全版本,尽管它并未直接实现栈操作的方法,但是Deque的接口方法可以相对应地使用。
126 12
|
2月前
|
存储 NoSQL Java
Java Stream API:集合操作与并行处理
Stream API 是 Java 8 提供的集合处理工具,通过声明式编程简化数据操作。它支持链式调用、延迟执行和并行处理,能够高效实现过滤、转换、聚合等操作,提升代码可读性和性能。
|
2月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。