【java】Set detailed explanation

Common settings of set command

        The functions of each option are as follows:

Set access is unordered and the elements are unique

Code demo:

public static void demo1() {
    HashSet<String> hs = new HashSet<>();	//创建HashSet对象
    boolean b1 = hs.add("a");
    boolean b2 = hs.add("a");		//当向set集合中存储重复元素的时候返回为false
   
    hs.add("b");
    hs.add("c");
    hs.add("d");
    System.out.println(hs);			//[d, b, c, a] 存取无序 并且去掉了重复元素
    System.out.println(b1);			//true
    System.out.println(b2);			//false	

    for (String string : hs) {		//只要能用迭代器迭代的,就可以使用增强for循环遍历
        System.out.println(string);
    }
}

        To ensure the uniqueness of an element, the element needs to override two methods: one is hashCode() and the other is equals(). In the process of storing elements, HashSet will first call the hashCode() value of the element to see if its hash value is the same as the hash value of the element already stored in HashSet. If it is different: it will be added directly to the set; if it is the same: then Continue to call equals() of the elements and compare these elements with the same hash value in sequence. If there is one that returns true, then repeat it without adding it; if the comparison results are all false, then add it without repeating it. In order to reduce the number of comparisons of equals and improve efficiency, in general, objects with different attributes should have different hashCode() values. So how to rewrite equals() and hashCode()? Eclipse can automatically generate it.

Code demo:

        

public static void main(String[] args) {
    HashSet<Person> hs = new HashSet<>();
    hs.add(new Person("张三", 23));
    hs.add(new Person("张三", 23));
    hs.add(new Person("李四", 24));
    hs.add(new Person("李四", 24));
    hs.add(new Person("李四", 24));
    hs.add(new Person("李四", 24));
		
	System.out.println(hs);//Person重写了equals()方法和hashCode()方法,所以 hs 去除了重复的元素
}
public class Person {	//Person里面 Eclipse自动生成了 equals()方法和hashCode()方法
    private String name;
    private int age;
    public Person() {
        super();			
    }
    public Person(String name, int age) {
        super();
        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 + "]";
    }	
    
    /*
	* 为什么是31?
	* 1,31是一个质数,质数是能被1和自己本身整除的数
	* 2,31这个数既不大也不小
	* 3,31这个数好算,2的五次方-1,2向左移动4位
	*/
    @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;				//直接返回true
        if (obj == null)				//传入的对象为null
            return false;				//返回false
        if (getClass() != obj.getClass())//判断两个对象对应的字节码文件是否是同一个字节码
            return false;				//如果不是直接返回false
        Person other = (Person) obj;		//向下转型
        if (age != other.age)				//调用对象的年龄不等于传入对象的年龄
            return false;				//返回false
        if (name == null) {				//调用对象的姓名为null
            if (other.name != null)			//传入对象的姓名不为null
                return false;			//返回false
        } else if (!name.equals(other.name))		//调用对象的姓名不等于传入对象的姓名
            return false;				//返回false
        return true;					//返回true
    }		
}

        

LinkedHashSet: The direct parent class is HashSet

Features: Access is orderly, and stored elements cannot be repeated.

Code demo:

        

LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("a");
lhs.add("a");
lhs.add("a");
lhs.add("a");
lhs.add("b");
lhs.add("c");
lhs.add("d");

System.out.println(lhs);//[a,b,c,d]  去除了重复的元素,同时又保证了存取有序

TreeSet: The element is unique, and the more important thing is to sort the elements.

Method 1: Let the class where the element is located implement the Comparable interface, override the CompareTo() method, and add elements based on the return value of CompareTo()

    Return a positive number: add to the right side of the binary tree.
    Return a negative number: add to the left side of the binary tree
    . Return 0: Duplicate, do not add.

Example:
        

