Java 集合

71 阅读7分钟

Java 集合

对象的容器,定义了对多个对象进行操作的常用方法。

位于java.util.*包下

数组

  • 长度固定
  • 既可以存储基本数据类型,又可以存储引用数据类型

集合

  • 长度不固定
  • 只能存储引用数据类型

Collection 集合

Collection 父接口,代表一组任意类型的对象,无序,无下标。

方法方法描述
boolean add(Object obj)添加⼀个对象数据
boolean addAll(Collection c)将⼀个集合中的所有对象添加到此集合中
void clear()清空此集合中的所有对象
boolean contains(Object o)检查此集合中是否包含o对象
boolean equals(Object o)⽐较此集合是否与指定对象相等
boolean isEmpty()判断此集合是否为空
boolean remove(Object o)在此集合中移除o对象
int size()返回此集合中的元素个数
Object[] toArray()将此集合转换成数组

注:遍历同时不能使用集合删除方法,否则出现并发修改异常,可使用迭代器的删除方法。

List

特点:有序、有下标、元素可以重复 继承Collection接口

List.png

方法方法描述
void add(int index, Object o)在index位置插⼊对象o
boolean addAll(int index, Collection c)将⼀个集合中的元素添加到此集合中的index位置
Object get(int index)返回集合中指定位置的元素
List subList(int fromIndex, int toIndex)返回fromIndex和toIndex之间的集合元素
public class TestList {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("Apple");
        list.add("Pear");
        list.add("Banana");
        
        // 遍历的方法
        // 1. for 循环
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        // 2. 增强 for 循环
        for (Object object : list) {
            String string = (Object) object;
            System.out.println(string);
        }
        // 3. 迭代器
        Iterator it = list.listIterator();
        while(it.hasNext()) {
            System.out.println(it.next());
        }
        // 4. 列表迭代器,和Iterator的区别,ListIterator可以向前或向后遍历,添加、删除、修改元素
        ListIterator lit = list.listIterator();
        while(lit.hasNext()) {
            System.out.println(lit.nextIndex() + "..." + lit.next());
        }
        while(lit.hasPrevious()) {
            System.our.println(lit.previousIndex() + "..." + lit.previous());
        }
    }
}
ArrayList

数组结构实现、查询快、增删慢。存储结构是数据。 JDK1.2 线程不安全

add方法源码分析

ArrayList-add方法-源码分析.png

remove方法源代码分析

ArrayList-remove-源码分析.png

LinkedList

链表结构实现、查询慢、增删快。存储结构是双向链表。 JDK1.2 线程不安全

Vector

数组结构实现,查询快,增删慢。 JDK1.0 线程安全、运行效率比 ArrayList 较慢

数据结构
  • 栈:先进后出
    • Stack类:继承Vector
    • push方法入栈、pop方法出栈
    • LinkedList也实现了栈结构
  • 队列:先进先出
    • Queue接口:继承Collection接口
    • offer方法入队、poll方法出队
    • LinkedList实现了Queue接口

泛型

Java 泛型是JDK1.5中引入的一个新特性,其本质就是参数化类型,把类型作为参数传递。 泛型分类:泛型类、泛型接口、泛型方法。

T称为类型占位符,表示一种引用数据类型。

  • 泛型类
public class Generic<T> {
    T t;
    public void show(T t) {
        System.out.println(t);
    }
}
  • 泛型接口
// 接口
public interface USB<T> {
    T service(T t);
}
// 实现
public class Mouse<T> implements USB<T>{

    @Override
    public T service(T t) {
        return t;
    }
}
  • 泛型方法
public class Generic {
    public <T> T show(T t) {
        return t;
    }
}
注意事项
  • 泛型不能在类中声明静态属性、静态常量
    • static修饰的属性是静态属性,先于对象,泛型类型取决于创建对象时传入的实际类型
  • 泛型不能在类中初始化对象或数组,但是可以声明对象或数组
    • 实例化对象需要分配空间,没有确定类型不能开辟空间
    • 初始化数组时需要给元素进行分配空间,泛型类型不确定,无法分配空间
  • 在类中不能使用泛型声明参数个数相同的重载方法
  • 使用不同实际类型创建出的泛型类对象的引用不可以相互赋值
