Java 细数各种常见的集合:List,Set,Map

文章类别 in java

为什么会出现java集合?

——这是因为在面向对象编程中,需要用一种容器来装对象这种元素!

那数组不是可以装元素吗?

——数组是可以装元素,但是数组有一定的局限性,它的长度是不可改变的,是固定的,而集合的默认长度是10,但是它是可以动态添加的!

而且数组不但可以装引用类型,还可以装一般的数据类型,而集合是专门来装引用类型的!

java集合继承体系

由于集合的存储方式(数据结构)不同,比如一些需求是要讲元素按顺序的存储,而一些需求是要将元素不能重复的存储,这时候就分出了许多集合来对应这种需求,那么这么多的集合里面,肯定有一些共同的属性,这时候就有了继承的体系!

文档中可以看到Collection:

java.util Interface Collection

Type Parameters: E - the type of elements in this collection

All Superinterfaces: Iterable

All Known Subinterfaces:

BeanContext, BeanContextServices, BlockingDeque, BlockingQueue, Deque, **List**, NavigableSet, Queue, **Set**, SortedSet, TransferQueue

All Known Implementing Classes:

AbstractCollection, AbstractList, AbstractQueue, AbstractSequentialList, AbstractSet, ArrayBlockingQueue, ArrayDeque, ArrayList, AttributeList, BeanContextServicesSupport, BeanContextSupport, ConcurrentHashMap.KeySetView, ConcurrentLinkedDeque, ConcurrentLinkedQueue, ConcurrentSkipListSet, CopyOnWriteArrayList, CopyOnWriteArraySet, DelayQueue, EnumSet,** HashSet, JobStateReasons, LinkedBlockingDeque, LinkedBlockingQueue, LinkedHashSet, **LinkedList, LinkedTransferQueue, PriorityBlockingQueue, PriorityQueue, RoleList, RoleUnresolvedList, Stack, SynchronousQueue, TreeSet, Vector

以上黑体字部分是常见的集合!当然还有Map集合,后面会提到!

简化一下:

  • Collection
  • List - ArrayList(最常用) - LinkedList - Vector
  • Set - HashSet - TreeSet

首先明确List集合和Set集合的区别:

Java的List集合 :

是有序的(存储元素的顺序和取出元素的顺序是相同的) 
可重复的(存储的元素可以使相同的)

代码体现:

public class ListDemo {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("1");
        list.add("1");
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");
        Iterator i = list.iterator();
        while(i.hasNext())
        {
            String s = (String) i.next();
            System.out.println(s);
        }
    }
}

//输出结果:
1
1
1
2
3
4
5
//从输出结果中可以看出,存入数据的顺序和取出数据的顺序是一样的,而且1是可以重复的

ArrayList、Vector底层的数据结构是数组,具有查询快,增删慢的特点! LinkedList底层的数据结构是链表,具有增删快,查询慢的特点!

Java的Set集合

是无序的(它不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。) 
是唯一的(存储到集合中的元素是不可重复的)

代码体现:

public class SetDemo {

    public static void main(String[] args) {
        Set set = new HashSet();
        set.add("1");
        set.add("1");
        set.add("1");
        set.add("2");
        set.add("3");
        set.add("4");
        set.add("5");

        Iterator iterator = set.iterator();
        while(iterator.hasNext())
        {
            System.out.println(iterator.next());
        }
    }

}

//输出结果:
3
2
1
5
4
//从中可以看出顺序和存储的时候不同,而且1只输出一次(唯一性)

为什么Set集合中的元素是不可重复的呢?

从源代码可以看到:

public HashSet() {
        map = new HashMap<>();
    }
//当new 一个HashSet的时候,它去创建了一个HashMap

//执行add方法时:
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    //返回的是put方法!

//而put方法:(简单讲就是判断添加的值之前是否加过!)
  public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);//这里有个hash方法
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))//这里有个equals的判断{
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

//再来看一下hash方法:
  final int hash(Object k) {
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }

        h ^= k.hashCode();//这里用了hashCode方法


        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }


//从中可以看到。底层是用了hashcode 和 equals 方法! 所以才会保证了唯一性!

验证一下以上的结论是否正确,我们写一个学生类,里面不用重写hashcode和equals的方法,看看是不是就可以重复了!

//创建学生类:
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO 自动生成的构造函数存根
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

}

//main测试:
public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合
        HashSet<Student> hash = new HashSet<Student>();
        //创建学生对对象
        Student s1 = new Student("one",1);
        Student s2 = new Student("two",2);
        Student s3 = new Student("two",2);
        Student s4 = new Student("three",3);
        Student s5 = new Student("four",4);
        Student s6 = new Student("four",4);
        Student s7 = new Student("five",5);
        //添加
        hash.add(s1);
        hash.add(s2);
        hash.add(s3);
        hash.add(s4);
        hash.add(s5);
        hash.add(s6);
        hash.add(s7);
        //遍历
        for(Student s : hash)
        {
            System.out.println(s.getAge() + s.getName());   
        }
    }
}
//输出结果:
2two
3three
2two
4four
1one
5five
4four
//很明显可以看到元素2two重复了!

那重写Student类中的hashcode和equals方法看看:

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO 自动生成的构造函数存根
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @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;
        Student other = (Student) 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;
    }

}

