标签:out static images 双向链表 饿汉 overflow 遍历 使用 cte
Collection
和 Map
两种体系
Collection
接口:单列数据,定义了存取一组对象的方法的集合Map
接口:双列数据,保存具有映射关系 "key-value对" 的集合boolean add(Object obj) / addAll(Collection<?> coll)
:添加元素/某集合的所有元素int size()
:获取有效元素个数void clear()
:清空集合boolean isEmpty()
:是否是空集合boolean contains(Object obj)
:是通过元素的 equals()
来判断是否是同一个对象boolean containsAll(Collection<? extends E> c)
:也是调用元素的 equals()
来比较的。拿两个集合的元素挨个比较boolean remove(Object obj)
:通过元素的 equals()
判断是否是要删除的那个元素。只会删除找到的第 1 个元素boolean removeAll(Collection<?> coll)
:取当前集合的差集boolean retainAll(Collection<?> c)
:把交集的结果存在当前集合(this) 中,不影响形参集合 cboolean equals(Object obj)
:集合是否相等Object[] toArray()
:转成对象数组// ↑→ public static <T> List<T> asList(T... a)
List list = Arrays.asList(new Integer[]{1, 2, 3});
System.out.println(list); // [1, 2, 3]
List list2 = Arrays.asList(new int[]{1, 2, 3}); // 基本类型数组被当作一个元素
System.out.println(list2); // [[I@4554617c]
List list3 = Arrays.asList(1,2, 3);
System.out.println(list3); // [1, 2, 3]
int hashCode()
:获取集合对象的哈希值Iterator<E> iterator()
:返回迭代器对象,用于集合遍历public interface Collection<E> extends Iterable<E>
Iterator
对象称为迭代器(设计模式的一种),主要用于遍历 Collection
集合中的元素Collection<I>
继承了 java.lang.Iterable<I>
,该接口有一个 iterator()
,那么所有实现了Collection<I>
的集合类都有一个 iterator()
,用以返回一个实现了 Iterator<I>
的对象Iterator
仅用于遍历集合,Iterator
本身并不提供承装对象的能力。如果需要创建 Iterator
对象,则必须有一个被迭代的集合iterator()
都得到一个全新的迭代器对象,游标(cursor) 默认都在集合的第 1 个元素之前boolean hasNext()
:判断 iterator 内是否存在下1个元素,如果存在,返回true,否则返回false(注意,这时上面的那个指针位置不变)E next()
:返回 iterator 内下1个元素,同时上面的指针向后移动一位。如果不断地循环执行next()方法,就可以遍历容器内所有的元素了void remove()
:删除 iterator 内指针的前1个元素,前提是至少执行过1次 next()
迭代的错误写法 // 在调用 it.next()
之前必须要调用 it.hasNext()
进行检测。若不调用,且下一条记录无效,直接调用 it.next()
会抛出 NoSuchElementException
Iterator it = c.iterator();
Object obj;
while((obj = it.next()) != null) // 第 c.size() + 1 次,会抛异常
System.out.println(obj);
Iterator iter = coll.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
if(obj.equals("Tom")) {
iter.remove();
}
}
remove()
,不是集合对象的 remove(obj)
next()
或在上一次调用 next()
之后已经调用了 remove()
, 再调用 remove()
都会报 IllegalStateException
JDK5.0 起,提供了 for each
循环迭代访问 Collection 和 数组。编译器简单地将 for each
循环翻译为带有迭代器的循环。 for each
循环可以与任何实现了 Iterator<I>
的对象一起工作,这个接口直播暗含了一个方法:Iterator<E> iterator()
。
Collection<I>
扩展了 Iterator<I>
。因此,对于标准类库中的任何集合都可以使用 for each
循环。
List
替代数组List<I>
的实现类常用的有:ArrayList
、LinkedList
和 Vector
JDK 7
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private transient Object[] elementData;
private int size;
public ArrayList() {
this(10);
}
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
}
JDK 8
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final int DEFAULT_CAPACITY = 10;
transient Object[] elementData;
private int size;
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
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);
}
}
ArrayList list = new ArrayList();
// 底层创建了长度是 10 的 Object[] elementData
list.add(123);
// elementData[0] = new Integer(123);list.add(11);
// 如果此次的添加导致底层 elementData[]
容量不够,则扩容ArrayList list = new ArrayList(int capacity)
ArrayList list = new ArrayList();
// 底层 Object[] elementData
初始化为{}
,并没有创建长度为 10 的数组list.add(123);
// 第一次调用 add()
时,底层才创建了长度 10 的数组,并将 数据123 添加到 elementData[0]
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
public LinkedList() {}
// 双向链表
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
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++;
}
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
}
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
public Vector() {
this(10);
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
void add(int index, E ele)
:在 index
位置插入 ele
boolean addAll(int index, Collection<? extends E> c)
:从 index
位置开始将 c
中的所有元素添加进来E get(int index)
:获取指定 index
位置的元素int indexOf(E obj)
:返回 obj
在集合中首次出现的位置int lastIndexOf(E obj)
:返回 obj
在集合中末次出现的位置E remove(int index)
:移除指定 index
位置的元素,并返回此元素E set(int index, E ele)
:设置指定 index
位置的元素为 ele
List<E> subList(int fromIndex, int toIndex)
:返回 [fromIndex, toIndex)
位置的子集合Set<I>
是 Collection
的子接口,Set<I>
没有提供额外的方法Set<I>
不允许包含相同(根据 equals()
)的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败Set<I>
存储无序、不可重复的数据
equals()
判断时,不能返回 true
,即相同的元素不能重复添加
Set<I>
的典型实现,大多数时候使用 Set 集合时都使用这个实现类hashCode()
比较相等,并且两个对象的 equals()
返回值也相等equals()
和 hashCode()
,以实现对象相等规则。即:"相等的对象必须具有相等的散列码"
hashCode()
的基本原则
hashCode()
应该返回相同的值equals()
比较返回 true 时,这两个对象的 hashCode()
的返回值也应相等equals()
比较的 Field,都应该用来计算 hashCode 值equals()
的基本原则
equals()
的时候,总是要改写 hashCode()
,根据一个类的 equals()
(改写后),两个截然不同的实例有可能在逻辑上是相等的。但是,根据 Object.hashCode()
,它们仅仅是两个对象, 因此,违反了 "相等的对象必须具有相等的散列码"equals()
的时候一般都需要同时复写 hashCode()
。通常参与计算 hashCode()
的对象的属性也应该参与到 equals()
中进行计算hashCode()
,有 31 这个数字?HashSet 底层:数组 + 链表的结构
当向 HashSet 集合中存入一个元素 a,HashSet 首先调用元素 a 所在类的 hashCode()
,计算元素 a 的 hashCode 值,此 hashCode 值接着通过某种散列函数计算出在 HashSet 底层数组中的存放位置(这个散列函数会与底层数组的长度相计算得到在 数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布, 该散列函数设计的越好) ,判断数组此位置上是否已经有元素:
equals()
equals()
返回 true,则元素 a 添加失败equals()
返回 false,则元素 a 添加成功 ---> [情况3]对于添加成功的 [情况2] 和 [情况3] 而言,元素 a 与已经存在指定索引位置上数据以链表的方式存储:
public void test() {
HashSet set = new HashSet();
Person p1 = new Person("AA",21);
Person p2 = new Person("BB",22);
set.add(p1);
set.add(p2);
p1.name = "CC";
set.remove(p1);
System.out.println(set);
set.add(new Person("CC",21));
System.out.println(set);
set.add(new Person("AA",22));
System.out.println(set);
}
-------------------------------------
[Person{name=‘CC‘, age=21}, Person{name=‘BB‘, age=22}]
[Person{name=‘CC‘, age=21}, Person{name=‘BB‘, age=22}, Person{name=‘CC‘, age=21}]
[Person{name=‘CC‘, age=21}, Person{name=‘BB‘, age=22}, Person{name=‘CC‘, age=21}, Person{name=‘AA‘, age=22}]
TreeSet
是 SortedSet<I>
的实现类,TreeSet
可以确保集合元素处于排序状态TreeSet
底层使用 [红黑树] 结构存储数据Comparator<? super E> comparator()
E first()
E last()
E lower(Object e)
E higher(Object e)
SortedSet<E> subSet(fromElement, toElement)
SortedSet<E> headSet(toElement)
SortedSet<E> tailSet(fromElement)
TreeSet 会调用集合元素的 compareTo(T obj)
来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。所以,如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable<I>
Comparable 的典型实现:
![](_v_images/20200710220928328_1902.png =700x)
compareTo()
,后面添加的所有元素都会调用 compareTo()
进行比较compareTo(T obj)
比较返回值equals()
时,应保证该方法与 compareTo(T obj)
有一致的结果:如果两个对象通过 equals()
比较返回 true,则通过 compareTo(T obj)
比较应返回 0。 否则,让人难以理解。Comparable<I>
,如果元素所属的类没有实现 Comparable<I>
,或不希望按照升序(默认情况)的 方式排列元素或希望按照其它属性大小进行排序,则考虑使用 [定制排序]。定制排序,通过 Comparator<I>
来实现,需要重写 compare(T o1, T o2)
int compare(T o1, T o2)
,比较 o1 和 o2 的大小:如果方法返回正整数,则表示 o1 大于 o2;如果返回 0,表示相等;返回负整数,表示 o1 小于 o2。Comparator
比较两个元素返回了 0Comparator<I>
的实例作为形参传递给 TreeSet 的构造器:TreeSet(Comparator<? super E> comparator)
ClassCastException
标签:out static images 双向链表 饿汉 overflow 遍历 使用 cte
原文地址:https://www.cnblogs.com/liujiaqi1101/p/13289266.html