泛型集合

参数化类型、类型安全的集合,强制集合的元素类型必须一致

  • 特点
    • 编译时即可检查,而非运行时抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间引用不能相互赋值

Set

特点:无序、无下标,元素不可重复 方法全部继承至Collection中的方法

Set.png

HashSet

基于equals,hashCode实现元素不重复 当存入元素的哈希码相同时,会调用==equals进行确认,结果为true,拒绝后者进入

public class TestHashSet {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();

        set.add(30);
        set.add(20);
        set.add(10);
        set.add(60);
        set.add(10);
        set.add(20);
        //
        System.out.println(set.size());
        System.out.println(set);

        // 增强 fro
        for (Integer i : set) {
            System.out.print(i + " ");
        }
        // 迭代器
        Iterator it = set.iterator();
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }

        System.out.println();
        System.out.println(set.contains(20));

        set.remove(10);
        System.out.println(set);

        set.clear();
        System.out.println(set);

        System.out.println(set.isEmpty());
    }
}
LinkedSet

链表实现的HashSet,按照链表进行储存,即可保留元素的插入顺序

public class TestLinkedHashSet {
    public static void main(String[] args) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>();

        set.add(1);
        set.add(2);
        set.add(3);

        System.out.println(set);
    }
}
TreeSet
  • 基于排列顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • 通过CompareTo方法确定是否为重复元素
public class TestTreeSet {
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();
        
        set.add(20);
        set.add(10);
        set.add(30);
        set.add(50);

        System.out.println(set);

        set.add(15);

        System.out.println(set);

        System.out.println(set.contains(30));

        set.remove(20);

        System.out.println(set);

        set.clear();

        System.out.println(set.isEmpty());
    }
}
Comparator 比较器

可以实现定制比较,元素自身提供的比较规则称为自然排序

使用Comparator比较器,元素类型可不实现Comparable接口,并且优先级高于Comparable接口。

public class TestComparator {
    public static void main(String[] args) {
        Student s1, s2, s3, s4;
        s1 = new Student(3213, "John", "男", 100);
        s2 = new Student(3212, "Jack", "男", 99);
        s3 = new Student(3211, "Rose", "女", 99);
        s4 = new Student(3213, "John", "男", 100);
        
        // 使用了Comparator比较器,匿名内部类实现compara方法,使用学生学号进行比较
        Set<Student> students = new TreeSet<>(((o1, o2) -> Integer.compare(o1.getSID(), o2.getSID())));

        students.add(s1);
        students.add(s2);
        students.add(s3);
        students.add(s4);

        System.out.println(students);
    }
}
// 定义一个Student类
public class Student  {
    private int SID;
    private String name;
    private String sex;
    private double score;

    public Student() {
    }

    public Student(int SID, String name, String sex, double score) {
        this.SID = SID;
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    public int getSID() {
        return SID;
    }

    public void setSID(int SID) {
        this.SID = SID;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                       "SID=" + SID +
                       ", name='" + name + ''' +
                       ", sex='" + sex + ''' +
                       ", score=" + score +
                       '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student student)) return false;
        return SID == student.SID && Double.compare(score, student.score) == 0 && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
    }

    @Override
    public int hashCode() {
        return Objects.hash(SID, name, sex, score);
    }
}

Map 集合

特点:称为“映射”存储一对数据(Key-Value),键不可以重复,值可以重复。

方法描述
V put(K key, V value)将对象存入到集合中,关联键值。key重复则覆盖原值
Set<K> keySet()返回所有key
Collection<V> values返回包含所有值的Collection集合
Set<Map.Entry<K,V>> entrySet()键值匹配的Set集合

Map.png

HashMap

JDK1.2版本,线程不安全,运行效率快;允许null作为keyvalue

public class TestHashMap {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();

        map.put("cn", "中国");
        map.put("uk", "英国");
        map.put("us", "美国");
        map.put("cn", "中华人民共和国");

        System.out.println(map.size());
        System.out.println(map);
        
