Java集合框架详解

一 、java集合框架常用的构成体系

接口:                   Collection                                  Map

子接口:          List                         Set              

常用实现类:  ArrayList    LinkedList    Vector      HashSet      LinkedHashSet    TreeSet      HashMap   LinkedHashMap   TreeMap     Hashtable

工具类:                  Collections

二、四个接口的区别

1.Collection接口存储无序不唯一数据

2.List接口存储有序不唯一的数据

3.Set接口存储无序唯一的数据

4.Map接口以键值对的形式存储数据,以键取值,键唯一,值可以重复

三、List接口

1、list接口常用方法

add(E):在列表的最后添加元素;E是元素的泛型

add(index,E):在列表的指定位置插入元素

size():返回当前列表的元素个数

get(index):返回下标index的元素,如果没有泛型约数返回Object类型,需要强转;如果有泛型约数,直接返回泛型类型无需强转

clear():清除列表里的所有数据;

isEmpty():检查列表是否为空;

contains():contains底层是调用equals方法,传入一个对象,检查列表中是否包含该对象;

如果传入的是String和基本数据类型,可以直接比较,因为String类自己重写了equals,基本数据类型比较地址就可以;

indexOf():传入对象,返回该对象在列表中第一次出现的索引;如果传入对象和contains一样要在实体类重写equals();

lastIndexOf():传入对象,返回该对象在列表中最后一次出现的索引;如果传入对象和contains一样要在实体类重写equals();

remove():传入一个下标删除列表中对应的元素,返回删除的元素对象,若下标超出集合长度,报下标越界异常。

传入一个对象,需要重写实体类的equals方法,返回boolean值

set(index,o):传入修改的下标,和新传入的对象,将指定位置的下标处的原元素替换成新元素,返回原来元素对象

subList(index,index):返回 List 集合;

toArray():返回对象数组 Object[] o ;

iterator():返回迭代对象

2.ArrayList

实现了一个长度可变的数组,在内存空间开辟一串连续的空间

这种存储结构,在循环遍历和随机访问元素的速度非常快

3.LinkedList

使用链表结构存储数据,在插入和删除元素时速度非常快

特有常用方法:

addFirst():开头添加元素

addLast():末尾添加元素

removeFirst():删除第一个元素,并返回第一个元素

removeLast():删除最后一个元素,并返回返回最后一个元素

getFirst():获取第一个元

getLast():获取最后一个元素

4.遍历集合

①使用for循环

②使用forEach遍历

③使用迭代器(iterator)遍历列表,使用列表调用.iteration()返回迭代器对象,

使用迭代器对象调用.hasNext()方法判断是否又下一条数据,使用迭代器对象调用.next()方法取出下一条数据

     ArrayList<String> list = new ArrayList<String>();
        list.add("list1");
        list.add("list2");
        list.add("list3");
        list.add("list4");
        list.add(2,"123");
        list.add(null);
