网站首页 > 基础教程 正文
以下案例基于此代码:
class Animal{ }
/************ 鸟类 ************/
class Bird extends Animal{ }
// 乌鸦
class CrowBird extends Bird{ }
// 喜鹊
class MagpiedBird extends Bird{ }
/************ 犬类****** ******/
class Dog extends Animal{ }
// 牧羊犬
class ShepherdDog extends Dog{ }
// 二哈
class ErhaDog extends Dog{ }
/********* 鱼类 *********/
class Fish extends Animal{ }
// 金鱼
class GlodFish extends Fish{ }
// 鲨鱼
class SharkFish extends Fish{ }
一、抛出问题:
1、List<Bird>与List<? extends Bird>,List<? super Bird>的区别?
2、为啥List<? extends Bird>不能add非空对象,只能get?List<? super Bird>可以add,但是get出来的为Object?
先看java中泛型的几个基本问题:
a、List<Bird> birdList = new ArrayList<>();等价于List<Bird> birdList = new ArrayList<Bird>()。
结论:实例化时不写泛型,默认和声明时泛型一致;实例化时的泛型与声明时的泛型要一致,否则会报错。
b、List<Bird> birdList = new ArrayList<>(); birdList中可以添加Bird及Bird的所有子类。
结论:集合中只能添加指定的泛型类型及其子类型。
c、List<CrowBird>与List<Bird>不是继承关系,这是引入List<? extends Bird>的原因。
一、泛型上边界
?extend Bird表示泛型上边界。举例,List<? extend Bird>表示实例化的对象的泛型只能是Bird及其子类。有如下特点:
1、不能向集合中添加非空元素;
2、只能从集合中获取元素;
千万注意,List<? extend Bird> birdList,不是表示birdList中能添加Bird及Bird的子类,那是List<Bird>的功能。List<? extend Bird> birdList表示birdList可以实例化成new ArrayList<Bird>(),new ArrayList<CrowBird>(),new ArrayList<MagpiedBird>()。即birdList最终实例化的集合的泛型是Bird或者Bird的子类。
二、泛型下边界
?super Bird表示泛型下边界。举例,List<? super Bird>表示实例化的对象的泛型只能是Bird及其父类。有如下特点:
1、能向集合中添加元素;只能添加super后面指定泛型类型及其子类型元素。
2、能从集合中获取元素,但是Object类型。
千万注意,List<? super Bird> birdList,不是表示birdList中能添加Bird及Bird的父类。List<? super Bird> birdList表示birdList可以实例化成new ArrayList<Bird>(),new ArrayList<Animal>()。即birdList最终实例化的集合的泛型是Bird或者Bird的父类。
三、深入理解
通过下面的例子和图形来回答上面抛出的问题
泛型上边界代码分析入下:
package com.stone.gen;
import java.util.ArrayList;
import java.util.List;
public class GenericParadigm {
public static void main(String[] args) {
List<? extends Bird> birdList = null;
// is ok;此时存储的数据只能是Bird及子类
birdList = new ArrayList<Bird>();
// is ok;此时存储的数据只能是CrowBird及子类
birdList = new ArrayList<CrowBird>();
// is ok;此时存储的数据只能是MagpiedBird及子类
birdList = new ArrayList<MagpiedBird>();
// is error;声明与实例化冲突了,IDE报错
birdList = new ArrayList<Animal>();
/*
* 也就是说,List<? extends Bird> birdList表示具体实例化的对象的泛型必须是Bird或者Bird的子。
* 所以这儿的list到底是什么类型的泛型,取决于最终的实例化。 List<? extends Bird> birdList可能是new
* ArrayList<Bird>(),这个时候只能添加Bird及子类 List<? extends Bird> birdList可能是new
* ArrayList<CrowBird>(),这个时候只能添加CrowBird及子类 List<? extends Bird>
* birdList可能是new ArrayList<MagpiedBird>(),这个时候只能添加MagpiedBird及子类
* 所以,List<? extends Bird> birdList中不能添加。因为具体的泛型对象不确定。但是可以get,因为
* Bird是泛型的上限,从里面取出来得对象,必定是Bird对象。
*/
}
}
class Animal {}
/*** 鸟类 ***/
class Bird extends Animal {}
// 乌鸦
class CrowBird extends Bird {}
// 喜鹊
class MagpiedBird extends Bird {}
/*** 犬类 ***/
class Dog extends Animal {}
// 牧羊犬
class ShepherdDog extends Dog {}
// 二哈
class ErhaDog extends Dog {}
/*** 鱼类 ***/
class Fish extends Animal {}
// 金鱼
class GlodFish extends Fish {}
// 鲨鱼
class SharkFish extends Fish {}
原因分析:
new ArrayList<Bird>里存储的只能是Bird及其子类;
new ArrayList<CrowBird>里存储的只能是CrowBird及其子类;
new ArrayList<MagpiedBird>里存储的只能是MagpedBird及其子类;
1、那如果按照List<? extends Bird> birdList中存储的是Bird及其子类这
种方式理解的话,那我们把birdList实例化成new ArrayList<CrowBird>(),
这样是不是就不能放Bird了,只能放CrowBird及其子类了,推翻了我们
的错误理解。这就是上边界不能add的原因。
2、由于是上边界,就是存储的对象类型的上限,所以里面存储的一定是Bird
及其子类型,所以取出来一定是Bird。所以能get。
3、根本原因是List<? extend Bird>不是实例化的对象的子集。
泛型下边界分析如下:
package com.stone.gen;
import java.util.ArrayList;
import java.util.List;
public class GenericParadigm {
public static void main(String[] args) {
List<? super Bird> birdList = null;
birdList = new ArrayList<Bird>();// is ok;此时存储的数据只能是Bird及子类
birdList = new ArrayList<Animal>();// is ok;此时存储的数据只能是Animal及子类
birdList = new ArrayList<Dog>();// is error;声明与实例化不一致,IDE报错
/*
* 也就是说,List<? super Bird> list表示具体实例化的对象的泛型必须是Bird或者Bird的父。 List<?
* super Bird> list可能是new ArrayList<Bird>(),这个时候只能添加Bird及其子 List<? super
* Bird> list可能是new ArrayList<Animal>(),这个时候只能添加Animal及其子
*/
}
}
class Animal {}
/*** 鸟类 ***/
class Bird extends Animal {}
// 乌鸦
class CrowBird extends Bird {}
// 喜鹊
class MagpiedBird extends Bird {}
/*** 犬类 ***/
class Dog extends Animal {}
// 牧羊犬
class ShepherdDog extends Dog {}
// 二哈
class ErhaDog extends Dog {}
/*** 鱼类 ***/
class Fish extends Animal {}
// 金鱼
class GlodFish extends Fish {}
// 鲨鱼
class SharkFish extends Fish {}
原因分析:
List<? super Bird> birdList = null;我们在实例化时,实例化对象的泛型
对象是Bird或者Bird的父,即:
birdList = new ArrayList<Bird>();
birdList = new ArrayList<Animal>();
1、Bird是下限,new ArrayList<Bird>();可以存储Bird及其子;
new ArrayList<Animal>();可以存储Animal及其子,是不是包含了Bird
及其子。所以集合里面可以添加Bird及其子。这就是下边界为什么可以
add的原因,因为实例化出来的集合对象一定包含了下限。所以,
下边界描述的是能能add(super后面指定泛型类型及其子类型)元素。
2、但是获取出来的对象可能是Bird,也可能是Animal,不知道具体类型,
所有get出来是Object。
3、根本原因是List<? super Bird>是实例化的对象的子集。
猜你喜欢
- 2024-11-19 业务人员学Python系列(9):列表操作方法
- 2024-11-19 python常用列表函数
- 2024-11-19 一文搞明白RocksDB
- 2024-11-19 Python3 列表list合并的4种方法
- 2024-11-19 2 常见的Python数据结构-元组、列表
- 2024-11-19 Python 入门系列——14. List的CURD
- 2024-11-19 列表常用操作-增加与删除
- 2024-11-19 一文了解 Python 中的 append() 与 extend()方法
- 2024-11-19 [Python知识点]list列表append()和extend()的区别
- 最近发表
- 标签列表
-
- jsp (69)
- gitpush (78)
- gitreset (66)
- python字典 (67)
- dockercp (63)
- gitclone命令 (63)
- dockersave (62)
- linux命令大全 (65)
- pythonif (86)
- location.href (69)
- dockerexec (65)
- tail-f (79)
- queryselectorall (63)
- location.search (79)
- bootstrap教程 (74)
- deletesql (62)
- linuxgzip (68)
- 字符串连接 (73)
- html标签 (69)
- c++初始化列表 (64)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)