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时有了改进,是数组加链表的组合实现

数组特点:连续空间,访问迅速

链表特点:逻辑连续,新增删除节点迅速

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))

 

posted @ 2021-07-20 10:05  二娃千里眼  阅读(53)  评论(0)    收藏  举报