public static void demo2() {
    TreeSet<Person> ts = new TreeSet<>();
    ts.add(new Person("zhangsan", 23));
    ts.add(new Person("lisi", 13));
    ts.add(new Person("wangwu", 33));
    ts.add(new Person("zhaoliu", 43));
    ts.add(new Person("aaaa", 53));
    System.out.println(ts);
}
public class Person implements Comparable<Person> {
    private String name;
    private int age;
    public Person() {
        super();
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    /*
    //1):按照年龄排(先比较年龄后比较姓名)
    public int compareTo(Person o) {		
    	//this 是集合即将存入的元素, o 是集合已经存入的元素
    	int num = this.age - o.age;	//年龄是比较的主要条件
    	return num == 0 ? this.name.compareTo(o.name) : num;	//姓名是比较的次要条件
    }
    */

    /*
    //2):按照姓名排(先比较姓名后比较年龄)
    public int compareTo(Person o) {
    	int num = this.name.compareTo(o.name);		//姓名是主要条件
   		return num == 0 ? this.age - o.age : num;	//年龄是次要条件
    }
    */

    //3):按照姓名长度排(先比较姓名长度 后比较姓名内容 后比较年龄)
    public int compareTo(Person o) {	
        int length = this.name.length() - o.name.length();	//比较长度为主要条件
        int num = length == 0 ? this.name.compareTo(o.name) : length;//比较内容为次要条件
        return num == 0 ? this.age - o.age : num;//比较年龄为次要条件
    }	
}

        

Method 2: When creating a TreeSet object using the parameterized construction method of TreeSet, pass in a comparator. When adding elements to the TreeSet, elements are added based on the return value of the compare() method of the comparator.

    Return a positive number: add to the right side of the binary tree.
    Return a negative number: add to the left side of the binary tree
    . Return 0: Duplicate, do not add.

Code demo:
        

public static void demo3() {
    //在构造函数中传入比较器后 就不用再让Person实现Comparable接口了
    TreeSet<Person> ts = new TreeSet<>(new Comparator<Person>() {	
        //3):按照姓名长度排(先比较姓名长度 后比较姓名内容 后比较年龄)
        @Override
        public int compare(Person o1, Person o2) {//o1是即将存入的元素  o2是已经存入集合的元素
            //比较长度为主要条件
            int length = o1.getName().length() - o2.getName().length();	
            //比较内容为次要条件
            int num = length == 0 ? o1.getName().compareTo(o2.getName()) : length;	
            return num == 0 ? o1.getAge() - o2.getAge() : num;
        }

        /*
		//2):按照姓名排(先比较姓名后比较年龄)
		public int compare(Person o1, Person o2) {
			int num = o1.getName().compareTo(o2.getName());
			return num == 0 ? o1.getAge() - o2.getAge() : num;
		}
		*/

        /*
		//1):按照年龄排(先比较年龄后比较姓名)
		public int compare(Person o1, Person o2) {
			int num = o1.getAge() - o2.getAge();
			return num == 0 ? o1.getName().compareTo(o2.getName()) : num;
		}
		*/
    });
    ts.add(new Person("zhangsan", 23));
    ts.add(new Person("lisi", 13));
    ts.add(new Person("wangwu", 33));
    ts.add(new Person("zhaoliu", 43));
    ts.add(new Person("aaaa", 53));
    System.out.println(ts);
}

Source code analysis of TreeSet storing elements and sorting elements

        When TreeSet stores elements, it will first determine whether a comparator exists (that is, determine whether the comparator is null). If it exists, the comparator will be asked to call the compare(T t1, T t2) method to compare the upcoming elements in sequence. The stored value and the value already stored in the TreeSet collection. If a positive number is returned: put it on the right side of the binary tree; if a negative number is returned: put it on the left side of the binary tree; if it returns 0: do not add. If it does not exist: the bottom layer will automatically promote the element to be stored to an object of Comparable type (so if there is no comparator, the class where the element is located does not implement the Comparable interface, and the type will be reported when doing automatic promotion. Conversion error), and let the object call the CompareTo(T t) method, and compare it with the elements that have been stored in the TreeSet collection in sequence. If a positive number is returned: put it on the right side of the binary tree; if a negative number is returned: put it on the left side of the binary tree; if it returns 0: Do not add. Therefore, if both methods are used at the same time, the bottom layer will give priority to using the second method (the comparator method).

Source code fragment analysis:
        

        

