集合框架和分析

集合框架可以分为两个部分:Collection和Map,详细的框架图如下:

我们先来分析一下Collection集合框架,Collection包括两大体系List和Set,其中List中的元素存取有序、元素可重复、有索引,可以根据索引获取值,Set的元素存取无序、不能存储重复元素。

List下面有有三个实现类ArrayList、vector、LinkedList,ArrayList和Vector底层是数组,LinkedList底层实现是链表。

ArrayList和Vector底层是数组实现,能够根据索引直接获取值,所以查找快,但是删除和添加操作慢,因为需要向前或向后挪动多个元素。Vector是旧版本的,线程安全,所以如果是单线程进行存取,最好用ArrayList,效率快,如果是多线程我们最好用Vector来进行存储,因为Vector里面的方法是线程安全的。

LinkedList是基于链表实现的,查找必须从头开始,所以查找速度慢,但是删除和添加只需要挪动两个节点,所以删除和添加速度快。链表提供了特殊的方法,所以链表可以实现栈或者队列。

 

Set接口有三个实现类HashSet、LinkedHashSet、TreeSet

HashSet集合存储不重复,无序,原理是什么?因为HashSet底层实现是哈希表,哈希表通过hashCode()和equals()方法来共同保证元素不重复。首先根据存储的元素算出hashCode值,然后根据算出的hashCode值和数组的长度算出存储的下标;如果下标位置无元素,那么直接存储,如果有元素,那么就要使用存入的元素和已经存在的元素进行equals方法进行比较,如果结果为真就不存储,如果为假就进行存储,以链表方式进行存储。

注意:一般我们自定义的类都需要重新写hashCode()和equals(),必须要重写Object类的这两个方法,因为hash值是根据存储的元素获得的

如:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

LinkedHashSet基于链表和哈希表实现的,所以具有存取有序,元素唯一的特点。

package cn.yqg.day4;

public class Person {
  private int age ;
  private String name;
  public Person(int age,String name) {
      this.age=age;
      this.name=name;
  }
  
@Override
public String toString() {
    return "Person [age=" + age + ", name=" + name + "]";
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}
}
package cn.yqg.day4;


import java.util.Iterator;
import java.util.LinkedHashSet;

public class Test {
    public static void main(String[] args) {
        LinkedHashSet<Person> list=new LinkedHashSet<>();
        list.add(new Person(1,"12"));
        list.add(new Person(1,"12"));
        list.add(new Person(3,"14"));
        list.add(new Person(4,"15"));
        
        Iterator<Person> it=list.iterator();
        while(it.hasNext()) {
            Person p=it.next();
            System.out.println(p);
        }
    }
}

运行结果:

Person [age=1, name=12]
Person [age=3, name=14]
Person [age=4, name=15]

 

TreeSet:特点存取无序,元素唯一,可以进行排序;TreeSet是基于二叉树实现。

存储过程:如果是第一个元素,直接存入,作为根节点,下一个元素进来就会进行比较,如果大于加点就放在节点右边,如果小于节点就放在节点左边,等于节点就不存储,后面的元素会依次进行比较直到有存储的位置为止。

package cn.yqg.day4;

import java.util.TreeSet;

public class Test2 {
    public static void main(String[] args) {
        TreeSet<String> set=new TreeSet<>();
        set.add("abd");
        set.add("abc");
        set.add("bcd");
        set.add("bce");
        set.add("bce");
        
        for(String str : set) {
            System.out.println(str);
        }
    }
}

运行结果:

abc
abd
bcd
bce

TreeSet保证元素唯一有两种方式:

1.自定义对象实现Comparable()接口,重写CompareTo()方法,该方法返回0表示相等,大于0表示存入的元素比被比较的元素大。反之小于0。

2.在创建TreeSet的时候向构造器中传入比较器Comparator接口实现类的对象,实现Comparator接口重写compare方法。

如果向TreeSet中存储自定义类没实现Comparable接口,或者没有传入Comparator比较器时,会出现ClassCastException异常。

下面演示用两种方式存储自定义对象

package cn.yqg.day4;

import java.util.TreeSet;

public class Test4 {
   public static void main(String[] args) {
     TreeSet<Person> treeSet=new TreeSet<>();
     treeSet.add(new Person(4,"1"));
     treeSet.add(new Person(1,"张三"));
     treeSet.add(new Person(1,"李四"));
     treeSet.add(new Person(3,"大王"));
     treeSet.add(new Person(2,"小王"));
     treeSet.add(new Person(3,"大王"));
     treeSet.add(new Person(4,"1"));
     treeSet.add(new Person(4,"1"));
     
     for(Person p : treeSet) {
         System.out.println(p);
     }
}
}
package cn.yqg.day4;

public class Person implements Comparable<Person>{
  private int age ;
  private String name;
  public Person(int age,String name) {
      this.age=age;
      this.name=name;
  }
  
@Override
public String toString() {
    return "Person [age=" + age + ", name=" + name + "]";
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (age != other.age)
        return false;
    if (name == null) {
        if (other.name != null)
            return false;
    } else if (!name.equals(other.name))
        return false;
    return true;
}

@Override
public int compareTo(Person o) {
    int rusult=this.age-o.age;
    if(rusult==0) {
        return this.name.compareTo(o.name);
    }
    return rusult;
}

}

另一种方式:使用比较器Comparator

package cn.yqg.day4;

import java.util.Comparator;
import java.util.TreeSet;

