Java集合整理
•Collection
•List
◦ArrayList
◦LinkedList
◦Vector
◦Stack
•Set
◦HashSet
◦LinkedHashSet
◦TreeSet
•Map
•HashMap
◦LinkedHashMap
•TreeMap
•ConcurrentHashMap
•Hashtable
动态数组(ArrayList)
1,首先,原数组data,容量capacity为4,数组中元素size为4
2,然后新开一个数组new data(原数组data),开的空间要比原来大一些(从4–>8)
3,遍历原数组data,赋值到new data中。此时容量capacity为8,数组中的元素size为4
4,本身data指向4个空间的数组,现在指向8个空间的数组(new data也指向它)
总结
整个过程封装在一个函数内,对于new data这个变量在函数执行完便失效了,而data由于是类的成员变量,与整个类的生存周期一致(只要类还在使用,data就是有效的)
细节
对于原来4个空间的数组,由于没有对象指向它,所以利用java的垃圾回收机制将其回收
双向链表(LinkedList)
在单链表中,我们有一个数据域,还有一个指针域,数据域用来存储相关数据,而指针域则负责链表之间的“联系”。 而在双向链表中,我们需要有两个指针域,一个负责向后连接,一个负责向前连接。
如何实现数组和 List 之间的转换?
Arrays.aslist:数组转List
toArray:List转数组
ArrayList 和 Vector 的区别是什么?
•线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
•性能:ArrayList 在性能方面要优于 Vector。
•扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
Array 和 ArrayList 有何区别?
•Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
•Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
•Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
hash冲突
如果插入的key的hashcode相同,那么这些key也会被定位到Node数组的同一个格子里。如果同一个格子里的key不超过8个,使用链表结构存储。如果超过了8个,那么会调用treeifyBin函数,将链表转换为红黑树
迭代器(Iterator)
提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节
Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例
Iterator 的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
迭代器应用:
复制代码
list l = new ArrayList();
l.add("aa");
l.add("bb");
l.add("cc");
for (Iterator iter = l.iterator(); iter.hasNext();) {
String str = (String)iter.next();
System.out.println(str);
}
/*迭代器用于while循环
Iterator iter = l.iterator();
while(iter.hasNext()){
String str = (String) iter.next();
System.out.println(str);
}
*/
Iterator的接口定义:
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
使用: Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型
boolean hasNext():判断容器内是否还有可供访问的元素
void remove():删除迭代器刚越过的元素
迭代使用方法:(迭代其实可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类)
for(Iterator it = c.iterator(); it.hasNext(); ) {
Object o = it.next();
//do something
}
HashMap数组+链表
1,为什么用了一维数组:数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难
2,为什么用了链表:链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易
而HashMap是两者的结合,用一维数组存放散列地址,以便更快速的遍历;用链表存放地址值,以便更快的插入和删除!
loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 216=32,即扩大一倍
扩容,多线程同时执行resize,其他线程影响造成有的next()向回☞指形成环形链表
扩容
ArrayList:50%
HashMap:1
Vector:1
哪些集合类是线程安全的?
Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全的,不过在 JDK 1.5 之后随着 Java. util. concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap。
**
怎么确保一个集合不能被修改?
可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
示例代码如下:
List list = new ArrayList<>();
list. add(“x”);
Collection clist = Collections. unmodifiableCollection(list);
clist. add(“y”); // 运行时此行报错
System. out. println(list. size());
在 Queue 中 poll()和 remove()有什么区别?
•相同点:都是返回第一个元素,并在队列中删除返回的对象。
•不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。
代码示例:
Queue queue = new LinkedList();
queue. offer(“string”); // add
System. out. println(queue. poll());
System. out. println(queue. remove());
System. out. println(queue. size());