 public V put(K key, V value) {		//key则是TreeSet即将存入的元素
     Entry<K,V> t = root;		//获取TreeSet中已存入的元素列表也就是 t

     /*此处有代码省略*/
     
	 //comparator是一个成员变量,初始值是null,如果TreeSet构造方法中传入了比较器
     //则comparator就不再是null
     Comparator<? super K> cpr = comparator;
     if (cpr != null) {	//如果有比较器 就使用比较器来比较
     	do {
             parent = t;
             cmp = cpr.compare(key, t.key);	//让比较器 cpr 去调用compare(T t1, T t2)方法,去依次比较即将存入的值 key 和已经存入TreeSet集合的值 t.key
             if (cmp < 0)			//如果返回负数
                 t = t.left;			//往二叉树左侧放
             else if (cmp > 0)		//如果返回正数
                 t = t.right;		//往二叉树右侧放
             else				//如果返回 0
                 return t.setValue(value);	//不添加
         } while (t != null);
     } else {				//如果没有比较器 则使用自然排序来比较
         if (key == null)
             throw new NullPointerException();
         Comparable<? super K> k = (Comparable<? super K>) key;	//把即将存入的元素 key 自动提升为Comparable类型的对象 k (所以如果没有比较器的情况下,元素所在的类没有实现Comparable接口,在做自动提升类型的时候就会报类型转换错误),
         do {
             parent = t;
             cmp = k.compareTo(t.key);	//让即将存入的元素 k 调用CompareTo(T t)方法,和已经存入TreeSet集合的元素 t.key 依次比较
             if (cmp < 0)			//如果返回负数
                 t = t.left;			//往二叉树左侧放
             else if (cmp > 0)		//如果返回正数
                 t = t.right;		//往二叉树右侧放
             else				//如果返回 0
                 return t.setValue(value);	//不添加
         } while (t != null);
     }

     /*此处有代码省略*/

 }

        Case 1: Write a program to obtain 10 random numbers from 1 to 20, requiring that the random numbers cannot be repeated. And output the final random number to the console.

        

/** - 分析:
  	- 1,有Random类创建随机数对象
    - 2,需要存储10个随机数,而且不能重复,所以我们用HashSet集合
    - 3,如果HashSet的size是小于10就可以不断的存储,如果大于等于10就停止存储
    - 4,通过Random类中的nextInt(n)方法获取1到20之间的随机数,并将这些随机数存储在HashSet集合中
    - 5,遍历HashSet
      */
public static void main(String[] args) {

    //1,有Random类创建随机数对象
    Random r = new Random();

    //2,需要存储10个随机数,而且不能重复,所以我们用HashSet集合
    HashSet<Integer> hs = new HashSet<>();

    //3,如果HashSet的size是小于10就可以不断的存储,如果大于等于10就停止存储
    while(hs.size() < 10) {

        //4,通过Random类中的nextInt(n)方法获取1到20之间的随机数,并将这些随机数存储在HashSet集合中
        hs.add(r.nextInt(20) + 1);
    }

    // 5,遍历HashSet
    for (Integer integer : hs) {
        System.out.println(integer);
    }

}

        Case 2: Unordered and repeated strings are stored in a collection. Define a method to order them (lexicographic order), and the duplicates cannot be removed.

        

/** - 分析:
    - 1,定义一个List集合,并存储重复的无序的字符串
    - 2,定义方法对其排序保留重复
    - 3,打印List集合
 */
public static void main(String[] args) {
	//1,定义一个List集合,并存储重复的无序的字符串
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");        
    list.add("aaa");        
    list.add("ccc");        
    list.add("ddd");        
    list.add("fffffffffff");        
    list.add("heima");        
    list.add("itcast");        
    list.add("bbbb");        
    list.add("aaa");        
    list.add("aaa");                
    
    //2,定义方法对其排序保留重复       
    sort(list);                
    //3,打印list        
    System.out.println(list);
}       
/*     
	* 定义方法,排序并保留重复     
	* 分析:     
	* 1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器
	* 2,将list集合中所有的元素添加到TrreSet集合中,对其排序,保留重复 
	* 3,清空list集合
	* 4,将TreeSet集合中排好序的元素添加到list中 
*/    
public static void sort(List<String> list) {
    //1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器      
    TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
   		@Override            
    	public int compare(String s1, String s2) {
            int num = s1.compareTo(s2);
            //比较内容为主要条件
            return num == 0 ? 1 : num; //保留重复            
        }        
    });     
    //2,将list集合中所有的元素添加到TrreSet集合中,对其排序,保留重复
    ts.addAll(list);       
    //3,清空list集合        
    list.clear();        
    //4,将TreeSet集合中排好序的元素添加到list中        
    list.addAll(ts);    
}

        

Guess you like

Origin blog.csdn.net/m0_73367097/article/details/132420160