容器
18. Java 容器都有哪些?
容器分类图:
|Collection接口
| ├List接口
| │-├LinkedList类
| │-├ArrayList类
| │-└Vector类
| │ └Stack类
| │
| ├Set接口
| │├HashSet类
| │├LinkedHashSet类 (LinkedHashSet也是HashSet的子类)
| │└SortedSet接口--NavigableSet接口--TreeSet类
|
|Map接口
| ├Hashtable类
| ├HashMap类
| ├IdentityHashMap类 (不常用)
| ├SortedMap接口--NavigableMap接口--TreeMap类
| ├LinkedHashMap类 (LinkedHashMap也是HashMap的子类)
| └WeakHashMap类
19. Collection 和 Collections 有什么区别?
Collection是一个集合接口,它包含了对集合对象进行一些基本操作的通用接口方法,Collection接口有很多的实现,比如List,Set;
Collections是针对集合类的一个包装类,它提供了一些静态方法以实现对集合的排序、搜索、线程安全化等操作。他不能被实例化,相当于一个工具类,服务于java的Collection框架。
20. List、Set、Map 之间的区别是什么?
List、Set都是实现了Collection接口,而Map没有实现Collection接口。
三者的区别:
I) 元素的重复性
List:允许有重复的元素,任何数量的重复元素都不会影响已加入的重复元素及其索引
Set:不允许有重复的元素,实现Set接口的所有类都不允许有重复的元素,若多次插入同一个元素,集合中只显示一个
Map:键值对的形式存在,不允许有重复的键,但是允许不同键的值相同。若插入重复的键,后者的值会覆盖前者。
II)元素的有序性
List:实现List接口的所有类都是有序的,保持了元素插入时的顺序
Set:大部分实现类是无序的,但是某些实现类是有序的,比如:TreeSet类,它实现了SortedSet接口,会将元素按升序排序;LinkedHashSet类也是有序的,保持元素输入时的顺序
Map:大部分实现类是无序的,但是某些实现类是有序的,比如:TreeMap类,它实现了SortedMap接口,会将元素按升序排序;LinkedHashMap类也是有序的,保持元素输入时的顺序
III)元素是否为空值
List:可以允许有多个空值(ArrayList,LinkedList,Vector三者均可)
Set:只允许有一个空值(HashSet和LinkedList允许一个null值,TreeSet不允许null值)
Map:只允许有一个空键,但可以有多个空值(HashMap、LinkedHashMap、WeakHashMap允许一个null键和多个null值,HashTable不允许null键和null值,TreeMap不允许null键but允许多个null值)
总结:
List | Set | Map | |
元素重复性 | 可重复 | 不可重复 | 键不可重复,值可以重复 |
元素有序性 | 有序 | 无序(except LinkedHashSet和TreeSet) | 无序(except LinkedHashMap和TreeMap) |
元素为空性 | 可为空 | 可有一个空元素 | 可有一个空键和多个空值 |
21. HashMap 和 Hashtable 有什么区别?
HashMap | HashTable | TreeMap |
允许一个null键,多个null值 | 不允许null键,null值 | 不允许null键,但允许多个null值 |
没有contains方法,有containsValue和containsKey方法 | Contains,containsValue和containsKey方法都有 | 没有contains方法,有containsValue和containsKey方法 |
非线程安全 | 线程安全 | 非线程安全 |
检索速度较HashTable快 | 检索速度慢(因为有线程安全机制) | 检索速度比HashMap慢 |
默认大小16,2的次幂 | 默认大小11,增容oldx2+1 |
22. 如何决定使用 HashMap 还是 TreeMap?
i.HashMap适合插入,删除元素,定位元素;
ii.TreeMap可以按自然顺序或者自定义顺序遍历元素;
iii.HashMap和TreeMap都是非线程安全;
iiii.HashMap通常比TreeMap检索速度要快一些(HashMap基于哈希表实现,TreeMap基于红黑树实现,二者结构使然。)
iiiii.HashMap的输出结果是无序的,TreeMap输出结果是有序的。
建议如果不需要排序的话多使用HashMap,若需要排序的话使用TreeMap
23. 说一下 HashMap 的实现原理?
HashMap的底层是由数组(bucket)和链表(linkedList)组成的,数组是HashMap的主体,链表则是为了解决哈希冲突而存在的。
HashMap基于hashing原理,通过put(key,value)来存储对象,get(key)来获取值对象。
HashMap进行put()操作时,会先调用键对象的hashCode()方法返回一个hashCode,通过hashCode获取bucket位置,然后将Entry对象存储其中(Entry对象包括键对象和值对象)。
HashMap进行get()操作时,会先调用键对象的hashCode()方法返回一个hashCode,通过hashCode获取bucket位置,然后通过键对象的equals()获取值对象。
若有两个及以上对象的hashCode相同,说明他们在同一个bucket中,会发生碰撞,这时候就会产生一条链表,entry对象会存储在同一条链表的下一个节点。(hashCode相同,不代表这俩对象就相同)
可参考:https://www.cnblogs.com/chengxiao/p/6059914.html;
https://blog.csdn.net/weixin_43748216/article/details/89532111
24. 说一下 HashSet 的实现原理?
HashSet的底层实现是HashMap,保存元素都是使用HashMap来保存的,key-value的key保存HashSet的元素值,value自定义了一个static final的Object虚拟对象。
参考:https://blog.csdn.net/weixin_43748216/article/details/89638782
25. ArrayList 和 LinkedList 的区别是什么?
ArrayList的底层结构是动态数组,根据下标访问元素,效率高;若在数组尾部添加元素也比较快,但是在指定位置删除或添加元素,需要一个个移动数组元素,效率较低。(为什么说是动态数组呢,是因为ArrayList在数组元素超过最大容量时,会进行扩容,扩容后的容量时扩容前的1.5倍)
LinkedList的底层结构是链表,访问元素需要遍历链表,效率较低;但是增删元素时,只需要改变指针的指向即可,效率高。
so,使用set()和get()时,使用ArrayList效率高;使用add()和remove()时,使用LinkedList较快。
26. 如何实现数组和 List 之间的转换?
/**
* Array转换为List
*/
Integer[] array = new Integer[5];
array[0] = 4432;
array[1] = 8432;
array[2] = 7654;
array[3] = 9874;
array[4] = 3454;
List<Integer> list = null;
list = Arrays.asList(array);
/**
* List转换为Array
*/
List<String> list1 = new ArrayList<>();
list1.add("世");
list1.add("园");
list1.add("会");
String[] array1 = list1.toArray(new String[list1.size()]);
27. ArrayList 和 Vector 的区别是什么?
ArrayList和Vector的底层结构都是动态数组。
二者的主要区别在扩容机制和线程安全与否:
i.ArrayList扩容后容量是原来的1.5倍,Vector扩容后容量是原来的2倍;
ii.ArrayList是非线程安全的,Vector是线程安全的,因此ArrayList的性能要比Vector好些。
28. Array 和 ArrayList 有何区别?
1. Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明。
2. Array只能存储同构的对象,而ArrayList可以存储异构的对象。
同构的对象是指类型相同的对象,若声明为int[]的数组就只能存放整形数据,string[]只能存放字符型数据,但声明为object[]的数组除外。而ArrayList可以存放任何不同类型的数据(因为它里面存放的都是被装箱了的Object型对象,实际上ArrayList内部就是使用"object[] _items;"这样一个私有字段来封装对象的)
3 在CLR托管对中的存放方式
Array是始终是连续存放的,而ArrayList的存放不一定连续。
4 初始化大小
Array对象的初始化必须只定指定大小,且创建后的数组大小是固定的,而ArrayList的大小可以动态指定,其大小可以在初始化时指定,也可以不指定,也就是说该对象的空间可以任意增加。
5 Array不能够随意添加和删除其中的项,而ArrayList可以在任意位置插入和删除项。
Array和ArrayList的相似点
1 都具有索引(index),即可以通过index来直接获取和修改任意项。
2 他们所创建的对象都放在托管堆中。
3 都能够对自身进行枚举(因为都实现了IEnumerable接口)。
ArrayList的一些特性
ArrayList的capacity属性值会随ArrayList中的项的实际大小来发生改变
通过ArrayList类的TrimToResize()方法可以将ArrayList实例中的空项去除以压缩体积。
在C#2.0中,建议大家尽量使用范型版的ArrayList,即System.Collection.Generics命名空间下的List<T>,这样不但保证了类型安全,而且由于没有了装箱和拆箱的过程,从而提高了对象处理的效率
29. 在 Queue 中 poll()和 remove()有什么区别?
/*
* 删除队列头的元素,这个方法和poll方法的不同之处在于,这个方法在队列为
* 空的时候选择抛异常
*
*/
E remove();
/*
* poll方法也是删除队列头的元素,如果队列为空的化,返回null
*
*/
E poll();
30. 哪些集合类是线程安全的?
HashTable,Vector,Stack
31. 迭代器 Iterator 是什么?
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
32. Iterator 怎么使用?有什么特点?
Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
Iterator的用法:
Queue<String> queue = new LinkedList<>();
queue.add("明");
queue.add("天");
queue.add("你");
queue.add("好");
Iterator iterator = queue.iterator();
if(iterator.hasNext()){
iterator.next();
iterator.remove();
}
System.out.println(queue);
33. Iterator 和 ListIterator 有什么区别?
我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。
但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:
1). ListIterator有add()方法,可以向List中添加对象,而Iterator不能
2). ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
3). ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
4). 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
34. 怎么确保一个集合不能被修改?
利用Collections提供的方法:
List使用的是Collections提供的unmodifiableList方法
List<String> list = new LinkedList<>();
list.add("明");
list.add("天");
list.add("你");
list.add("好");
list = Collections.unmodifiableList(list);
list.add("世界");
运行以上代码会报错:Exception in thread "main" java.lang.UnsupportedOperationException
Map使用的是Collections提供的unmodifiableMap方法
Map<String,Object> map = new HashMap<>();
map.put("1","明");
map.put("2","天");
map.put("3","你");
map.put("4","好");
map = Collections.unmodifiableMap(map);
map.put("5","世界");
运行以上代码会报错:Exception in thread "main" java.lang.UnsupportedOperationException