JavaSE入门级-第十一课-泛型与集合
前言
jdk1.5是一个重大版本跟新,其中加入了泛型的概念,极大的化简了数据类型转换的编程
对象的造型
如果两个类之间存在继承关系,他们的对象可以相互转换
l 向上转型
子类对象 转变 成为父类对象,不需要显示声明直接转
l 向下转型
父类对象 转变 成为子类对象,需要强制声明也称为强转,为了防止异常出现需要使用关键字 instanceof 判断是否是实例
实例代码:

类型问题
有如下两个 代码类:
某一个属性存在争议,有些时候要用 String 有些时候要用 Integer

客户端代码:

解决办法
使用Object,因为Object是超类,所有类的父类

客户端代码:使用存在缺陷因为需要造型

泛型介绍
泛型,顾名思义泛指所有的类型,它可以使用一个标识符表示任何的类型,在声明该对象的时候指明是哪个类型可以完成自动转换
泛型简单应用
客户端代码:

解析:
泛型可以是任意的表示符,可以是单个字符,或者多个字母,类中如果出现泛型在类名上必须声明,使用<>
泛型语法
l 标识符的含义,语法虽然可以随便写,但是根据编码规范是不能随便写的
T – Type,G – General,E - Element,K - Key,V - Value
l 泛型可以多个声明
class Part<A,B,C,D,E,F,G>{ // TODO } 随便多少个都行
l 泛型类型可以嵌套
Part<Part<String>> p = new Part<Part<String>>();
l 泛型上界限

可以使用 extends 表示泛型可以改变的范围
泛型类
类声明时定义泛型,类体可以使用
泛型方法
如果仅仅只是在某个方法中会出现泛型,可以直接在方法处声明

调用时直接传参数即可
泛型通配符
当一个方法入参是泛型时,我们又需要使用它的类型可以使用泛型通配符 ?
(以后会说)
泛型通配符的上下界
l 通配符的上限,只能是 Number 的子类,或者本身

l 通配符的下限,只能是 Type 的父类,或者本身

集合序列
练习
l 完成一个数组工具类,要求能实现,数组元素的新增,删除,指定位置新增,指定位置删除(使用多态)
ArrayList 简单介绍
上文中我们花了大量的篇幅去实现数组的节点改动方法,java针对这种问题有集合序列类
l ArrayList 实现元素的新增和删除
对比与数组的生命 ArrayList更加简便,构造一个ArrayList
ArrayList<String> strList = new ArrayList<String>();
l 添加元素

l 删除元素

练习
l 使用ArrayList完成对数组方法的改造
java.util.Collection<E>
集合接口规范,Collection是集合接口,定义了一系列方法,包括遍历,添加,移除
l add(E e)
添加元素
l addAll(Collection c)
添加一整个集合
l clear()
清空集合
l contains(Object o)
判断是否包含整个集合
l isEmpty()
判断集合内是否有其他元素
(注意:接口是方法的抽象集合,它定义出了一套规范,是一种标准,尽管它没有实现)
集合类图

(提醒:看上去很复杂,也没说都要学啊)
l 简化版本

java.util.List
List是Collection的子接口,List规定了可重复对象集合的规范
java.util.List
- java.util.ArrayList 底层实现是顺序表
- java.util.LinkedList 底层实现是链表
java.util.ArrayList
l List的一个实现类,常用方法:

l 代码实例:

其余方法参考文档
集合的遍历
遍历即循环输出,有标准序列 ArrayList<UserInfo> list = new ArrayList<UserInfo>();
l 标准for循环输出
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
l 简写for循环输出
for(UserInfo u:list){ // UserInfo表示列表类型 u表示标量 list表示循环目标序列
System.out.println(u);
}
简写for在遍历中使用较多
l 迭代器Iterator<E>
使用实现好的迭代器模型,完成迭代循环

练习:
l 使用集合序列完成员工信息录入系统
(要求:员工包括属性 员工号 姓名,实现系统能够完成员工的新增、修改、删除、查询)
java.util.LinkedList
List的一个实现类,基础实现原理是链表,对于元素的新增,移除操作更快
l LinkedList除List之外的特殊方法

代码实例:

练习:
l 使用System.currentTimeMills() 测验 ArrayList 和 LinkedList的效率
java.util.Vector(了解)
Vector是矢量队列,支持,新增,修改,删除 自己去了解
Vector是线程安全的
固定长度的List
数组工具类 Arrays 提供一个方法 asList(Object… objs); 能够直接获得 List

l 这个List不是ArrayList类,是Arrays的内部类ArrayList,特别注意这个List不能添加删除元素
java.util.Set
Set就是集合,很多元素放在一起,不能保证元素的顺序,或者说没有明显的顺序,和Collection行为几乎一致,只不过Set不允许出现null
java.util.HashSet
Set的实现类,大多数时候我们选择的类(数据和方法的集合),HashSet是线程不安全的
l 常用方法
和Collection类似,也提供了 add() remove() 等等,见文档
l 实现原理
HashSet会依赖于 hash表,根据对象计算hashcode进行去重
java.util.TreeSet
Set的实现类,与HashSet行为几乎一致,但是它是有序的,能够保证存取顺序
l 常用方法,见文档
栈和队列
在《数据结构》中,有两种常见的线性结构,栈和队列,这两种输入容器java做了实现
l 栈 java.util.Stack
继承至 Vector 具备List的方法,当然也有栈的特殊方法,存储策略 FILO

l 队列 java.util.Queue
继承至 Collection,存储策略 FIFO

映射
映射类型数据Map,如果没有连续的内存空间可以使用链表,也可以使用集合映射,映射数据以键值对的组合形式出现 Key-Value
java.util.Map
l Map的方法集合有:

l put(K,V) 方法
将元素键值对添加到 Map中
l get(K) 方法
根据key获取对应元素
java.util.HashMap
HashMap 是Map的常用实现类,底层数显原理,是使用数组和链表的结合(以后再说)
l 代码实例:

Map的keySet,values,entrySet
l keySet的返回是一个Set集合,能一次性获取所有的Key,用于遍历

l values的返回是一个 Collection集合,能一次性获取所有的Value

l entrySet的返回是一个Set集合,能够一次性获取所有的Entry
(注意:单独的Entry是一个接口,一个键值对就称为称为一个entry)
Map的四种遍历方式
有Map映射集合 Map<String,String> map = new HashMap<String,String>();
l 使用for循环遍历keySet

l 使用迭代器迭代keySet

l 使用简写for循环Entry

l 使用for直接遍历values

练习:
l 使用Map改造之前的员工系统
其它Map实现类
HashMap,TreeMap,HashTable,以及类图中显示的内容
集合 及 映射的问题总结
重要是不重要,但是面试就是爱问问问,工作中 只会用 ArrayList 和 HashMap
HashMap,TreeMap,HashTable的区别
l TreeMap是有序的,HashMap和HashTable是无序的
l HashTable是同步的,其它是不同步的即线程不安全的
l HashMap的效率会高于HashTable因为同步的原因
l HashTable不许null值
l HashMap允许null值,K-V都允许
List,Set的区别
l list允许对象重复,也可以添加null,存储是有序的
l set不允许对象重复,只能有一个null,存储是无序的
ArrayList,LinkedList,Vector的区别
l ArrayList是顺序表结构,查询遍历快,新增移除慢
l LinkedList是链表结构,查询慢,新增移除慢
l Vector和ArrayList类似,它是同步的,即线程安全
HashSet,TreeSet的区别
l HashSet依赖于hashcode可以放null
l TreeSet依赖于树 不可以放null
HashMap底层实现原理(了解)
HashMap允许空值,依赖于hashcode实现,在JDK1.2都是hash算法,在1.8时有了改进,是数组加链表的组合实现
l 数组特点:连续空间,访问迅速
l 链表特点:逻辑连续,新增删除节点迅速
l hash表特点:查询高效
我们来看一张map存储结构图:

l map.put方法
其实就是把key的值按照hash算法转换成对应的数组下标,并且挂在改下标后面,使用hash算法就不能避免重复问题,如果不同对象得到了相同的hashcode,那我们会使用链表去存储它,如果这个链表超过了一定的长度,我们会使用红黑树进行转换格式
l map.get 方法
首先按照key的hash值快速查找,如果没有找到下标位置的元素就返回null,如果找到之后是一个链表结构,表示这个hashcode有冲突,这时会拿key的具体值去equals每一个节点查找,知道找到具体的value为止
l 高效查找,高效新增
hashmap的设计,数组部分用于查询,链表部分用户新增节点
l JDK1.8的HashMap
在get() 之后,会有一个链表遍历部分,一般很吵出现多个冲突的情况,真实存在jdk1.8的做法是讲链表改造成为 红黑树 转变的标准是8个节点,当红黑树节点 少于6个又会转换成为链表
l HashMap的扩容因子
HashMap的默认长度是16,默认的扩容因子是0.75,意思就是当底层数据达到容量的75%数组就开始扩容,扩容的大小为初始化容量的2倍
(注意:alibaba 规范规定 新建HashMap(16))

浙公网安备 33010602011771号