欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

集合总结

程序员文章站 2022-03-05 12:05:23
...
题外话:Eclipse怎么关联源码(Ctrl+鼠标左键可以进入相应的类)

找到安装java JDK时的路径,在该路径,找到src.zip就行

1.集合分类

都在java.util的包下面

1.1 Collection&&Collections

Collections是一个集合类,该类专门由操作或返回集合的静态方法组成
public class Collections {
}

Collection是一个接口,接口定义如下

public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    ......
    void clear();
    boolean equals(Object o);
    int hashCode();
}
// List继承Collection,又重写了Collection接口中的那些方法
public interface List<E> extends Collection<E> {
}
// Set继承Collection
public interface Set<E> extends Collection<E> {
}
如图可以看出Collection是List与Set的根接口,而Map与Collection接口没关系,但是属于集合类的一部分
集合总结
集合总结
集合总结

2.集合的基本操作

2.1 List

2.1.1 ArrayList

private static final int DEFAULT_CAPACITY = 10; // 数组默认大小为10
private int size;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;

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);
	    }
	}
public ArrayList() {
	    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
	}
public boolean add(E e) {
	ensureCapacityInternal(size + 1);
	elementData[size++] = e;
	return true;
}
public void ensureCapacityInternal(int minCapacity) {
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	}
	ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
	/**
	 * 在ArrayList<E> extends AbstractList<E>其抽象类中定义的protected transient int modCount = 0;
	 */
	modCount++;
	if (minCapacity - elementData.length > 0)
		grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1); // 右移1位,除以2,容量增为原来的1.5倍
	if (newCapacity - minCapacity < 0)
		newCapacity = minCapacity;
	if (newCapacity - MAX_ARRAY_SIZE > 0)
		newCapacity = hugeCapacity(minCapacity);
	elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
	if (minCapacity < 0)
		throw new OutOfMemoryError();
	return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
public int size() {
	return size;
}
public boolean isEmpty() {
	return size == 0;
}
public void clear() {
	modCount++;
	for (int i = 0; i < size; i++)
		elementData[i] = null;
	size = 0;
}

说明:
1)ArrayList底层是使用数组存储的,当数组大小不足存放新增元素的时候,才会发生扩容。在add操作中,ArrayList首先会调用ensureCapacityInternal方法进行扩容检测的。如果数组大小不足,则会自动扩容;如果扩容后的大小超出数组最大的大小,则会抛出异常。
2)fail-fast机制的实现
fail-fast机制也叫作”快速失败”机制,是Java集合中的一种错误检测机制。在对集合进行迭代过程中,除了迭代器可以对集合进行数据结构上进行修改,其他的对集合的数据结构进行修改,都会抛出ConcurrentModificationException错误。这里,所谓的进行数据结构上进行修改,是指对存储的对象,进行add,set,remove操作,进而对数据发生改变。
ArrayList中,有个modCount的变量,每次进行add,set,remove等操作,都会执行modCount++。在获取ArrayList的迭代器时,会将ArrayList中的modCount保存在迭代中,每次执行add,set,remove等操作,都会执行一次检查,调用checkForComodification方法,对modCount进行比较。如果迭代器中的modCount和List中的modCount不同,则抛出ConcurrentModificationException。
3)transient关键字
当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。例如,当反序列化对象——数据流(例如,文件)可能不存在时,原因是你的对象中存在类型为java.io.InputStream的变量,序列化时这些变量引用的输入流无法被打开。其实和hibernate中的注解@Transient一样

2.1.2 LinkedList


2.2 Set

Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。
看源码HashSet底层就是HashMap
集合总结
而TreeSet底层就是TreeMap
集合总结

2.2.1 HashSet
Set<Integer> set = new HashSet<Integer>();
set.add(1);set.add(2);set.add(3);
System.out.println(set.size()); //输出2
set.clear();
set.add(1);set.add(2);set.add(2);
System.out.println(set.size()); //输出3,说明set中不会出现重复元素
// 遍历set
set.clear();
set.add(1);set.add(3);set.add(2);
for(Integer i: set) {
    System.out.println(i); //输出1 2 3 说明set是有序的(数字按123,字母按abc来)吗?XX大错特错XX
}
// 但是这个为什么无序呢
HashSet<Integer> set = new HashSet<Integer>();  
set.add(2007111315);  
set.add(2007111314);  
set.add(2007111318);  
set.add(2007111313);  
System.out.println(set); // 输出[2007111314, 2007111315, 2007111313, 2007111318]无序
TreeSet ts = new TreeSet(set); 
ts.comparator();
System.out.println(set); // 输出有序(把HashSet作为构造参数放到TreeSet中就可以排序)
上面是因为HashSet是根据哈希算法决定其在堆内存的位置,然后Integer(或String)其哈希值计算出的位置都是统一的,恰好是满足这种123,abc的顺序,所以输出set元素表面上看起来是有序。反例可以看下下面这个
public class SetOrderTest {
	public static void main(String[] args) {
		Set<User> set = new HashSet<User>();
		set.add(new User("c"));
		set.add(new User("b"));
		set.add(new User("a"));	
		for(User i: set) {
			System.out.println(i.getName()); // 输出可能cba abc等各种顺序,证明了无序
		}
	}
}

class User{
	String name;
	public User(String name) {
		super();
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
2.2.2 TreeSet

TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列。如果是TreeSet<Person>在实体里面指定比较的规则,需要在自定义类(Person)中实现Comparable接口,并重写接口中的compareTo方法,这样输出就不会报错ClassCastException

Set<String> set = new TreeSet<String>();  
set.add("abc");  
set.add("xyz");  
set.add("rst");          
System.out.println(set);//输出  [abc, rst, xyz] 

3.2 Map

Map集合使用键(key)值(value)来保存数据,其中值(value)可以重复,但键(key)必须是唯一,也可以为空,但最多只能有一个key为空,它的主要实现类有HashMap、TreeMap、Hashtable。

3.2.1 HashMap

3.2.2 TreeMap

3.2.3 Hashtable



相关标签: 集合深入学习