java面试题答案——容器

容器

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值)

    
    总结:

 ListSetMap
元素重复性可重复不可重复键不可重复,值可以重复
元素有序性有序无序(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","世界");

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==


    运行以上代码会报错:Exception in thread "main" java.lang.UnsupportedOperationException
 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值