Set集合

在这里插入图片描述

Set子接口

  • 特点:无序、无下标、元素不可重复。
  • 方法:全部继承自Collection中的方法。
/**
 * 测试Set接口的使用
 * 特点:1.无序,没有下标;2.重复
 * 1.添加数据
 * 2.删除数据
 * 3.遍历【重点】
 * 4.判断
 */
public class setMethod {
    public static void main(String[] args) {
        //创建集合
        Set<String> set =new HashSet<>();
        //1.添加数据
        set.add("java");
        set.add("python");
        set.add("golang");
        System.out.println("数据个数:"+set.size());
        System.out.println(set);
        //2.删除元素
 //       set.remove("python");
 //       System.out.println(set);
        //3.遍历
        //3.1使用增强for
        System.out.println("===使用增强for===");
        for (String str:set) {
            System.out.println(str);
        }
        //3.2使用迭代器
        System.out.println("===使用迭代器===");
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //4.判断
        System.out.println(set.contains("java"));
        System.out.println(set.isEmpty());
        
    }
}

运行结果:

数据个数:3
[python, java, golang]
===使用增强for===
python
java
golang
===使用迭代器===
python
java
golang
true
false

Set实现类

HashSet【重点】

特点:

  • 基于HashCode计算元素存放位置。
  • 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
/**
 * HashSet集合的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 1.添加元素
 * 2.删除元素
 * 3.遍历
 * 4.判断
 */
public class hashsetMethod {
    public static void main(String[] args) {
        //1.新建集合
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("java");
        hashSet.add("python");
        hashSet.add("golang");
        System.out.println("元素个数:"+hashSet.size());
        System.out.println(hashSet);
        //2.删除元素
//        hashSet.remove("python");
//        System.out.println(hashSet);
        //3.遍历
        //3.1使用增强for
        System.out.println("===使用增强for===");
        for (String str:hashSet) {
            System.out.println(str);
        }
        //3.2使用迭代器
        System.out.println("===使用迭代器===");
        Iterator<String> iterator = hashSet.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}
public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.HashSet;

public class Test {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> persons = new HashSet<>();
        //1.添加元素
        Person p1 = new Person("hjx",18);
        Person p2 = new Person("xjh",19);
        persons.add(p1);
        persons.add(p2);
    //    persons.add(p2);  重复元素不能添加
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons);
        persons.add(new Person("xjh",19));
        System.out.println(persons);
    }
}

运行结果:

元素个数:2
[Person{name='xjh', age=19}, Person{name='hjx', age=18}]
[Person{name='xjh', age=19}, Person{name='xjh', age=19}, Person{name='hjx', age=18}]

HashSet存储过程

  1. 根据hashCode计算保存的位置,如果位置为空,则直接保存,否则执行第二步。
  2. 执行equals方法,如果方法返回true,则认为是重复,拒绝存储,否则形成链表。
import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

 /*   @Override
    public int hashCode() {
        int n1 = this.name.hashCode();
        int n2 = this.age;
        return n1+n2;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj==null){
            return false;
        }
        if (this==obj){
            return true;
        }
         if (this instanceof Person){
             Person p = (Person)obj;
             if (this.name.equals(p.getName())&&this.age==p.getAge()){
                 return true;
             }
         }
         return false;
    }
*/
//编译器给的重写hashCode和equals方法:
   @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && name.equals(person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
import java.util.HashSet;
import java.util.Iterator;

public class Test {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> persons = new HashSet<>();
        //1.添加元素
        Person p1 = new Person("hjx", 18);
        Person p2 = new Person("xjh", 19);
        persons.add(p1);
        persons.add(p2);
        //    persons.add(p2);  重复元素不能添加
        System.out.println("元素个数:" + persons.size());
        System.out.println(persons);
        persons.add(new Person("xjh", 19));  //重写了hashCode和equals方法就不能添加了
        System.out.println(persons);

        //2.删除元素
  //      persons.remove(p1);
        //3.遍历
        //3.1使用增强for
        for (Person p:persons) {
            System.out.println(p);
        }
        //3.2使用列表迭代器
        Iterator<Person> it = persons.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //4.判断
        System.out.println(persons.contains(p1));

    }
}

运行结果:

元素个数:2
[Person{name='xjh', age=19}, Person{name='hjx', age=18}]
[Person{name='xjh', age=19}, Person{name='hjx', age=18}]
Person{name='xjh', age=19}
Person{name='hjx', age=18}
Person{name='xjh', age=19}
Person{name='hjx', age=18}
true

