文章目录
1、Java集合框架的基础接口有哪些?
Collection为集合层级的根接口。
一个集合代表一组对象,这些对象即为它的元素。
Java平台不提供这个接口任何直接的实现。
Set是一个不能包含重复元素的集合。
这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。
List是一个有序集合,可以包含重复元素。
你可以通过它的索引来访问任何元素。List更像长度动态变换的数组。
Map是一个将key映射到value的对象.
一个Map不能包含重复的key:每个key最多只能映射一个value。
一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator
2、Iterator与ListIterator有什么区别?
Iterator:只能正向遍历集合,只可以向前遍历,适用于获取移除元素。
ListIerator:ListIerator可以双向遍历,ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。
3、在Hashtable上下文中同步是什么意思?怎样使Hashmap同步?
同步意味着在一个时间点只能有一个线程可以修改哈希表,任何线程在执行hashtable的更新操作前需要获取对象锁,其他线程等待锁的释放。
HashMap可以通过Map m = Collections.synchronizedMap(hashMap)来达到同步的效果。
4、map的遍历方式
第一种 这是最常见的用法,
优点:这种用法可以同时拿到key和value值。
缺点:如果map是空,将会出现空指针异常,那么每次在对map遍历以前,就要先进行判空
public static void forEachMap(Map<String,String> map) {
for ( Map.Entry<String,String> entry : map.entrySet()) {
System.out.println(entry.getKey()+entry.getValue());
}
}
第二种
只遍历key或者value。
比第一种方法的效率略微有提升,而且代码也能简洁一点。
同样,这种方法也需要判断map是否为空
public static void forEachMap2(Map<String,String> map){
for (String str :map.keySet()){
System.out.println(str);
}
for (String str :map.values()){
System.out.println(str);
}
}
第三种
使用迭代器的方式
public static void forEachMap1(Map<String, String> map) {
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey() + entry.getValue());
}
}
// 使用迭代器但是不适用泛型
public static void forEachMap4(Map<String, String> map) {
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry entry= (Map.Entry) iterator.next();
//这里的类型转换的原因是,如果不加String,那么背默认为两个object,不能相加
System.out.println((String)entry.getKey() + entry.getValue());
}
}
第四种
先拿到map的key值,再拿取value值。 这种方式效率比较低,一般不推荐使用
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key = " + key + ", Value = " + value);
}
5、ArrayList、Vector和LinkedList有什么区别?
1.ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构。
2.对于随机访问的get和set方法,ArrayList要优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
LinkedList经常用在增删操作较多而查询操作很少的情况下,ArrayList则相反。
这三个类都继承自List接口,内部元素可以重复但有序。都在java.util包中,都是可伸缩的数组,也就是说可以动态改变数组的长度。
ArrayList和Vector:都是基于Object[] 对象数组实现的。它们在创建的时候会申请连续的存储空间来存储数据。总结:
他们支持使用下标来访问元素,索引数据的速度回比较快。
因为是顺序存储,插入数据的时候需要移动容器中的数据,所以对数据的插入操作效率会比较慢。
ArrayList和Vector都有一个初始化的容量值,当添加
进入容易中的数据长度大于容器的长度时,它们会自动动态扩充
他们的存储单元。Vector默认扩充为原来的2倍,而ArrayList扩充为原来的1.5倍。
区别:
-
它俩最大的区别就是同步的使用。ArrayList中的方法都是非同步的,所以ArrayList不是安全的,Vector中的大多数方法都是直接或者间接同步的,所以Vector是线程安全的。相对而言,因为Vector是线程安全,而ArrayList线程不安全,所以ArrayList性能较Vector高。
-
LinkedList是采用双向列表实现的,对数据的索引需要从列表头开始遍历,因此用于随机访问则效率比较低。但是因为插入元素是不需要对数据进行移动,因此插入操作的效率较高。同时LinkedList是非线程安全容器。
-
List的选择:
-
当进行索引或在集合的末端增加和删除元素时,使用ArrayList和Vector的效率较高;
-
当进行特定位置的插入和删除元素的操作时,LinkedList的效率较高;因为LinkedList不需要移动元素。当在多线程中使用容器时,选择Vector比较安全。因为Vector是线程安全。
6、关于foreach和iterator
foreach的语法只是对iterator进行了简单的包装,使用起来更加方便而已,但是如果在foreach循环体内,对集合元素进行删除添加操作的时候,会报出ConcurrentModificationException,并发修改异常。
如果需要在遍历集合的时候对象集合中元素进行删除操作,需要使用iterator的遍历方式,iterator自带的remove删除方式不会报出异常。
import java.util.List;
import java.util.ArrayList;
import java.util.List;
public class UseForeach {
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
//遍历集合
list.add("abc");
list.add("def");
list.add("hjj");
list.add("klm");
list.add("nop");
list.add("qrs");
System.out.println("foreach example\n");
for(String string:list) {
System.out.println(string);
}
System.out.println();
String[] strs=new String[list.size()];
//遍历数组
list.toArray(strs);
for(String string:list) {
System.out.println(string);
}
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test_1 {
public Test_1() {
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
List l = new ArrayList();
l.add("aa");
l.add("bb");
l.add("cc");
for (Iterator i = l.iterator(); i.hasNext();) {
String str = (String) i.next();
System.out.println(str);
}
System.out.print("\n");
Iterator it = l.iterator();
while (it.hasNext()) {
String str = (String) it.next();
System.out.println(str);
}
}//main
}
运行结果:
//aa
//bb
//cc
//
//aa
//bb
//cc
//
7、什么是CopyOnWriteArrayList,它与ArrayList有何不同?
CopyOnWriteArrayList是ArrayList的一个线程安全的变体,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。相比较于ArrayList它的写操作要慢一些,因为它需要实例的快照。
CopyOnWriteArrayList中写操作需要大面积复制数组,所以性能肯定很差,但是读操作因为操作的对象和写操作不是同一个对象,读之间也不需要加锁,读和写之间的同步处理只是在写完后通过一个简单的"="将引用指向新的数组对象上来,这个几乎不需要时间,这样读操作就很快很安全,适合在多线程里使用,绝对不会发生ConcurrentModificationException ,因此CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。
文章持续更新:欢迎各位小伙伴关注我的公众号:菜丸的程序屋。希望将我的不足之处给予指点,谢谢大家。