集合位于java.util包
集合概念
存储对象的容器,定义了对对象常用的方法
与数组的区别
- 数组的长度固定
- 数组可以存储基本数据类型和引用类型,集合只能存储引用类型
Collection体系集合
- Collection:该体系结构的根接口,被称为"集合"
- List:有序、可重复
- ArrayList
- LinkedList
- Vector
- Set:无序、不可重复
- HashSet
- SortedSet
- TreeSet
- List:有序、可重复
Collection接口
包含有序或者无序,重复或者不重复的集合
常用方法
//添加一个对象
boolean add(Object obj);
//将集合中的所有对象添加到此集合中
boolean addAll(Collection c);
//清除该集合中的所有对象
void clear();
//检测是否包含对象o
boolean contains(Object o);
//比较此集合是否与指定对象相同
boolean equals();
//判断集合是否未空
boolean isEmpty();
//删除集合中的o对象
boolean remove(Object o);
//删除在本集合和c集合中均存在的元素
boolean removeAll(Collection<?> c)
//返回集合中元素的个数
int size();
//将集合转换成数组
Object[] toArray();
//返回在此集合上的进行迭代的迭代器
Iterator<E> iterator();
迭代器就是用来遍历集合的一种方式
Iterator
常用方法
//如果还有元素,返回true
boolean hasNext();
//返回下一个元素
E next();
void remove();
注意事项
- 迭代过程中不能使用集合的提供的remove()方法
List接口
有序、元素可以重复
常用方法
//在index位置插入对象obj
void add(int index, Object obj);
//将集合中的所有对象添加到此集合中index位置
boolean addAll(int index, Collection c);
//返回集合中指定位置的元素
Object get(int index);
//返回from和to之间的集合元素
List subList(int from, int to);
//返回列表中第一次出现指定元素的索引
int indexOf(Object obj);
//按适当顺序返回迭代器
ListIterator listIterator();
//按适当顺序返回迭代器,从指定的位置开始
ListIterator listIterator(int index);
//用指定元素替换列表中指定位置的元素
E set(int index, E element);
ListIterator
常用方法
//插入元素
void add(E e);
//逆向遍历列表,如果有元素则返回true
boolean hasPrevious();
//返回next后续调用所用返回元素的索引
int nextIndex();
//返回前一个元素
E previous();
//返回对previous的后续调用所返回元素的索引
int previousIndex();
//替换元素
void set(E e);
#List实现类
ArrayList
- 数组结构实现,查询速度快,增删慢
- JDK1.2版本,运行效率快,线程不安全
Vector
- 数组结构实现,查询速度快,增删慢
- JDK1.0版本,运行效率快,线程安全
LinkedList
- 双向链表结构实现,增删快,查询慢
ArrayList
常用功能
- 增
- add();
- 删
- remove(Object o);
- 遍历
- Iterator
- hasNext()
- next()
- remove()
- ListIterator
- hasNext()
- next()
- remove()
- hasPrevious
- previous()
- Iterator
- 判断
- contains()
- isEmpty()
- 查找
- indexOf()
注意事项
- remove方法参数为对象时,比较的是地址是否相同
ArrayList源码分析
变量
- int DEFAULT_CAPACITY:默认容量
- Object[] elementData:存放元素的数组
- int size 实际元素个数
add方法解析
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//确保每次添加元素前数组空间足够
//minCapacity = 数组元素总数+1
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//判断集合的构建是调用了哪个构造函数,如果是无参构造函数则返回DEFAULT_CAPACITY、否则返回minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//当数组的容量elementData.length小于minCapacity(siz + 1)时进行扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//每次扩容旧数组空间/2的大小,如果扩容之后数组仍然太小,则将最小容量赋值给newCapacity
//如果扩容之后太大,那么将MAX_ARRAY_SIZE赋值给newCapacity
//将数组复制到大小为newCapacity的新的数组中去,并将引用赋值给elementData
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector
常用方法
//返回枚举器,与迭代器功能相似
Enumration elements();
Enumration
常用方法
boolean hasMoreElements();
Object nextElement();
LinkedList
变量
- int size 实际元素个数
- Node first 指向第一个结点
- Node end 指向最后一个结点
源码解析
add方法
public boolean add(E e) {
linkLast(e);
return true;
}
// 创建新的结点,连接前一个节点
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
ArrayList与LinkedList的不同实现方式
ArrayList必须开辟连续的内存空间,而LinkedList不需要
泛型
JDK1.5引入的新特性,本质是参数化类型,把类型作为参数传递
常见形式
- 泛型类
- 泛型接口
- 泛型方法
语法
<T,......> T称为类型占位符,表示一种引用类型
优势
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性
注意事项
- 泛型只能是引用类型
- 不同的泛型对象不能相互赋值
实例代码
//泛型类
public class MyGeneric <T>{
T t;
public void show(T t) {
System.out.println(t);
}
public T getT() {
return t;
}
//泛型接口
public interface MyInterface<T> {
abstract T server(T t);
}
//泛型接口实现方式一
public class MyInterfaceimpl implements MyInterface<String>{
@Override
public String server(String t) {
return t;
}
}
//泛型接口实现方式二
public class MyInterfaceimpl2<T> implements MyInterface<T>{
@Override
public T server(T t) {
return t;
}
}
//泛型方法
public <T> T show(T t) {
System.out.println(t);
return t;
}
public class GenericTest {
public static void main(String[] args) {
MyGeneric<String> mg = new MyGeneric<>();
mg.t = "11";
mg.show(mg.t);
System.out.println(mg.getT());
MyGeneric<Integer> i = new MyGeneric<>();
i.t = 39;
i.show(200);
System.out.println(i.getT());
MyInterfaceimpl m = new MyInterfaceimpl();
System.out.println(m.server("hohoho"));
MyInterfaceimpl2<Integer> m2 = new MyInterfaceimpl2();
System.out.println(m2.server(2378));
MyGenericMethod mm = new MyGenericMethod();
mm.show(53.1123);
}
}
泛型集合
参数化类型,类型安全的集合,强制集合元素的类型必须一致
特点
- 编译时即可检查,而非运行时抛出异常
- 访问时不必强制类型转换
- 不同泛型之间引用不能相互赋值,泛型不存在多态
Set集合
方法全部继承自Collection方法
Set的实现类
- HashSet
- 基于HashCode计算元素存放位置
- 当存入元素的哈希值相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
- TressSet
- 基于排序顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- CompareTo来判断是否为重复元素
HashSet
数据结构
数组+链表+红黑树
存储过程
- 根据hashcode计算存储位置,如果位置为空则直接保存,如果不为空,则执行2
- 执行equals,如果equals为true则认为是重复的,反之以链表结点的形式链接
实现属性相同的对象不重复存储
- 重写hashCode()方法,计算每个属性的哈希值,并相加返回,此时两个值相同对象的哈希值相同
- 重写equals方法,如果每个属性值相同,则判断两个对象相同
TreeSet
数据结构
红黑树
红黑树
元素实现Comparable接口
TreeSet的存储结构为红黑树,需要确认比较的数值是哪个,因此需要确定比较的值
// 重写compare
@override
public int compare(Person o1, Person o2){
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().comareTo(o2.getName());
return n1 == 0 ? n2 : n1;
}
Comparator比较器
定制比较规则,元素可以不实现Comparable接口
TreeSet t1 = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Dog d1 = (Dog)o1;
Dog d2 = (Dog)o2;
int n1 = d1.getName().compareTo(d2.getName());
int n2 = d1.getAge() - d2.getAge();
return n2==0?n1:n2;
}
});
Map集合
- Map I
- HashMap C
- SortedMap I
- TreeMap C
I表示接口,C表示类
特点
- 存储任意键值对
- 键:无序、无下标、不允许重复
- 值:无序、无下标、允许重复
常用方法
V put(K key,V value);
Object get(Object key);
//返回所有key
Set keySet();
//返回包含所有值的Collection集合
Collection<V> values();
//返回键值匹配的Set集合
Set<Map.Entry<K,V>> entrySet();
遍历方式
- 使用keySet方法
for(String key: s) {
System.out.println(key + " " + m.get(key));
}
- 使用entrySet方法
Set<Map.Entry<String, Integer>> ss = m.entrySet();
for (Map.Entry<String, Integer> mm : ss) {
System.out.println(mm.getKey() + " " + mm.getValue());
}
Iterator i = ss.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
一个Entry类型就是一个键值对
HashMap
JDK1.2加入,线程不安全,运行效率快,允许使用null作为key或者value
存储结构
数组+链表+红黑树
案例使用
HashMap<Student, String> s = new HashMap();
Student a = new Student("芜湖1", 18);
Student b = new Student("芜湖2", 19);
Student c = new Student("芜湖3", 20);
s.put(a,"a");
s.put(b,"b");
s.put(c,"c");
//对象地址不同,会插入。如果想要以属性作为基准,与HashSet相同,重写HashCode和equals方法
s.put(new Student("芜湖3", 20),"d");
System.out.println(s.size());
System.out.println(s.toString());
Set<Student> ss = s.keySet();
for(Student st: ss) {
System.out.println(st.toString() + " " + s.get(st));
}
Set<Map.Entry<Student, String>>et = s.entrySet();
System.out.println(et.toString());
源码分析
变量
//默认容量
int DEFAULT_INITIAL_CAPACITY = 16;
//最大容量
int MAXIMUM_CAPACITY = 1<<30;
//默认加载因子,当大于容量的75%时进行扩容
float DEFAULT_LOAD_FACTOR = 0.75f;
//当链表长度大于8时,并且数组长度大于等于64,就将该链表变为红黑树
int TREEIFY_THRESHOLD = 8;
//当链表长度小于6时,调整会链表结构
int UNTREEIFY_THRESHOLD = 6;
哈希表中的数组
Node<K,V>[] table;
//元素的个数
int size
构造方法
//此时size为0,table为null
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
put
源码学习:blog.csdn.net/Z_ChenChen/…
总结
- HashMap刚创建时table为null,添加第一个元素时容量调整为16
- 当元素个数大于阀值会进行空若,扩容,扩容为原来的两倍
- 每当链表长度大于8并且元素个数大于64,则会调整为红黑树
- 当链表长度小于6时调整为链表
- jdk1.8以前从链表头插入,1.8以后从尾部插入
TreeMap
实现SortedMap接口(是Map的子接口),可以对key进行自动排序
数据结构
红黑树
使用方法
与TreeSet相同
Collections工具类
常用方法
//反转顺序
void reverse(List<?> list);
//随机重置集合元素顺序
void shuffle(List<?> list);
//升序排序,必须实现Comparable接口
void sort(List<?> list);
//将j复制到i中去,注意需要将i的空间大小变得与j一致再复制
copy(List<?> i,List<?> j)
toArray(Array[] a);
//数组转成集合,集合受限,不能进行增删
List<?> Array.asList(Array);