集合
单列集合
List
List
集合存储元素特点:有序可重复,存储的元素有下标。有序实际上是说存进去是这个顺序,取出来还是这个顺序。这里的顺序不是说按照大小排序。
- ArrayList集合底层采用了数组这种数据结构,ArrayList集合是非线程安全的。
Linkedlist
集合底层采用了双向链表数据结构Vector
集合底层采用了数组这种数据结构,Vector集合是线程安全的。Vector所有的方法都有
synchronized关键字修饰所以线程安全,但是效率较低,现在保证线程安全有别的方案,所以Vector
使用较少了。
Set
Set集合存储元素特点:无序不可重复。:无序表示存进去是这个顺序,取出来就不一定是这个顺序了,
另外Set集合中元素没有下标。Set集合中的元素还不能重复。
- 实际上
HashSet
集在 new 的时候,底层实际上new了一个HashMap集合。向HashSet集合中存储元素,实际上是存储到HashMap集合中了。HashMap集合是一个哈希表数据结构 SortedSet
集合存储元素的特点:由于继承了Set集合,所以它的特点也是无序不可重复;但是放在SortedSet集合中的元素可以自动排序。我们称为可排序集合。放到该集合中的元素是自动按照大小顺序排序的。TreeSet
底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了。
双列集合
Map集合和Collecion集合没有关系。Map集合以key和value的鍵値対的方式存緒元素。key和value都是存緒java対象的内存地址,所有Map集合的key特点:无序不可重夏的。Map集合的key和Set集合存緒元素特点相同。
- HashMap 集合底层是哈希表数据结构,是非线程安全的。
- Properties是线程安全的,因为继承Hashtable; :另外Properties存储元素的时候也是采用key和value的形式存储,并且
key和value只支持String类型,不支持其它类型。
- Hashtable集合底层也是哈希表数据结构,是线程安全的,其中所有的方法都带有synchronized关键字,效率较低,现在使用较少了,因为控制线程安全有其它更好的方案。
- TreeMap 底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序。
contains方法
Collection的contains
方法底层会调用 equals 方法。如果contatins(object)
如果object的类型重写了equals方法,则按照重写后的逻辑来定义是否包含该object,如果没重写equals方法则默认会调用Object类的equals方法:根据对象的内存地址来决定是否已经存在某个对象。
Collection collection = new ArrayList();
collection.add(new String("abc"));
System.out.println(collection.contains(new String("abc"))); // true
contains中传入的是String类型的对象,String是重写过equals方法的,是以内容来判断是否相等。
Collection c = new ArrayList();
c.add(new User("qwe"));
System.out.println(c.contains(new User("qwe"))); // false
class User {
public String name;
public User(){}
public User(String name) {
this.name = name;
}
}
该User类没有重写equals方法,所以默认根据内存地址来判断是否为同一个对象
remove方法
remove方法
底层同样也调用了equals方法,所以当要删除某个对象时,如果该对象的类型重写了equals方法,则跟会根据重写后的逻辑将所有和要被删除对象相等的对象一同删除。
Collection c = new ArrayList();
User u1 = new User("qwe");
User u2 = new User("qwe");
c.add(u1);
c.remove(u2);
System.out.println(c.size()); // 1
该User类没有重写equals方法,所以当remove(u1)
时,只会根据内存地址判断集合中其他元素是否和u1相等。
String s1 = new String("abc");
collection.add(s1);
String s2 = new String("abc");
collection.remove(s2);
System.out.println(collection.size()); // 0
String重写了equals,所以她认为删除s2就是删除s1
集合里面的内容只要发生改变,迭代器就要重新获取。在用迭代器遍历集合的过程中,不可以调用集合的remove方法;如果非要在遍历的过程中修改集合,可以调用迭代器的remove方法删除当前元素
HashMap
HashSet的底层是用HashMap实现的,而HashMap的底层是哈希表实现的
map.put(K,V)原理
- 先将k,v封装到Node对象当中。
- 底层会调用k的hashCode0方法得出hash值,然后通过哈希函数/哈希算法,将hash值转换成数组的
下标,下标位置上如果没有任何元素,就把Node添加到这个位置上了。如果说下标对应的位置上有链表,此时会拿着k和链表上每一个节点中的k进行equals ,如果所有的equals方法返回都是false ,那么这个新节点将会被添加到链表的末尾。如果其中有一个equals返回了true,那么这个节点的value将会被覆盖。
map.get(K)原理
- 先调用k的hashCode0方法得出哈希值,再通过哈希算法转换成数组下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,返回null.如果这个位置上有单向链表,那么会拿着参数k和单向链表上的每个节点中的k进行equals ,如果所有equals方法返回false ,那么get方法返回null ,只要其中有一个节点的k和参数k equals的时候返回true ,那么此时这个节点的value就是我们要找的value , get方法最终返回这个要找的value.
- 通过讲解可以得出HashMap集合的key,会先后调用两个方法,一个方法是hashCode0 , -个方法
是equals0 ,那么这两个方法都需要重写。- 如果一个类的equals方法重写了,那么hashCode()方法必须重写。并lequals方法返回如果是true , hashCode()方法返回的值必须一样。equals.方法返回true表示两个对象相同,在同一个单向链表上比较。那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的。所以hashCode()方法的返回值也应该相同。
- 放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
- 在JDK8之后,如果哈希表单向链表中元素超过8个,单向链表这种数据结构会变成红黑树数据结构。当红黑树上的节点数童小于6时,会重新把红黑树变成单向链表数据结构。
HashTable的key 和lvalue不可以为null。Hashtable集合初始化容里11 Hashtable集合扩容是:原容里*2+ 1
HashMap.集合的key和value都是可以为null的。
Properties
Properties是一Map集合,继承Hashtable , Properties的key和value都是String类型。
TreeSet和TreeMap
TreeSet的底层是用TreeMap实现的,而TreeMap的底层是用二叉排序树实现的
如果在TreeSet和TreeMap的key上放入系统定义好的数据类型,则会根系统数据类型定义好的比较方法来排序。所以如果是自定义类型,我们也需要定义比较方法。有两种定义比较方法的方法:
- 让自定义类实现Comparable接口,在
compareTo
方法中写比较规则 - 自定义一个比较器实现Comparator 接口,在
compare
方法中写比较规则,并在创建集合的时候传入该比较器。eg:
TreeSet<User> users = new TreeSet<>(new Comparator<User>() { // 匿名内部类的方式
@Override
public int compare(User o1, User o2) {
return o1.name.compareTo(o2.name);
}
});
通常上来说,如果该类的比较规则不会轻易变动则建议让类实现
Comparable
接口;如果该类的比较规则会经常变动,则用第二种方法。