常用类库:
泛型:
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定 义成参数形式
(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
1.在类上使用:在类创建时就声明这个类中有一种类型就是我们泛指的类型
public class ClassName<T>{
private T data;
}
2.泛型在接口中的使用
public interface IntercaceName<T>{
T getData();
}
实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下:
指定类型:
public class Interface1 implements IntercaceName<String> {
private String text;
@Override
public String getData() {
return text;
}
}
不指定类型:
public class Interface1<T> implements IntercaceName<T> {
private T data;
@Override
public T getData() {
return data;
}
}
3.泛型在方法中的使用
一般:private static <T> void 方法名(T a, T b) {}
比较特殊:private static <T> T 方法名(T a, T b) {}
泛型限定和通配符:
1. 在使用泛型时, 可以指定泛型的限定区域 ,
- 例如: 必须是某某类的子类或 某某接口的实现类,
格式: <T extends 类或接口1 & 接口2>
多态不能用在内容上
类型通配符是使用?代替方法具体的类型实参。
1 <? extends Parent> 指定了泛型类型的上届
2 <? super Child> 指定了泛型类型的下届
3 <?> 指定了没有限制的泛型类型
作用:
1、 提高代码复用率
2、 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
注意:
在编译之后程序会采取去泛型化的措施。
也就是说Java中的泛型,只在编译阶段有效。
在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加 类型检查
和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
集合:
类集成为Java对数据结构的实现。
类中最大的几个操作接口:
Collection(单值顶级接口)、Map(双值)、Iterator(迭代器)(三大重点)
链表与二叉树思路:
什么是链表:
链表 [Linked List]:链表是由一组不必相连(不必相连:可以连续也可以不连续)的内
存结构(节点),按特定的顺序链接在一起的抽象数据类型。
补充:
抽象数据类型(Abstract Data Type [ADT]):表示数学中抽象出来的一些操作的集合。
内存结构:内存中的结构,如:struct、特殊内存块...等等之类;
数组和链表的区别和优缺点:
数组是一种连续存储线性结构,元素类型相同,大小相等
数组的优点:
存取速度快
数组的缺点:
事先必须知道数组的长度
插入删除元素很慢
空间通常是有限制的
需要大块连续的内存块
插入删除元素的效率很低
链表是离散存储线性结构
n 个节点离散分配,彼此通过指针相连,每个节点只有一个前驱节点,每个节点只有一
个后续节点,首节点没有前驱节点,尾节点没有后续节点。
链表优点:
空间没有限制
插入删除元素很快
链表缺点:
存取速度很慢
链表常用的有 3 类: 单链表、双向链表、循环链表。
常见的数据结构:
栈:stack,又称堆栈, 栈(stack)是限定仅在表尾进行插入和删除操作的线性表。我们把允许插
入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为先进后出
的线性表 。
特点:
先进后出,入口出口都是栈的顶端位置
压栈:存元素。
弹栈:取元素。
队列:queue,简称队, 队列是一种特殊的线性表,是运算受到限制的一种线性表,只允许在表的
一端进行插入,而在另一端进行删除元素的线性表。队尾(rear)是允许插入的一端。队头(front)是
允许删除的一端。空队列是不含元素的空表。
特点:
先进先出,入口和出口各占一侧。
数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就
像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到
租房子的人。
特点:
查找元素快:通过索引,可以快速访问指定位置的元素
增删元素慢
指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原
数组元素根据索引,复制到新数组对应索引的位置。
指定索引位置删除元素:需要创建一个新数组,把原数组元素根据索引,复制到新数组对应
索引的位置,原数组中指定索引位置元素不复制到新数组中。
链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动
态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的
指针域。
特点:
多个节点之间,通过地址进行连接。
查找元素慢。
增删元素快
增加元素:只需要修改连接下个元素的地址即可。
删除元素:只需要修改连接下个元素的地址即可。
二叉树:binary tree ,是每个结点不超过2的有序树(tree) 。
二叉树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。
特点:速度特别快,趋近平衡树,查找叶子元素最少和最多次数不多于二倍。
Collection接口(重点)
Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接
口,分别是 java.util.List 和 java.util.Set 。其中, List 的特点是元素有序、元素可重
复。 Set 的特点是元素无序,而且不可重复。
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,
这些方法可用于操作所有的单列集合。方法如下:
public boolean add(E e) : 把给定的对象添加到当前集合中 。 public void clear() :清空集合中所有的元素。
public boolean remove(E e) : 把给定的对象在当前集合中删除。
public boolean contains(E e) : 判断当前集合中是否包含给定的对象。
public boolean isEmpty() : 判断当前集合是否为空。
public int size() : 返回集合中元素的个数。
public Object[] toArray() : 把集合中的元素,存储到数组中。
List集合:
java.util.List 接口继承自 Collection 接口,是单列集合的一个重要分支,习惯性地会将实现了
List 接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行
存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有
序,即元素的存入顺序和取出顺序一致。
特点:
1. 它是一个元素存取有序的集合。
2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素。
3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
List接口中常用方法
public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
public E get(int index) :返回集合中指定位置的元素。
public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新
前的元素。
ArrayList:
使用的是数组结构 对于增加删除慢,查找快
Vector:
Vector是同步的。
如果不需要线程安全实现,建议使用ArrayList代替Vector。
LinkedList(了解)
Iterator和ListIterator(方法整理)
forEach
用于迭代数组或集合(Collection集合)
语法:
for(数据类型 变量名:集合或数组名称){}
Set没有get获取数据,转换成迭代器(Iterator)或者toArray转换成数组进行数据提取。
不包含重复元素的集合。
如果将可变对象用作set元素,则必须非常小心。 如果在对象是集合中的元素时以影响equals比较的方式更
改对象的值,则不指定集合的行为。 这种禁令的一个特例是,不允许将一个集合作为一个元素包含在内。
HashSet:散列存放(哈希表)(不能存储重复元素)
不能保证存储顺序。
TreeSet和Comparable
TreeSet有序排列
如果是自定义的对象类型,那么会出错,需要对进行比较的类实现Comparable接口(Comparable<类名>)
同时实现相应的比较方法compareTo()
Comparator(排序)可以不用实现Comparable接口(了解)
多看其他人的相关的API总结
Map:
Map集合存储的是一个个键值对 数据。
哈希表概述:
哈希表是散列表
hashCode()返回的是int值
初始数组为长度为16
哈希表存入数据是需要进行对16取余的操作,取余的值为相应的下标,同一下标则生成链表依次存储。
(JDK1.8)哈希桶中的数据量大于8时,从链表转换为红黑二叉树
当哈希桶中的数据量减少到6时,从红黑二叉出转换成链表。
初始桶数量为16
散列因子为0.75
当有(散列因子)75%的桶中都有了数据的时候,哈希表进行扩容(16->32)
HashMap源码
HashMap中调用put方法
调用时,先通过哈希算法得到哈希值(键的哈希值),通过哈希值判断存储位置,然后判断是否满足存储条件,如果table为null,或者长度为0,则通过resize()方法对table扩容,不是则判断table[i]是否有元素,没有则直接存入,并且增加修改次数,判断容量,如果不足则扩容,重充足就结束。如果已经有了元素,则判断传入的key是否存在,有的话就对老值进行覆盖,然后增加修改次数,判断容量等结束,没有则继续判断是否为treeNode,是的话就用红黑数插入,不是就遍历链表,长度大于8则转为红黑树插入,不大于的话就链表插入,有重复继续覆盖。
使用案例:
HashMap/Hashtable/ConcurrentHashMap
/TreeMap/LinkedHashMap(使用方法大体一致)
map集合各子类区别分析:
HashMap,Hashtable,ConcurrentHashMap(都是数据容器)
(多线程. 线程安全与否)
HashMap(线程不安全)(同时操作)(效率高)
Hashtable (线程安全)(排队执行)(效率低)
ConcurrentHashMap(采用分段锁(分段排队)机制,保证线程安全,效率又比较高)
(下标相同再排队。)
TreeMap(存储时自动采用二叉树方式排序(从小到大))
LinkedHashMap(保证存储顺序)
散列表散列操作:
初始容量和负载因子
初始容量(合理,减少散列次数,减少哈希表的重新创建次数(扩容))
负载因子(散列因子(默认0.75)无限接近于1,节省空间,查询效率低,散列因子越小,空间浪费,查询效率高)
存储自定义对象:
自定义类型改变以后,哈希值也会发生改变,导致查找不到的情况,所以不要进行变化。
不要乱改存储在map集合中的键的对象,特别是自定义的对象。
JDK 9 集合新特性
创建固定长度集合的一些便捷方法:
List.of (有顺序)
Set.of(不保证顺序)
Map.of