002、Java面试之常见集合

1、List 和 Set 区别

  • List:有序,重复
  • 继承Collection的接口
  • 可以允许有重复的对象。
  • 可以插入多个null元素。
  • 有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
  • 常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
  • Set:无序,唯一

  • 继承Collection的接口,
  • 不允许有重复对象
  • 只允许一个 null 元素
  • 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator  或者 Comparable 维护了一个排序顺序。
  • Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。

2、Set和hashCode以及equals方法的联系

  • hashCode不同时,则必为不同对象。hashCode相同时,根据equlas()方法判断是否为同一对象。

为了判断集合中对象是否重复

set集合中存放数据的步骤:

  • 程序向HashSet中添加一个对象时,先用hashCode方法计算出该对象的哈希码
  • 如果该对象哈希码与集合已存在对象的哈希码不一致,则该对象没有与其他对象重复,添加到集合中。
  • 如果存在于该对象相同的哈希码,那么通过equals方法判断两个哈希码相同的对象是否为同一对象
  • 判断的标准是:属性是否相同
  • 相同对象,不添加;不同对象,添加。
//当存的数据相同时,(不管地址是否相同)就认为存的是一个数据
public void testSet() {
		Set set = new HashSet();
		String a = "11111";
		String b = "11111";
		String c = new String("11111");
	    set.add(a);
	    set.add(b);
	    set.add(c);
	    System.out.println("集合元素个数:"+set.size());
}
运行结果:
集合元素个数:1
/**
* 调用其他类来输入值时,计算机不能判断值是否相等
* 但是可以在调用的类中重载equals方法和hashCode方法
* 来进行判断值是否相等
*/
public class TestSet{
	 public void test() {
	    Set set = new HashSet();
	    set.add(new Person("张三",20));
	    set.add(new Person("张三",20));
	    set.add(new Person("张三",20));
	    System.out.println("集合元素个数:"+set.size());
    }
}
运行结果:
集合元素个数:1   //如果Person  有重载equals方法和hashCode方法,则个数为1
集合元素个数:3   //如果Person没有重载equals方法和hashCode方法,则个数为3

3、为什么重写equals一定要重写hashcode?

    //Object类源码
    public native int hashCode();
    public boolean equals(Object obj) {
        return (this == obj);
    }
  • equals和hashcode是java.lang.Object类的两个重要的方法
  • 对于值对象,    ==比较的是两个对象的值。
  • 对于引用对象,比较的是两个对象的地址。
  • 默认的equals方法同==
  • 对hashCode方法重写,以保证相同的对象返回相同的hash值,不同的对象返回不同的hash值。
  • 两个对象相等,hashcode是一定相等
  • 两个对象不等,hashcode不一定不等
  • hashcode相等,两个对象不一定相等
  • hashcode不等,两个对象是一定不等
  • hashmap中value的查找是通过 key 的 hashcode 来查找,所以对自己的对象必须重写 hashcode 通过 hashcode 找到对象后会用 equals 比较你传入的对象和 hashmap 中的 key 对象是否相同,所以要重写 equals.
  • 重写equals方法时需要重写hashCode方法,主要是针对Map、Set等集合类型的使用;
  • Map、Set等集合类型存放的对象必须是唯一的;
  • 集合类判断两个对象是否相等,是先判断equals是否相等,如果equals返回TRUE,还要再判断HashCode返回值是否ture,只有两者都返回ture,才认为该两个对象是相等的。
  • 由于Object的hashCode返回的是对象的hash值,所以即使equals返回TRUE,集合也可能判定两个对象不等,所以必须重写hashCode方法,以保证当equals返回TRUE时,hashCode也返回Ture,这样才能使得集合中存放的对象唯一。

 

 为什么要重载equal方法?

  • 因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。 

 为什么重载hashCode方法?

  • 一般的地方不需要重载hashCode,只有当类需要放在HashTable、HashMap、HashSet等等hash结构的集合时才会 重载hashCode,那么为什么要重载hashCode呢?就HashMap来说,好比HashMap就是一个大内存块,里面有很多小内存块,小内存块 里面是一系列的对象,可以利用hashCode来查找小内存块hashCode%size(小内存块数量),所以当equal相等时,hashCode必 须相等,而且如果是object对象,必须重载hashCode和equal方法。