TreeSet

1.特点:

  • 基于排序顺序实现不重复。
  • 实现了SortedSet接口,对集合元素自动排序。
  • 元素对象的类型必须实现Comparable接口,指定排序规则。
  • 通过CompareTo方法确定是否为重复元素。
import java.util.TreeSet;

/**
 * 使用TreeSet保存数据
 * 存储结构:红黑树
 * 要求:元素类必须实现Comparable接口,compareTo方法返回值为0,认为是重复元素
 */
public class treesetMethod {
    public static void main(String[] args) {
        TreeSet<Person> people = new TreeSet<>();
        Person p1 = new Person("hjx", 18);
        Person p2 = new Person("xjh", 19);
        Person p3 = new Person("xjh", 20);
        //需要实现Comparable接口
        people.add(p1);
        people.add(p2);
        people.add(p3);
        System.out.println(people);
    }
}

查看Comparable接口的源码,发现只有一个compareTo抽象方法,在Person类中实现它:

public class Person implements Comparable<Person>{
    @Override
	//1.先按姓名比
	//2.再按年龄比
	public int compareTo(Person o) {
		int n1=this.getName().compareTo(o.getName());
		int n2=this.age-o.getAge();
		return n1 == 0?n2:n1;
	}
}

运行结果:

[Person{name='hjx', age=18}, Person{name='xjh', age=19}, Person{name='xjh', age=20}]

2.除了实现Comparable接口里的比较方法,TreeSet也提供了一个带比较器Comparator的构造方法,使用匿名内部类来实现它:

/**
 * TreeSet的使用
 * Comparator:实现定制比较(比较器)
 */
public class treesetUse {
    public static void main(String[] args) {
        //创建集合,指定比较规则
        TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getAge()-o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1 == 0?n2:n1;
            }
        });
        Person p1 = new Person("hjx", 18);
        Person p2 = new Person("xjh", 19);
        Person p3 = new Person("xjh", 20);
        Person p4 = new Person("hjx", 20);

        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        System.out.println(persons);
    }
}

运行结果:

[Person{name='hjx', age=18}, Person{name='xjh', age=19}, Person{name='hjx', age=20}, Person{name='xjh', age=20}]

3.案例:

(匿名 new Comparator() 可以替换为 lambda)

 TreeSet<String> treeSet = new TreeSet<>((o1, o2) -> {
            int n1 = o1.length()-o2.length();
            int n2 = o1.compareTo(o2);
            return n1 ==0 ?n2:n1;
        });
import java.util.Comparator;
import java.util.TreeSet;
/**
 * 要求:使用TreeSet集合实现字符串按照长度进行排序
 * java python golang
 * Comparator接口实现定制比较
 */
public class Application {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length()-o2.length();
                int n2 = o1.compareTo(o2);
                return n1 ==0 ?n2:n1;
            }
        });
        treeSet.add("java");
        treeSet.add("python");
        treeSet.add("golang");
        System.out.println(treeSet);
    }
}

运行结果:

[java, golang, python]

Map体系集合

1.Map接口的特点:

  1. 用于存储任意键值对(Key-Value)。
  2. 键:无序、无下标、不允许重复(唯一)。
  3. 值:无序、无下标、允许重复。
    在这里插入图片描述
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
 * Map接口的使用
 * 特点:1.存储键值对 2.键不能重复,值可以重复 3.无序
 */
public class mapMethod {
    public static void main(String[] args) {
        //创建Map集合
        Map<String,String> map = new HashMap<>();
        //1.添加元素
        map.put("水","water");
        map.put("花","flower");
        map.put("叶","leave");

        System.out.println(map);

        //2.删除元素
  //      map.remove("水");
  //      System.out.println(map);

        //3.遍历
        //3.1使用keySet();
        System.out.println("====使用keySet()====");
        Set<String> key = map.keySet();
        for (String k:key) {
            System.out.println(k+"==="+map.get(k));
        }
        //3.2使用entrySet();效率较高
        System.out.println("====使用entrySet()====");
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> e:entries) {
            System.out.print(e+"\t");
            System.out.print(e.getKey()+"\t");
            System.out.print(e.getValue()+"\t");

        }
    }
}

运行结果:

{=flower,=water,=leave}
====使用keySet()=======flower
水===water
叶===leave
====使用entrySet()=====flower	花	flower	水=water	水	water	叶=leave	叶	leave	

