Java知识点问题精选之集合

举报
breakDawn 发表于 2021/02/25 10:02:08 2021/02/25
【摘要】 经典java容器结构图:注意哪些属于Collection,哪些属于Map。 List相关问题Q:arrList = new ArrayList<>(Arrays.asList()) 和 arrList = Arrays.asList()有什么区别 List<Integer> arrList1 = new ArrayList<>(Arrays.asList(1,2,3)...

经典java容器结构图:
image.png

注意哪些属于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倍
image.png

初始容量为10.
image.png

  • 注意,初始的数组长度还是0,数组长度和容量不是一个东西。

Q: Vector的扩容公式
A:
扩容容量= 原容量 *2
image.png

初始大小为10
image.png


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(容器)
    除此之外可以返回空的不可变集合和仅有单个元素的不可变集合。
    image.png

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做删除时,当删除倒数第二个元素时,是不会报错的。
因为:
image.png

特殊的引用容器

假设有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());

image.png

优先队列

image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。