hashset :不同步的,插入与读取顺序不一样,集合元素值可以为null,当hashset中存取元素时,会调用对象的hashcode方法得到对象的hashcode值,然后根据值查找元素,如果两个元素通过equals方法返回true但他们的hashcode方法不同也可以添加成功,所以hashset判断两个对象的标准是通过equals方法比较相等,并且两个对象的hashcode值也相等。再添加新类时注意重写hashcode与equals方法令相同元素这两种相等。
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。采用add方法时会进行hashcode判断有返回值true或者false
Linkedhashset:基于hashset来的,底层是链表,迭代遍历快,且顺序与存取的一致。因为linkedhashset本质也时hashset的一种,在插入删除要维护链表稍微慢一点
treeset:底层是二叉树,按给定的顺序排列,只能添加同一种对象。
1自然排序:将存入的类实现comparable接口重写比较方法
class R implements Comparable{
int age;
public R(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
@Override
public int compareTo(Object o) {
R r=(R)o;
return this.age-r.age;
}
}
class test{
public static void main(String[] args) {
Set s=new TreeSet();
R r1=new R(5);
R r2=new R(3);
R r3=new R(31);
R r4=new R(8);
s.add(r1);
s.add(r2);
s.add(r3);
s.add(r4);
for(Object r:s){//实现不知道什me类型
R ra=(R)r;//进行强转
System.out.println(ra.getAge());
}
}
}
2定制排序,在treeset中写排序方法。
class R {
int age;
public R(int age){
this.age=age;
}
public int getAge(){
return this.age;
}
}
class test{
public static void main(String[] args) {
Set s=new TreeSet(new Comparator<R>() {//匿名内部类实现定制排序
@Override
public int compare(R o1, R o2) {
return o1.age-o2.age;
}
});
R r1=new R(5);
R r2=new R(3);
R r3=new R(31);
R r4=new R(8);
s.add(r1);
s.add(r2);
s.add(r3);
s.add(r4);
for(Object r:s){
R ra=(R)r;
System.out.println(ra.getAge());
}
}
}
set集合都不是线程安全的,可以用collections控制集合类的方法进行同步
SortedSet s1=Collections.synchronizedSortedSet(new TreeSet());
List集合删除操作,本质是比较集合中的元素与要被删除的元素equals比较,如果传入list.remove(new A())A中恰好重写了equals方法返回固定true。所以导致删除一直有效。默认删除第一个。当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。LinkedList比ArrayList更占内存,因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。linkedlist用迭代器iterator遍历比较好,arrylist用get获取比较好。
arrylist与vector底层都是数组,vector线程安全的。
Map
从源码来看,java先实现了map然后将value置为null实现了set。
hashmap jdk7底层为entry数组,初始长度为16.在jkd8中底层问node[]数组,且底层为数组加链表加红黑树,更加方便查找。
hashtable与vector一样古老的类,线程安全的不允许null作为key与value,hashmap可以。其中key中的对象也要重写hashcode与equals方法。同样检测hashtable中是否存在某value的值时实际还是调用equals方法,与其他的任意一个其他的value值的equals方法比较。如果返回true则一样。
class A{
@Override
public boolean equals(Object obj) {
return true;
}
}
class test{
public static void main(String[] args) {
Map m=new Hashtable();
A a=new A();
m.put("xxx",20);
m.put("xxqx",25);
m.put("dsa", a);
System.out.println(m.containsValue(88));//true将a对象调用equals方法与任何对象比较返回true
}
}
HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
get方法底层有getentry维护,直接通过key获得entry.getvalue。HashMap 实现了Serializable接口,因此它支持序列化。