Map集合的实现类

HashMap【重点】

JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value

public class Student {
    private String name;
    private int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}
import java.util.HashMap;

/**
 * HashMap集合的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 使用key的hashcode和equals作为重复
 */
public class HashMapMethod {
    public static void main(String[] args) {
        //创建集合
        HashMap<Student, String> students = new HashMap<>();
        //1.添加元素
        Student s1 = new Student("hjx",001);
        Student s2 = new Student("xjh",100);

        students.put(s1,"北京");
        students.put(s2,"上海");
        students.put(new Student("xjh",100),"上海");
        //假如相同的属性认为是一个对象怎么修改?
        System.out.println("元素个数:"+students.size());
        System.out.println(students);
    }

}

运行结果:

元素个数:3
{Student{name='xjh', id=100}=上海, Student{name='xjh', id=100}=上海, Student{name='hjx', id=1}=北京}

要想使相同的属性无法再重复添加,重复依据是hashCode和equals方法,重写后(编译器自带的):

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id && name.equals(student.name);
    }

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

运行结果变为:

元素个数:2
{Student{name='xjh', id=100}=上海, Student{name='hjx', id=1}=北京}
public class HashMapMethod {
    public static void main(String[] args) {
        //创建集合
        HashMap<Student, String> students = new HashMap<>();
        //1.添加元素
        Student s1 = new Student("hjx",001);
        Student s2 = new Student("xjh",100);

        students.put(s1,"北京");
        students.put(s2,"上海");
        students.put(new Student("xjh",100),"上海");
        //假如相同的属性认为是一个对象怎么修改?
        System.out.println("元素个数:"+students.size());
        System.out.println(students);
        //2.删除元素
 //       students.remove(s1);
 //       System.out.println(students);
        //3.遍历
        //3.1使用keySet();
        System.out.println("===使用keySet===");
        for (Student key:students.keySet()) {
            System.out.println(key+"==="+students.get(key));
        }
        //3.2使用entrySet();    返回值是一个键值对
        System.out.println("===2使用entrySet===");
        for (Map.Entry<Student,String> entry: students.entrySet()) {
            System.out.println(entry);
        }
        //4.判断
        System.out.println(students.containsKey(s1));
    }
}

运行结果:

元素个数:2
{Student{name='xjh', id=100}=上海, Student{name='hjx', id=1}=北京}
===使用keySet===
Student{name='xjh', id=100}===上海
Student{name='hjx', id=1}===北京
===2使用entrySet===
Student{name='xjh', id=100}=上海
Student{name='hjx', id=1}=北京
true

HashMap源码

1.默认初始化容量:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
2.数组最大容量:
static final int MAXIMUM_CAPACITY = 1 << 30;
3.默认加载因子:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
4.链表调整为红黑树的链表长度阈值(JDK1.8):
static final int TREEIFY_THRESHOLD = 8;
5.红黑树调整为链表的链表长度阈值(JDK1.8):
static final int UNTREEIFY_THRESHOLD = 6;
6.链表调整为红黑树的数组最小阈值(JDK1.8):
static final int MIN_TREEIFY_CAPACITY = 64;
7.HashMap存储的数组:
transient Node<K,V>[] table;
8.HashMap存储的元素个数:
transient int size;

9.默认加载因子是什么?
就是判断数组是否扩容的一个因子。假如数组容量为100,如果HashMap的存储元素个数超过了100*0.75=75,那么就会进行扩容。
10.链表调整为红黑树的链表长度阈值是什么?
假设在数组中下标为3的位置已经存储了数据,当新增数据时通过哈希码得到的存储位置又是3,那么就会在该位置形成一个链表,当链表过长时就会转换成红黑树以提高执行效率,这个阈值就是链表转换成红黑树的最短链表长度;
11.红黑树调整为链表的链表长度阈值是什么?
当红黑树的元素个数小于该阈值时就会转换成链表。
12.链表调整为红黑树的数组最小阈值是什么?
并不是只要链表长度大于8就可以转换成红黑树,在前者条件成立的情况下,数组的容量必须大于等于64才会进行转换。

HashSet源码

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    private transient HashMap<E,Object> map;
    private static final Object PRESENT = new Object();
    public HashSet() {
        map = new HashMap<>();
    }
}

HashSet的存储结构就是HashMap,它的存储方式,可以看一下add方法:

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

它的add方法调用的就是map的put方法,把元素作为map的key传进去的。