//main:
public class HashSetDemo {
    public static void main(String[] args) {
        //创建集合
        HashSet<Student> hash = new HashSet<Student>();
        //创建学生对对象
        Student s1 = new Student("one",1);
        Student s2 = new Student("two",2);
        Student s3 = new Student("two",2);
        Student s4 = new Student("three",3);
        Student s5 = new Student("four",4);
        Student s6 = new Student("four",4);
        Student s7 = new Student("five",5);
        //添加
        hash.add(s1);
        hash.add(s2);
        hash.add(s3);
        hash.add(s4);
        hash.add(s5);
        hash.add(s6);
        hash.add(s7);
        //遍历
        for(Student s : hash)
        {
            System.out.println(s.getAge() + s.getName())
        }
    }
}
//输出:
3three
4four
1one
2two
5five
//看,不重复了,因此:以上结论是正确的!

那么,有没有一种是不重复但是有序的特点的集合呢?有的,比如TreeSet集合! 它为什么会有序呢? 因为它的底层用了:comparable的compareto方法! 它的底层数据结构是**二叉树 **

TreeSet有两种排序方式: 1. 自然排序:TreeSet() 构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。

  1. 比较器器排序:TreeSet(Comparator comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。

首先看自然排序:

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Integer> tree = new TreeSet<Integer>();

        tree.add(15);
        tree.add(15);
        tree.add(18);
        tree.add(20);
        tree.add(20);
        tree.add(32);
        tree.add(32);
        tree.add(56);
        tree.add(2);

        for(Integer i : tree)
        {
            System.out.println(i);
        }
    }
}
//输出结果:
2
15
18
20
32
56
//可以发现,它自然排序了而且是唯一的。注意:Iteger重写了compareTo方法!

选择器排序:

//定义学生类对学生成绩进行排序:
public class Student {
    private String name;
    private int YuWenScore;
    private int ShuXueScore;
	private int yingYucore;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getYuWenScore() {
        return YuWenScore;
    }
    public void setYuWenScore(int yuWenScore) {
        YuWenScore = yuWenScore;
    }
    public int getShuXueScore() {
        return ShuXueScore;
    }
    public void setShuXueScore(int shuXueScore) {
        ShuXueScore = shuXueScore;
    }
    public int getYingYucore() {
        return YingYucore;
    }
    public void setYingYucore(int yingYucore) {
        YingYucore = yingYucore;
    }

    public Student(String name, int yuWenScore, int shuXueScore, int yingYucore) {
        super();
        this.name = name;
        this.YuWenScore = yuWenScore;
        this.ShuXueScore = shuXueScore;
        this.YingYucore = yingYucore;
    }

    public Student() {
        super();
        // TODO 自动生成的构造函数存根
    }

    public int getSum()
    {
        return this.getShuXueScore() + this.getYingYucore() + this.getYuWenScore();
    }

}

//mian
public class ArrangeMain {
    public static void main(String[] args) {
		//自定义按成绩排序
        TreeSet<Student> ts = new TreeSet<Student>(
                new Comparator<Student>() {
                    public int compare(Student o1, Student o2) {                        
                        //总分从高到低:主要条件
                        int num = o2.getSum() - o1.getSum();
                        //总分相同不一定数学成绩相同
                        int num2 = num == 0 ? o2.getShuXueScore() - o1.getShuXueScore():num;
                        //总分相同不一定语文成绩相同
                        int num3 = num2 == 0 ? o2.getYuWenScore() - o1.getYuWenScore():num2;
                        //总分相同不一定英语成绩相同
                        int num4 = num3 == 0 ? o2.getYingYucore() - o1.getYingYucore():num3;
                        //姓名不一定相同
                        int num5 = num4 == 0 ? o2.getName().compareTo(o1.getName()):num4;
                        return num5;
                    }
                }

                );
        for(int i=0;i<3;i++)
        {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入姓名:");
            String name = sc.nextLine();
            System.out.println("请输入语文成绩:");
            int Yuwen = sc.nextInt();
            System.out.println("请输入数学成绩:");
            int ShuXue = sc.nextInt();
            System.out.println("请输入英语成绩:");
            int YingYu = sc.nextInt();

            Student s = new Student();
            s.setName(name);
            s.setShuXueScore(ShuXue);
            s.setYingYucore(YingYu);
            s.setYuWenScore(Yuwen);

            ts.add(s);
        }
        int i = 0;
        for(Student stu : ts)
        {
            System.out.println(stu.getName() +" 的数学成绩:"+ stu.getShuXueScore()
                    +" 语文成绩:"+ stu.getYuWenScore() +" 英语成绩:"+ stu.getYingYucore()
                    +"排名第" + ++i);
        }
    }
}


控制台:
请输入姓名:
小明
请输入语文成绩:
100
请输入数学成绩:
100
请输入英语成绩:
100
请输入姓名:
小花
请输入语文成绩:
99
请输入数学成绩:
99
请输入英语成绩:
100
请输入姓名:
小李
请输入语文成绩:
60
请输入数学成绩:
100
请输入英语成绩:
100
小明 的数学成绩:100 语文成绩:100 英语成绩:100排名第1
小花 的数学成绩:99 语文成绩:99 英语成绩:100排名第2
小李 的数学成绩:100 语文成绩:60 英语成绩:100排名第3

再来说说Java的Map集合:

Map集合是元素成对出现的,键值对。键是唯一(set)的,值是可重复(List)的; 通常以put方法存储元素,以get()方法获取数据

与以上对应,HashMap无序,不重复,TreeMap有序,不重复,(针对键说的!)

我的相关文章

相关资料