Java知识点问题精选之集合
经典java容器结构图:
注意哪些属于Collection,哪些属于Map。
List相关问题
Q:arrList = new ArrayList<>(Arrays.asList()) 和 arrList = Arrays.asList()有什么区别
List<Integer> arrList1 = new ArrayList<>(Arrays.asList(1,2,3));
List<Integer> arrList2 = Arrays.asList(1,2,3);
arrList1.add(4);
arrList2.add(4);
A:执行arrList2.add(4)时会报错。
因为 Arrays.asList()只会返回1个固定大小的列表, 其返回的List是AbstractList,无法调用add、remove和clear, 如果调用会直接抛异常。
异常名字为UnsupportedOperationException
具体原因可以见评论区。
Q:那上面asList支持通过修改原数组来修改list内容吗?
例如
String[] ss = {"a","b","c"};
List<String> arrList = Arrays.asList(ss);
ss[0] = "d";
System.out.println(arrList);
上面操作后arrList会报错吗?
A:
不会报错。arrList里的内容变成了{“d”,“b”,“c”}
Q: ArrayList的扩容公式和默认初始大小是多少?
A:
扩容容量= 原容量 + (原容量右移1位,即0.5倍)= 1.5倍
初始容量为10.
- 注意,初始的数组长度还是0,数组长度和容量不是一个东西。
Q: Vector的扩容公式
A:
扩容容量= 原容量 *2
初始大小为10
Q:vector和ArrayList的区别
A:
vector是线程安全的, 每个方法都加了syn关键字,频繁的加锁可能导致性能降低
Q:为什么不推荐使用stack
A:
为什么不推荐使用stack
https://www.cnblogs.com/cosmos-wong/p/11845934.html
stack 继承自vector , 但是vector里包含了很多不需要的public方法
只是为了实现栈,不用链表来单独实现,而是为了复用简单的方法而迫使它继承 Vector,Stack 和 Vector 本来是毫无关系的。这使得 Stack 在基于数组实现上效率受影响,另外因为继承 Vector 类,Stack 可以复用 Vector 大量方法,这使得 Stack 在设计上不严谨
Map相关问题
Q: 解答下列特性和哪些Map有关
-
实现基于散列表,迭代时是不确定随机的顺序的Map为-----------------------------------------HashMap
-
迭代时按照插入顺序进行迭代-----------------------------------------------------LinkedHashMap
-
迭代时按照键值的比较顺序进行迭代-----------------------------------------------------TreeMap
-
基于红黑树的实现-----------------------------------------------------TreeMap
-
线程安全的Map-----------------------------------------------------ConcurrentHashMap
-
键值比较时使用==而不是equal的Map-------------------------------------------------IdentityHashMap
-
可以按区间得到1个子map的Map----------------------sortMap
-
Set也有HashSet、LinkedSet、TreeSet、SortSet等,作用同理。
Q: hashCode相同, 那么equals肯定true吗?
A: 不一定。
Q: equals为true, 那么hashCode肯定相同吗?
A: 对。
原因: 参见散列表的原理,明白hashCode的作用后就明白为什么了。
Q: 2个String如果内容相同,那么hashCode相同吗?
A: 对,相同。因为二者equals返回true,所以必定hashCode相同。
Q: 如果在插入后,修改某个key的hashCode,可能造成什么问题?
A:
可能造成内存泄漏。因为map是按计算后的hashCode存放的,而如果在外部修改了某个key的值,可能造成之前塞入的那个哈希所在的地址无法被外部remove(key),却又无法被gc(因为一直持有),造成内存泄漏。
HashTable、HashMap、ConcurrentHashMap相关:
- key和value不可以为null的是:----------------------------HashTable
- 线程安全的是:---------------------------------HashTable和ConcurrentHashMap
他们2个的区别:
在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。(具体可参考底层实现原理,总之ConcurrentHashMap最重要的是做了分段)
Q:Collections.synchronizedMap(map)和ConcurrentHashMap,哪个同步效果好?
A:
Collections.synchronizedMap(map)与ConcurrentHashMap主要区别是:Collections.synchronizedMap()和Hashtable一样,实现上在调用map所有方法时,都对整个map进行同步
而ConcurrentHashMap的实现却更加精细,分端加锁
其实Colletions.synchronizedMap就是对放进去的map包了一层sync关键字。
详见:
https://www.cnblogs.com/a198720/articles/4227500.html
Q:linkedHashMap的accessOrder问题,下面输出什么
public void fun2() throws Exception {
LinkedHashMap<String, String> accessOrderTrue = new LinkedHashMap<>(16, 0.75f, true);
accessOrderTrue.put("1","1");
accessOrderTrue.put("2","2");
accessOrderTrue.put("3","3");
accessOrderTrue.put("4","4");
System.out.println("put后的数据:"+accessOrderTrue);
accessOrderTrue.get("2");
accessOrderTrue.get("3");
System.out.println("get后的数据"+accessOrderTrue);
}
A:
省略key值
put后的数据: {1=1,2=2,3=3,4=4}
get后的数据: {1=1,4=4,2=2,3=3}
- accessOrder为true时, 会把最近访问过的数据放到链表 末尾。
Q:
hashMap为什么多线程使用时可能会造成死循环?
A:
https://www.jianshu.com/p/1e9cf0ac07f4
主要发生在2个线程同时put并进行扩容时, 对同一个对象的链表引用会出现问题。、
Q:
java1.7 和1.8 之间, hashMap做了什么改进?
A:
1.7的哈希如果冲突严重,则在一个点上形成的链表会越来越长。
因此1.8做了改进,如果那个点的链表长度超过TREEIFY_THRESHOLD,则会转为红黑树。
Collections
- Collection是接口, Collections是1个工具类
- 排序: Collections.sort(collection ,Comparator<>)
- 打乱顺序: Collections.shuffle(collection ,Random)
- 填充: Collections.fill(list, 对象) , 注意是浅拷贝填充, 即填充后使用的是同一个引用。
- 返回不可变容器(即无法对容器做修改): Collections.unmodifiableMap(容器)
除此之外可以返回空的不可变集合和仅有单个元素的不可变集合。
Q: 当输入为哪些字母时,迭代时会报错
public static void main(String[] args) throws Exception {
List<String> list = Lists.newArrayList("A", "B", "C", "D");
String s = args[0];
for (String curStr : list) {
if (s.equals(curStr)) {
list.remove(curStr);
}
}
}
A:
删除A或者B会报错, 但是删除C不会!
对于foreach遍历容器,并用remove做删除时,当删除倒数第二个元素时,是不会报错的。
因为:
特殊的引用容器
假设有1个对象A, 有1个引用RA指向A
Q:如果RA引用了A,则A必不可能被回收, RA属于什么引用?
A: 强引用StrongRefernce,默认的引用操作都是强引用
Q: 如果只有RA引用了A, 在内存不足时会强制回收A,则RA属于什么引用?
A: 软引用SoftReferencem,用法如下:
SoftReference<String> softReference = new SoftReference<String>(str);
Q: 如果只有RA引用了A, 不管内存足不足,只要垃圾回收器扫描到了,就会直接回收,RA属于:
A: 弱引用WeakReference, 注意和垃圾收集器的启动间隔有关,因此短时间内RA还是可用的。
和这个引用相关的集合:WeakHashMap
Q: 当只有RA引用了A时,都会在下一次垃圾收集时直接回收,且创建引用时必须依赖引用队列,这个引用RA属于:
A: 虚引用(幽灵引用)PhantomReference。
和弱引用区别:
虚引用创建时必须依赖引用队列,且用途一般是跟踪对象的垃圾回收,让用户在回收时通过虚引用去触发一些清理行为。
Q: 引用队列是什么,作用是什么?
A: 引用队列可以配合软引用、弱引用及幽灵引用使用,当引用的对象将要被JVM回收时,会将其加入到引用队列。
应用:通过引用队列可以了解JVM垃圾回收情况。
// 引用队列
ReferenceQueue<String> rq = new ReferenceQueue<String>();
// 幽灵引用
PhantomReference<String> pr = new PhantomReference<String>(new String(""), rq);
// 永远为null(幽灵引用相当于无引用)
System.out.println(pr.get());
优先队列
- 点赞
- 收藏
- 关注作者
评论(0)