Hashtable

  • JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
  • 初始容量11,加载因子0.75。

Properties

  • Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。

它继承了Hashtable的方法,与流关系密切。

TreeMap

  • 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
import java.util.Map;
import java.util.TreeMap;

public class TreeMapMethod {
    public static void main(String[] args) {
        //创建集合
        TreeMap<Student,String> treeMap = new TreeMap<>();
        //1.添加元素
        Student s1 = new Student("hjx",001);
        Student s2 = new Student("xjh",100);
        treeMap.put(s1,"北京");
        treeMap.put(s2,"上海");
        //不能直接打印,需要实现Comparable接口,因为红黑树需要比较大小
        System.out.println("元素个数:"+treeMap.size());
        System.out.println(treeMap);
        //2.删除元素
 //       treeMap.remove(s1);
 //       System.out.println(treeMap);
        //3.遍历
        //3.1使用keySet
        System.out.println("===用keySet===");
        for (Student key: treeMap.keySet()) {
            System.out.println(key+"==="+treeMap.get(key));
        }
        //使用entrySet
        System.out.println("===用entrySet===");
        for (Map.Entry<Student,String> entry: treeMap.entrySet()) {
            System.out.println(entry);
        }
        //4.判断
        System.out.println(treeMap.containsKey(s1));
    }
}

运行结果:

元素个数:2
{Student{name='hjx', id=1}=北京, Student{name='xjh', id=100}=上海}
===用keySet===
Student{name='hjx', id=1}===北京
Student{name='xjh', id=100}===上海
===用entrySet===
Student{name='hjx', id=1}=北京
Student{name='xjh', id=100}=上海
true

在Student类中实现Comparable接口:

public class Student implements Comparable<Student>{
    @Override
    public int compareTo(Student o) {
        int n1=this.id-o.id;
        return n1;
}

除此之外还可以使用比较器来定制比较:

TreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
        // 略
        return 0;
    }			
});

TreeSet源码

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    private transient NavigableMap<E,Object> m;
    private static final Object PRESENT = new Object();
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
}

TreeSet的存储结构实际上就是TreeMap,它的存储方式:

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

它的add方法调用的就是TreeMap的put方法,将元素作为key传入到存储结构中。

Collections工具类

1.概念:集合工具类,定义了除了存取以外的集合常用方法。

2.方法:

  • public static void reverse(List<?> list)//反转集合中元素的顺序
  • public static void shuffle(List<?> list)//随机重置集合元素的顺序
  • public static void sort(List<T> list)//升序排序(元素类型必须实现Comparable接口)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class CollectionsMethod {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(34);
        list.add(12);
        list.add(56);
        list.add(78);
        //sort排序
        System.out.println("排序之前:"+list);
        Collections.sort(list);
        System.out.println("排序之后:"+list);
        //binarySearch二分查找
        int i = Collections.binarySearch(list, 56);
        System.out.println(i);
        //copy复制
        List<Integer> dest = new ArrayList<>();
        for (int j = 0; j < list.size(); j++) {
            dest.add(0);
        }//该方法要求目标元素容量大于等于源目标
            Collections.copy(dest,list);
            System.out.println("dest:"+dest);
        //reverse反转
        Collections.reverse(list);
        System.out.println("反转之后:"+list);
        //shuffle打乱
        Collections.shuffle(list);
        System.out.println("打乱之后:"+list);

        System.out.println("===list转成数组===");
        //补充:list转成数组
        Integer[] arr = list.toArray(new Integer[4]);
        System.out.println(arr.length);
        System.out.println(Arrays.toString(arr));

        System.out.println("===数组转成集合===");
        //补充:数组转成集合
        String[] str = {"h","j","x"};
        List<String> l = Arrays.asList(str);
        //受限集合,不能添加和删除
        System.out.println(l);

        //住:基本数据类型转成集合时需要修改为包装类
        Integer[] integers = {12,34,56,78};
        List<Integer> in = Arrays.asList(integers);
        System.out.println(in);
        
    }
}

运行结果:

排序之前:[34, 12, 56, 78]
排序之后:[12, 34, 56, 78]
2
dest:[12, 34, 56, 78]
反转之后:[78, 56, 34, 12]
打乱之后:[56, 34, 12, 78]
===list转成数组===
4
[56, 34, 12, 78]
===数组转成集合===
[h, j, x]
[12, 34, 56, 78]

在这里插入图片描述


版权声明:本文为weixin_51609696原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_51609696/article/details/118573648