int listLength = list.size();
    
        /**
         * 使用for循环遍历列表
         */
        for (int i = 0; i < listLength; i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("-------------------存储实体类---------------------");
        ArrayList<News> list2 = new ArrayList<News>();
        list2.add(new News(1,"等过","zhang"));
        list2.add(new News(2,"啦啦","wang"));
        list2.add(new News(3,"哈哈","li"));
        list2.add(new News(2,"啦啦","wang"));/**
         * forEach循环
         */
        for (News news : list2) {
            if (news == null) {
                System.out.println("---");
                continue;
            }
            System.out.println(news.getId()+" "+news.getTitle()+" "+news.getAuthor());
        }
       /**
         * 使用迭代器(iterator)遍历列表
         * 使用列表调用.iterator()返回迭代器对象
         * 使用迭代器对象调用.hasNext()方法判断是否又下一条数据
         * 使用迭代器对象调用.next()方法取出下一条数据
         */
        System.out.println("--------------迭代器输出----------------");
        Iterator<News> iter = list2.iterator();
        while(iter.hasNext()){
            News news = iter.next();
            if (news == null) {
                System.out.println("---");
                continue;
            }
            System.out.println(news.getId()+news.getAuthor()+news.getTitle());
        }

class News{
    private int id;
    private String author;
    private String title;public News() {
        super();
    }
    public News(int id, String author, String title) {
        super();
        this.id = id;
        this.author = author;
        this.title = title;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

四、Set接口

 1.常用方法

与list接口基本相同,但是由于set接口的特点是无序的,因此没有与下标相关的方法
例如:get(index)  remove(index)   add(index,obj)  ....

2.HashSet

①HashSet底层是调用HashMap的相关方法,传入数据后根据数据的hashCode进行散列运算hash(),
得到一个散列值(int)后,再按照散列值和set集合的大小进行按位运算,确定元素在序列中存储的位置
②HashCode如何判断两个对象是否相等?
a.先判断对象的hashCode(),如果hashCode值不同,那肯定不是同一个对象
b.如果相同则重写equals方法,再判断内容是否相等
所以>>>使用HashSet存储实体对象时,必须重写实体对象的hashCode()和equals()方法
     Set<Person> set2 = new HashSet<Person>();
        set2.add(new Person(1,"校长",15));
        set2.add(new Person(2,"小李",11));
        set2.add(new Person(3,"下哈",18));
        set2.add(new Person(4,"小妹",13));
        //实体对象new一个就是一个对象,set默认比较的是地址所以它不是重复对象可以存储;
        //若要判断对象内容是否一致,需要重写实体类hashCode()方法和equals()方法
        set2.add(new Person(3,"小李",11));
        set2.add(null);//不知道为什么会最先输出来
        set2.add(null);//set接口的唯一性,所以只能存储一个null
        //HashSet遍历出来是无序的
        Iterator<Person> iterator2 = set2.iterator();
        while(iterator2.hasNext()){
            Person p = iterator2.next();
            if (p == null) {
                System.out.println("---");
                continue;
            }
            System.out.println(p.getId()+" "+p.getName()+" "+p.getAge());
        }
class Person{
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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;
    }
    public Person() {
        super();
    }
    public Person(int id, String name, int age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + id;
        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 (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

3.LinkedHashSet

在HashSet的基础上,新增了一个链表 ,链表来记录HashSet中元素放入的顺序,因此使用迭代器遍历时,可以按照放入的顺序依次读出元素。
其他与HashSet基本保持一致。

4.TreeSet

将存入的数据按照二叉树的规则排序,然后输出(数字好像是从小到大的);
如果存入实体类对象:必须给定比较两个实体类的规则(说明按照这个实体的那一属性来区分他们)
方法一:需要实体类实现Comparable接口,重写compareTo()方法
        Set<Student> set2 = new TreeSet<Student>();
        set2.add(new Student(1,"战三",15));
        set2.add(new Student(3,"张三",12));
        set2.add(new Student(2,"李四",14));
        set2.add(new Student(4,"王伟",11));
        set2.add(new Student(3,"赵三",11));//按照只比较id来确定是否重复则这条不能存储;按照名字来比较则不重复
        //set2.add(null);//当使用compareTo来定义比较规则时,由于该方法不允许传入null所以TreeSet再这种情况下不能存储null
        System.out.println(set2.size());
        Iterator<Student> iterator2 = set2.iterator();
        while (iterator2.hasNext()) {
            Student p = iterator2.next();
            System.out.println(p.getId()+p.getName()+p.getAge());
        }
class Student implements Comparable<Student>{
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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;
    }
    public Student(int id, String name, int age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
    }
    @Override
    public int compareTo(Student student) {
        return this.id - student.id;
        //return this.name.compareTo(student.getName());
    }

方法二:

①在实例化TreeSet的同时,通过构造函数传入一个比较器:
比较器: 一个实现了Comparator接口,并重写了compare()方法的实现类的对象。
因此需要定义一个类实现比较器接口,重写compare()方法;
Set<Teacher> set1 = new TreeSet<Teacher>(new CompImpl());
        set1.add(new Teacher(1,"战三",15));
        set1.add(new Teacher(3,"张三",12));
        set1.add(new Teacher(2,"李四",14));
        set1.add(new Teacher(4,"王伟",11));
        set1.add(new Teacher(3,"赵三",11));//按照只比较id来确定是否重复则这条不能存储;按照名字来比较则不重复
        set1.add(null);//当使用compare来定义比较规则时,由于该方法允许传入null所以TreeSet再这种情况下能存储null
        System.out.println(set1.size());//输出5说明null存进去了
        Iterator<Teacher> iterator1 = set1.iterator();
        while (iterator1.hasNext()) {
            Teacher p = iterator1.next();
            if (p == null) {
                System.out.println("---");
                continue;
            }
            System.out.println(p.getId()+p.getName()+p.getAge());
        }
class CompImpl implements Comparator<Teacher>{

    @Override
    public int compare(Teacher t1, Teacher t2) {
        if (t1 == null || t2 == null) {
            return -1;
            //return 1;
        }
        return t1.getId() - t2.getId();
        //return t1.getName().compareTo(t2.getName());
    }
    
}
class Teacher{
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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;
    }
    public Teacher(int id, String name, int age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Teacher() {
        super();
    }
}
②或者使用匿名内部类直接拿到一个比较器对象
    Set<Doctor> set1 = new TreeSet<Doctor>(new Comparator<Doctor>() {

            @Override
            public int compare(Doctor d1, Doctor d2) {
                // TODO Auto-generated method stub
                if (d1 == null || d2 == null) {
                    return -1;
                    //return 1;
                }
                return d1.getId() - d2.getId();
            }
            
        });
        set1.add(new Doctor(1,"战三",15));
        set1.add(new Doctor(3,"张三",12));
        set1.add(new Doctor(2,"李四",14));
        set1.add(new Doctor(4,"王伟",11));
        set1.add(new Doctor(3,"赵三",11));//按照只比较id来确定是否重复则这条不能存储;按照名字来比较则不重复
        set1.add(null);
        Iterator<Doctor> iterator1 = set1.iterator();
        while (iterator1.hasNext()) {
            Doctor d = iterator1.next();
            if (d == null) {
                System.out.println("---");
                continue;
            }
            System.out.println(d.getId()+d.getName()+d.getAge());
        }
class Doctor{
    private int id;
    private String name;
    private int age;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    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;
    }
    public Doctor(int id, String name, int age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Doctor() {
        super();
    }
}

5.遍历

因为Set集合没有顺序所以只能有这两种遍历方法:forEach和 Iterator

6.comparable接口和Comparator接口区别

①前者是java.lang包下的接口,后者是java.util包下的
②前者由实体类实现,重写compareTo()方法,TreeSet调用空参构造器使用;
后者重新定义一个实现类来实现该接口,重写compare()方法,TreeSet调用含此接口的有参构造器使用;
③前者的compareTo()方法不允许传入null值(在方法体判空处理也不行),后者的compare()方法允许传入null,只是需要在方法体内进行判空处理即可
https://www.cnblogs.com/szlbm/p/5504634.html

五、Map接口

1.Map接口的特点:以键值对的形式存储数据,以键取值,键唯一值可重复 ;没有继承Iterator接口

2.常用方法:

put(key,value):向map最后追加一个键值对;

get(key):获取key所对应的值

clear():清除所有键值对

containsValue(obj):检测是否包含指定的值

containsKey(obj):检测是否包含指定的键

replace(K, V):替换指定的K的V

keySet():返回Set集合泛型为K

values():返回Collcetion集合泛型为V

entrySet():返回Set集合泛型为Entry<K,V>

3.遍历方式

HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        map.put(1, 1);
        map.put(1, 1);
        map.put(2, 4);
        map.put(3, 3);
        map.put(null, null); 
        System.out.println("--------keySet-----------");
        /**
         * 遍历Map的方式一
         */
        Set<Integer> keys = map.keySet();
        Iterator<Integer> iterator = keys.iterator();
        while (iterator.hasNext()) {
            Integer k = iterator.next();
            System.out.println(k+"----"+map.get(k));
        }
        /**
         * 遍历Map的方式二
         */
        System.out.println("--------------直接取值-------------");
        Collection<Integer> values = map.values();
        Iterator<Integer> iterator2 = values.iterator();
        while (iterator2.hasNext()) {
            System.out.println(iterator2.next());
        }
        /**
         * 遍历Map的方式三
         */
        System.out.println("--------------entry遍历--------------");
        Set<Entry<Integer, Integer>> set = map.entrySet();
        Iterator<Entry<Integer, Integer>> iterator3 = set.iterator();
        while (iterator3.hasNext()) {
            //Entry是Java给我们提供的一种特殊的数据类型,其实就是一个键值对
            //键就是当前这条记录的键,使用getKey()取到;
            //值就是当前这条记录的值,使用getValue()取到;
            Entry<Integer, Integer> entry = iterator3.next();
            //System.out.println(entry);
            System.out.println(entry.getKey()+"-------"+entry.getValue());
        } 

4.HashMap和HashTable的区别

1.HashMap是线程不安全(不同步),HashTable是线程安全的(同步的)

2.HashMap的键可以为null,HashTable的键不可以为null

https://blog.csdn.net/qq_35181209/article/details/74503362

六.关于这些常用的实现类能否存null的总结

ArrayList:可以存多个null,并且按照顺序输出;无论是否在实体类下

LinkedList:在存储非实体类时可以存多个null,并且按照顺序输出;实体类下面无法存储null

HashSet:只能存储一个null并且输出时候在最前面;无论是否在实体类下

LinkedHashSet:只能存储一个null并且输出时候按照输入顺序输出;无论是否在实体类下

TreeSet:底层默认用comparable接口的方法compareTo(),所以无法存入null;只有在存入实体类是自己定义比较规则时候,并且使用Compartor接口的实现类对象做构造函数才能存入

null,可以通过实体类的编码实现存多个null,输出的null在最前面

HashMap:可以存储一个null值,并且输出靠前;

LinkedHashMap:可以存储一个null,输出按照输入的顺序

TreeMap:同TreeSet

原文地址:https://www.cnblogs.com/ytsbk/p/8849883.html