public class Test5 {
   public static void main(String[] args) {
    TreeSet<Person2> treeSet2=new TreeSet<>(new Comparator<Person2>() {

        @Override
        public int compare(Person2 o1, Person2 o2) {
            if(o1==o2) {
                return 0;
            }
            int result=o1.getAge()-o2.getAge();
            if(result==0) {
                return o1.getName().compareTo(o2.getName());
            }
            return result;
        }
        
    });
    treeSet2.add(new Person2(1,"张三"));
    treeSet2.add(new Person2(5,"小龙"));
    treeSet2.add(new Person2(4,"3"));
    treeSet2.add(new Person2(5,"小庆"));
    treeSet2.add(new Person2(4,"1"));
    treeSet2.add(new Person2(1,"1"));
    
    for(Person2 p : treeSet2) {
        System.out.println(p);
    }
  }
}
package cn.yqg.day4;

public class Person2 {
    private int age ;
      private String name;
      public Person2(int age,String name) {
          this.age=age;
          this.name=name;
      }
      
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }

    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

运行结果:

Person [age=1, name=1]
Person [age=1, name=张三]
Person [age=4, name=1]
Person [age=4, name=3]
Person [age=5, name=小庆]
Person [age=5, name=小龙]

-------------------------------------------------------------------------------------------------------------------

Collection体系总结:

List:“特点”,存取有序,可存重复值,元素有索引。

ArrayList:数组结构,查询速度快,增删慢,线程不安全,效率高。

Vector:数组结构,查询快,增删慢,线程安全,效率低。

LinkedList:链表结构,增删快,查询慢,线程不安全,效率高。

Set:“特点”,存取无序,不可存重复值,无索引。

HashSet:哈希表,存储无序,元素不重复,无索引。

LinkedHashSet:链表加哈希表,存储有序,无索引,值不重复。

TreeSet:二叉树,元素不重复,存取无序,但是可以进行排序。

 

两种排序方式:

1.自然排序:我们的元素必须实现Comparable接口,实现CompareTo()方法。

2.比较器排序:我们自定义的类实现Comparator接口,比较器实现Compare方法。然后创建TreeSet的时候把比较器对象当做参数传递给TreeSet。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

现在我们来看看Map集合框架

Map是一个双列集合,保存的是键值对,键要求保持唯一性,值可以重复。键值一一对应。Map存储是将键值传入Entry,然后存储Entry对象。

Map接口实现类有三个,分别为HashMap、TreeMap、LinkedHashMap。

HashMap:是基于hash表实现的,所以存储自定义对象作为键时,必须重写hashCode和equals方法。存取无序

package cn.yqg.day4;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;

public class Test6 {
   public static void main(String[] args) {
    HashMap<Person,String> map=new HashMap<Person,String>();
    map.put(new Person(1,"pp"),"java");
    map.put(new Person(2,"kk"),"c");
    map.put(new Person(1,"pp"),"c++");
    map.put(new Person(3,"ll"),"java");
    
    Set<Entry<Person,String>> entrySet=map.entrySet();
    Iterator<Entry<Person,String>> it=entrySet.iterator();
    while(it.hasNext()) {
        Entry<Person,String> entry=it.next();
        System.out.println(entry.getKey()+"-----"+entry.getValue());
    }
}
}

结果:

Person [age=1, name=pp]-----c++
Person [age=3, name=ll]-----java
Person [age=2, name=kk]-----c

我们发现如果键重复,后面的值会覆盖前面的值。存取无序。

 

LinkedHashMap:用法基本和HashMap一致,基于链表和哈希表来实现的,所以有存取有序,键不重复的特点。

package cn.yqg.day4;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

public class Test7 {
         public static void main(String[] args) {
         LinkedHashMap<Person,String> map=new LinkedHashMap<Person,String>();
            map.put(new Person(1,"pp"),"java");
            map.put(new Person(2,"kk"),"c");
             map.put(new Person(1,"pp"),"c++");
             map.put(new Person(1,"pp"),"R");
             for(Entry<Person,String> entry : map.entrySet()) {
                 System.out.println(entry.getKey()+"-----"+entry.getValue());
             }
        }
}

实现结果:

Person [age=1, name=pp]-----R
Person [age=2, name=kk]-----c

我们注意到键如果相同,值会被后面的覆盖掉。而且存取有序。

TreeMap集合存储自定义对象,自定义对象始终作为TreeMap的key值,由于TreeMap底层实现是二叉树,所有存进去的数据都要进行排序,排序有两种方法,一种自定义类实现Comparable接口,实现CompareTo方法,另一种实现Comparator接口,实现自定义比较器Compare方法。

package cn.yqg.day4;

import java.util.Comparator;
import java.util.TreeMap;
import java.util.Map.Entry;

public class Test8 {
    public static void main(String[] args) {
        TreeMap<Person,String> map=new TreeMap<>(new Comparator<Person>() {

            @Override
            public int compare(Person o1, Person o2) {
                if(o1==o2) {
                    return 0;
                }
                int result=o1.getAge()-o2.getAge();
                if(result==0) {
                    result=o1.getName().compareTo(o2.getName());
                }
                return result;
            }
            
        });
        
        map.put(new Person(1,"pp"),"java");
          map.put(new Person(2,"kk"),"c");
           map.put(new Person(6,"pp"),"c++");
           map.put(new Person(0,"pp"),"R");
        map.put(new Person(-7,"pp"),"jsp");
        map.put(new Person(0,"pp"),"js");
        for(Entry<Person,String> entry : map.entrySet()) {
             System.out.println(entry.getKey()+"-----"+entry.getValue());
         }
    }
}
运行结果:
Person [age=-7, name=pp]-----jsp Person [age=0, name=pp]-----js Person [age=1, name=pp]-----java Person [age=2, name=kk]-----c Person [age=6, name=pp]-----c++

 

转载于:https://www.cnblogs.com/zzuli/p/9382931.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值