泛型的通配符
当使用泛型类或者泛型接口,传递的数据中,泛型的类型不确定,可以通过通配符<?>表示。一旦程序当中使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
通配符的基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?代表位置的通配符
此时只能接收数据,不能往该集合中存储数据。
代码示例:
public static void main(String[] args){
//可以存储整数的集合
Collection<Integer> list01 = new ArrayList<Integer>();
//此时list01可以存储整数的数据
//展示list01集合当中的数据
getElement(list01);
//可以存储String字符串的集合
Collection<String> list02 = new ArrayList<String>();
//此时list02可以存储字符串的数据
getElement(list02)// Collection<Object> × 不可以
// 此时如果换成泛型通配符? 就可以接收
getElement(list02);// 可以
}
// 可以接收任意的数据类型
public static void getElement(Collection<?> coll){
// 只能接收Integer类型的数据
// 此时? 可以代表任意类型
}
备注:泛型不存在继承关系 Collection list = new Arraylist(); 这是一种错误写法。
通配符的高级用法-----受限泛型
之前设置泛型的时候,实际上是可以任意设置的。只要是类就可以的,但是在Java的泛型当中还可以指定一个的泛型的上限和下限
泛型的上限:
格式:类型名称<? extends 类名> 对象名称
意义:只能接收该类型及其子类
泛型的下限:
格式:类型名称<? super 类名>对象名
意义:只能接收该类类型及其父类类型
比如说:已知的顶级父类Object,String类,Number类,Integer类 ,其中Number类是Integer的父类
示例代码:
public static void main(String[] args){
// 初始化三个集合
Collection<Integer> list01 = new ArrayList<Integer>();
Collection<String> list02 = new ArrayList<Integer>();
Collection<Number> list03 = new ArrayList<Integer>();
Collection<Object> list04 = new ArrayList<Integer>();
}
// 定义方法 此时可以接收任意的数据类型
public static void getElement(Collection<?> coll) {//.....}
// 定义方法,此时我只让该方法接收数字类型 Number类型或者Number的子类
pubic static void getElement(Collection<? extends Number> coll){//...}
// 定义方法,此时我只让接收Number类型及其以上的类型
public static void getElement(Collection<? super Number> coll) {//....}
数据结构
数据结构有什么作用?
当我们使用着Java官方给你提供的容器的时候,我们用起来是非常的好的,ArrayList其实就是一个无限扩充的数组,LinkedList其实一个链表。
现实世界中存储数据,我们要通过一些工具或者建模来进行存储。每种数据结构都有自己的优缺点。
而算法,在这么多的数据中如何以最快的速度实现插入、删除、查找数据问题。
我们Java语言是一种面向对象的编程语言,Java就相当于自动挡汽车,C语言就相当于手动挡汽车。数据结构呢?
数据结构就相当于变速箱的工作原理,不懂数据结构原理的,对于开发Java程序也是没有任何问题,
如果你懂变速箱的原理,那么不但可以开车,也可以修车,还可以造车。
数据结构内容非常多,我们介绍Java当中常见的数据结构:堆栈、队列、数组、链表和红黑树一一给大家介绍下。
常见的数据结构:
数据存储的常用结构:栈、队列、数组、链表和红黑树
栈
-
栈:stack,又称堆栈,它是运算受限的线性表结构,它的限制是仅允许在标的的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作。
简单的说,采用该结构的集合,对元素的存取有一下特点:
- 先进后出(存进去的元素,要在他后面的元素依次取出后,才能取出该元素)。例如:子弹压进弹夹和子弹从弹夹弹出的动作。
- 栈的入口、出口都是栈的顶端位置。
- 空栈:栈顶:栈底:
压栈:就是存储元素,把元素存储到栈的顶端位置,栈中已有的元素依次向栈底方向移动一个位置。
弹栈:就是取出元素,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。
队列
-
队列:queue,简称对,它同堆栈几乎一样的,也是一种运算受限的线性表结构,它的限制是仅允许在标的的一端进行插入,在标的的另一端进行删除。
简单的说,采用该结构的集合,对元素的存取有以下特点:
-
数组:Array,是有序的元素序列,数组是在内存当中开辟一段连续的空间,并在此空间内存储元素。例如:
生活中的酒店,酒店当中的房间号是连续的,不间断,有50个房间,从001—050每个房间都有固定编号,通过编号就可以快速找到酒店房间的住户。
简单的说,采用此结构的集合,对元素存取有以下特点:
-
查找元素快:通过索引,可以快速的访问到指定位置的元素。
-
增删元素慢:
-
指定索引位置增加元素:需要创建一个新数组,将指定的新元素存储到指定的索引位置,再把源数组元素根据他原来的索引,复制到新数组对应的索引位置。
-
指定索引位置删除元素:需要创建一个新数组,把源数组当中的元素根据索引,复制到新数组对应索引的位置,源数组中指定的索引位置元素不复制到新数组当中。
链表结构
-
-
链表:linked list,由一系列结点node(链表当中的每个元素称为结点)组成,结点可以在运行时动态生成。每个结点包含两个部分:一个是用于存储数据元素的数据域,另一个是用来存储下一个结点地址的指针域。我们常说的链表结构有单向链表和双向链表
简单的说,采用此结构的集合,对元素的存取有以下特点:
-
多个结点之间,通过地址进行连接。比如:多个人玩丢手绢,每个人右手拉住下一个人的左手,上一个人的左手拉住该人的右手。依次类推,多个人就被连接起来。
-
查找元素比较慢:想要查找某个元素,需要通过连接的结点,依次向后查询指定的元素。
-
删除元素比较快:
- 增加一个元素:只需要修改连接下个元素的地址即可。
- 删除一个元素:只需要修改连接下一个元素的地址即可。
红黑树
-
二叉树:binary tree,每个节点数不超过2的树(tree)
简单的理解,就是类似于我们生活中的树的结构,只不过每个节点上都最多只能有两个子节点。
顶上的节点称为根节点,两边的被称为“左子树”和“右子树”
在二叉树中有一种比较特殊树结构叫做红黑树,红黑树本身就是一个二叉树
红黑树的约束:
1. 节点可以是红色的也可以是黑色的
2. 根节点是黑色的
3. 叶子节点(空节点)是黑色的
4. 每个红色节点的子节点都是黑色的
5. 任何一个节点到其每一个叶子节点的所有路径上的黑色节点数是相同的。
红黑树的特点:
查询速度非常快,趋近于平衡树,查找叶子元素最小和最大不能超过2倍。
List集合
java.util.List
接口继承自Collection接口,是单列集合的一个重要分支,在List集合当中允许出现重复的元素,所有的元素都是以一种线性方式进行存储的,在List集合当中基本上我们可以通过索引来访问集合当中的元素。另外List集合还有一个特点就是元素是有序的,指的是存取元素顺序相同。
List接口当中的常用API方法:增删改查
- public void add(int index,E element):将指定的元素,添加到给定集合中的指定位置上
- public E get(int index):根据指定的索引获取对应位置上的元素
- public E remove(int index):通过索引删除索引对应位置上的元素
- public E set(int index,E element) :在指定索引位置上替换成给定的元素,并且返回更新前的元素。