容器类
容器类
一、Iterator 迭代器
方法
- boolean hasNext()
如果仍有元素可以迭代,返回true(指针不下移) - E next()
返回迭代的下一个元素,指针下移 - void remove()
从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的集合,则迭代器的行为是不明确的。
使用Iterator遍历
1.创建一个迭代器
2.当下一个元素存在,输出下一个元素
Iterator iterator = coll.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
二、Collection
Collection是所有容器类的根接口
2.1.set 集合
无序性:储存的内容是无序的。
不可重复性:通过重写 待储存类的hasecode和equals来实现。如果同一个类的两个实例的属性相同就认定这两个实例是同一对象,那么new 相同属性的对象时,只存一个。验证如下:
public class IteratorTest {
public static void main(String[] args) {
Set coll = new HashSet();
coll.add(new Person(99));
coll.add(new Person(99));
coll.add(new Person(88));
coll.add("123");
System.out.println(coll);
}
}
运行结果:
2.2. List 列表
可以重复的,也是有序的
2.2.1List的实现类:ArrayList
存储结构:数组,Object[]动态数组
使用时机:当数组添加的元素被频繁查询时。
特点:有序有下标,存储元素可以重复
线程安全:线程不安全
常数
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//defaultcapacity_empty_elementdata默认容量_空_元素数据
DEFAULT_CAPACITY
private static final int DEFAULT_CAPACITY = 10;
//默认容量为10
属性
- elementData
ArrayList通过Object数组存储元素数据,这个数组的长度就是ArrayList的容量
transient Object[] elementData;
- size
实际大小
private int size;
初始化
- ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//元素数据为空数组
}
- ArrayList(int initialCapacity)
传入ArrayList的容量
private static final Object[] EMPTY_ELEMENTDATA = {};
public ArrayList(int initialCapacity) {//传入初始容量
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];//新建了长度为initialCapacity的数组为elementDate的内存
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
- ArrayList(Collection<? extends E> c)
将Collection对象中的元素添加到ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList的动态扩容机制
- 第一步:add触发扩容机制
要扩容的话,肯定是在add方法中,看一下add的源码:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
①首先使用 了ensureCapacityInternal()方法,大概意思为“确保内部容量”,size是当前已存元素个数,并非容量。通过ensureCapacityInternal()确保了容量足够,如果容量本身就足够那不做改变,如果没有空间存下一个元素了则增加容量。
②然后将e添加到当前size的下一个数组中。
现在主要看一下ensureCapacityInternal(size + 1)是如何判断和扩容的。
- 第二步:ensureCapacityInternal(size + 1)确定最小需求容量
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
①传入的是minCapacity,就是(需要的)最小容量,比如size==10,已经存了10个元素,现在又add了一次,此时size+1 == 11,minCapacity == 11。
②先判断,如果elementDate为空数组,那么最小容量 minCapacity就是max(10,minCapacity)
③使用ensureExplicitCapacity()方法,explicit是直率的,清楚的,方法大概的意思是直接地确保容量(我太难了我没想出来更好的dbqQAQ)算了直接源码呈上!!:
- 第三步:ensureExplicitCapacity()判断后如果要扩就通过grow扩
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
如果真实储存元素的数组elementDate的长度小于最小(需要的)容量 minCapacity,说明容量不够用了,不能放进下一个元素,那么就要扩容,grow(minCapacity)就是扩内存的最直接方法!
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//位运算,右移一位,相当于oldCapacity*0.5
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);
}
①新的容量是原先容量的1.5倍。
不停的add数,add1第10个时容量还是10,当add第11个时,容量变为15。
②oldCapacity >> 1,是位运算,比如add第11个数时,oldCapacity是10,10的二进制是1010,右移一位是101.0它的十进制是5,那么oldCapacity >> 1 == 5,newCapacity ==15。
2.1.2 List的实现类:LinkedList
存储结构:双向链表
2.1.3 List的实现类:Vector
底层也是基于数组的操作,所以基本和ArrayList一样
但是在jdk1.7之前,扩容机制与ArrayList不同,
遍历方法ArrayList有的Vector都有,但Vector还保留了一种老的遍历方式
Vector是线程安全的,而ArrayList是线程不安全的
三、 Map
属于双列集合(Map集合是和Collction集合并列的)
- 存储结构:key----> value
- 特性:是无序的,且key是不可以重复的,value值可以重复,key
Map中所有的可以组成了一个Set集合,可以添加null值,
key是唯一的,value值是可以重复的。
所有的key组成的了一个Set集合,所有value值组成了一个Collection集合
key和value之间是一对一的关系,一个key对应一个指定的value - 实现类:
HashMap,TreeMap,LinkedHashMap,Properties(HashMap是使用频率最高的) - 实际开发中key通常为String类型
方法
entrySet()
返回类型:Set
Map的实现类:HashMap
HashMap排序
思路:用Collections提供的自定义sort排序,而这里的sort只接受List类型,所以需要将HashMap转换成List
1.通过entrySet将hashmap转成set
Set aset = hashmap.entrySet();
2.使用ArrayLish(Collection o)构造器将Set传入
ArrayList alist = new ArrayList(aset);
3.使用Clooections.sort自定义排序
匿名创建一个Comparator接口,重写compare
public int compare(Object o1, Object o2){}
- 返回:
如果o1>o2, 返回正数
如果o1<o2, 返回负数
Collections.sort(alist, new Comparator(){
public int compare(Object o1, Object o2) {
if(((Employee)((Entry)o1).getValue()).getAge()>((Employee)((Entry)o2).getValue()).getAge())
return 1;
if(((Employee)((Entry)o1).getValue()).getAge()<((Employee)((Entry)o2).getValue()).getAge())
return -1;
return 0;
}
});
最后提供hashMap排序代码:
public void hashMapSout(){
Set aset = hashmap.entrySet();
ArrayList alist = new ArrayList(aset);
Collections.sort(alist, new Comparator(){
public int compare(Object o1, Object o2) {
if(((Employee)((Entry)o1).getValue()).getAge()>((Employee)((Entry)o2).getValue()).getAge())
return 1;
if(((Employee)((Entry)o1).getValue()).getAge()<((Employee)((Entry)o2).getValue()).getAge())
return -1;
return 0;
}
});
System.out.println(alist);
}