为什么equals()相等,hashCode就一定要相等,而hashCode相等,却不要求equals相等?

  • 因为是按照hashCode来访问小内存块,所以hashCode必须相等。
  • HashMap获取一个对象是比较key的hashCode相等和equal为true。
  • 之所以hashCode相等,却可以equal不等,就比如ObjectA和ObjectB他们都有属性name,那么hashCode都以name计算,所以hashCode一样,但是两个对象属于不同类型,所以equal为false。

为什么需要hashCode?

  • 通过hashCode可以很快的查到小内存块。
  • 通过hashCode比较比equal方法快,当get时先比较hashCode,如果hashCode不同,直接返回false。

4、List 和 Map 区别

  • List是存储单列数据的集合,Map是存储键和值这样的双列数据的集合,
  • List中存储的数据是有顺序,并且允许重复;
  • Map中存储的数据是没有顺序的,键不能重复,值是可以有重复的。

5、Arraylist 与 LinkedList 区别

 

  • List接口下一共实现了三个类:ArrayList,Vector和LinkedList
  • LinkedList主要保存数据的插入顺序的时候使用,采用链表结构;ArrayList,Vector都是使用的是长度可变的数组存储
  • ArrayList和LinkedList可想从名字分析,它们一个是Array(动态数组)的数据结构,一个是Link(链表)的数据结构,此外,它们两个都是对List接口的实现。
  • 前者是数组队列,相当于动态数组;后者为双向链表结构,也可当作堆栈、队列、双端队列
  • 当随机访问List时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 当对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。
  • 从利用效率来看,ArrayList自由性较低,因为它需要手动的设置固定大小的容量,但是它的使用比较方便,只需要创建,然后添加数据,通过调用下标进行使用;而LinkedList自由性较高,能够动态的随数据量的变化而变化,但是它不便于使用。
  • ArrayList主要控件开销在于需要在lList列表预留一定空间;而LinkList主要控件开销在于需要存储结点信息以及结点指针信息。

 

6、ArrayList 与 Vector 区别

  • List接口下一共实现了三个类:ArrayList,Vector和LinkedList
  • LinkedList主要保存数据的插入顺序的时候使用,采用链表结构;ArrayList,Vector都是使用的是长度可变的数组存储
  • Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。 
  • 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
  • 同步性:Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。备注:对于 Vector&ArrayList、 Hashtable&HashMap,要记住线程安全的问题,记住 Vector与 Hashtable 是旧的,是 java 一诞生就提供了的,它们是线程安全的,ArrayList 与 HashMap是 java2时才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。
  • 数据增长:ArrayList 与 Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList 与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。 Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。 ArrayList 与 Vector 都可以设置初始的空间大小, Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。
  • 总结:即 Vector 增长原来的一倍, ArrayList 增加原来的0.5倍。 
  • vector多了一个public Vector(int initialCapacity, int capacityIncrement)构造器,可以设置容量增长,arraylist是没有的。

7、HashMap 和 Hashtable 的区别

 

  • HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
  • HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
  • 另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
  • 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
  • HashMap不能保证随着时间的推移Map中的元素次序是不变的。
  • HashMap可以通过下面的语句进行同步:
    Map m = Collections.synchronizeMap(hashMap);

8、HashSet 和 HashMap 区别

 

  • 什么是HashSet

  • HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。
  • public boolean add(Object o)方法用来在Set中添加元素,当元素值重复时则会立即返回false,如果成功添加的话会返回true。
  • 什么是HashMap

  • HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许重复的键。Map接口有两个基本的实现,HashMap和TreeMap。TreeMap保存了对象的排列次序,而HashMap则不能。HashMap允许键和值为null。HashMap是非synchronized的,但collection框架提供方法能保证HashMap synchronized,这样多个线程同时访问HashMap时,能保证只有一个线程更改Map。
  • public Object put(Object Key,Object value)方法用来将元素添加到map中。
HashMapHashSet
HashMap实现了Map接口HashSet实现了Set接口
HashMap储存键值对HashSet仅仅存储对象
使用put()方法将元素放入map中使用add()方法将元素放入set中
HashMap中使用键对象来计算hashcode值HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap比较快,因为是使用唯一的键来获取对象HashSet较HashMap来说比较慢

9、HashMap 和 ConcurrentHashMap 的区别

10、HashMap 的工作原理及代码实现,什么时候用到红黑树

11、多线程情况下HashMap死循环的问题

12、HashMap出现Hash DOS攻击的问题

13、ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数

14、手写简单的HashMap

15、看过那些Java集合类的源码

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值