        System.out.println(map.get("cn"));
        
        // 遍历
        // 1. 键集合遍历
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            System.out.print(map.get(key) + " ");
        }
        System.out.println();
        // 2. 迭代器
        Iterator iterator = keySet.iterator();
        while (iterator.hasNext()) {
            System.out.print(map.get(iterator.next()) + " ");
        }
        System.out.println();
        System.out.println("-----------------------------------------");

        // entrySet
        // 1. 增强 for
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for (Map.Entry<String, String> reflection : entrySet) {
            System.out.println(reflection.getKey() + "..." + reflection.getValue());
        }
        
        System.out.println("-----------------------------------------");
        
        // 2. 迭代器
        Iterator<Map.Entry<String, String>> entryIterator = map.entrySet().iterator();
        while (entryIterator.hasNext()) {
            Map.Entry<String, String> reflection = entryIterator.next();
            System.out.println(reflection.getKey() + "..." + reflection.getValue());
        }
    }
}

LinkedHashMap

有顺序的HashMap

public class TestLinkedHashMap {
    public static void main(String[] args) {
        LinkedHashMap<Integer, String> hashMap = new LinkedHashMap<>();

        hashMap.put(2, "two");
        hashMap.put(1, "one");
        hashMap.put(3, "three");

        System.out.println(hashMap);
    }
}

// 结果为
{2=two, 1=one, 3=three} // 有顺序

TreeMap

实现了SortMap接口,可以对key进行自动排序,key需要实现Comparable接口

public class TestTreeMap {
    public static void main(String[] args) {
        Student s1, s2, s3, s4;
        s1 = new Student(3310, "John", "男", 100);
        s2 = new Student(3311, "Jack", "男", 99);
        s3 = new Student(3312, "Rose", "女", 99.5);
        s4 = new Student(3310, "John", "男", 100);

        // 创建TreeMap对象,并传入排序依据,使用匿名内部类 -> 实现Comparator接口
        TreeMap<Student, String> treeMap = new TreeMap<>(((o1, o2) -> Double.compare(o1.getScore(), o2.getScore())));

        treeMap.put(s1, "东京");
        treeMap.put(s2, "南京");
        treeMap.put(s3, "天津");
        treeMap.put(s4, "北京");

        System.out.println(treeMap);

        Set<Student> studentSet = treeMap.keySet();
        for (Student student : studentSet) {
            System.out.println(student.getName() + "..." + treeMap.get(student));
        }

        Set<Map.Entry<Student, String>> entries = treeMap.entrySet();
        for (Map.Entry<Student, String> entry : entries) {
            System.out.println(entry.getKey().getName() + "..." + entry.getKey().getScore() + "..." + entry.getValue());
        }

        treeMap.remove(new Student(3310, "John", "男", 100));
        System.out.println(treeMap);

        System.out.println(treeMap.containsValue("东京"));
        System.out.println(treeMap.containsKey(s2));

        System.out.println(treeMap.isEmpty());
        treeMap.clear();
        System.out.println(treeMap.isEmpty());
        System.out.println(treeMap);

    }
}

HashTable

JDK1.0版本,线程安全,运行效率慢;不允许null作为keyvalue

Properties

HashTable 的子类,要求keyvalue都是String。通常用于配置文件的读取。

public class TestProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.put("name", "jack");
        properties.put("country", "China");
        properties.put("hobby", "eating");

        System.out.println(properties);
        // 使用stringPropertyNames()方法获取所有属性名集合
        Set<String> propertyNames = properties.stringPropertyNames();
        for (String propertyName : propertyNames) {
            System.out.println(propertyName + "..." + properties.getProperty(propertyName));
        }

        System.out.println(properties.containsKey("name"));
        System.out.println(properties.containsValue("china"));
        // System.getProperties()获取所有系统属性
        Properties properties1 = System.getProperties();
        Set<String> propertyNames1 = properties1.stringPropertyNames();
        for (String string : propertyNames1) {
            System.out.println(string + "..." + properties1.getProperty(string));
        }
    }
}

HashMap源码分析

HashMap-源码分析.png