Java internal organs Heart, Detailed Set collection

I compiled a free Java Advanced information, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo distributed high concurrency and other tutorials, a total of 30G, needs its own collection.
Portal:
https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q

A, Set

Set: pay attention to the unique nature of the collection system can tell if something is almost exists in the collection, it does not store duplicate elements

A storage disorder (retrieved sequentially deposited and not necessarily the same) elements, the value can not be repeated.

Equality objects

Refer to the same object heap two references are equal. If two reference hashCode method call will get the same result, if the class object does not belong to the covered Object hashCode method, then, hashCode returns a unique serial number for each object (java is calculated based on this target memory address number ), so that two different objects hashCode values ​​equal is not possible.

If you want to make two different Person objects considered equal, it must cover the hashCode method and the equals method of Object Following down, because Object hashCode method returns the memory address of the object, it is necessary to override the hashCode method, in order to ensure two different objects have the same hashCode, but also need to compare two different objects equals method returns true

The collection is not peculiar way, directly inherited from the Collection.

--- | Itreable interface This interface can use the enhanced for loop 
				--- | Collection describe the set of all common interfaces 
					--- | List interface can have a set of duplicate elements 
                            --- | ArrayList    
                            --- | LinkedList 
					--- | Set interface must not have a set of repeating elements


Case: set collection and add elements using an iterator iterates over the elements.

{class Demo4 public 
	public static void main (String [] args) { 
		// set the Set exist and are sequentially fetched inconsistent. Hs = new new HashSet the SET (); 
		hs.add ( "World Military"); 
		hs.add ( "weapon of knowledge"); 
		hs.add ( "Jianchuanzhishi"); 
		hs.add ( "Chinese Defense"); 
		System.out.println (hs); 
		// [Jianchuanzhishi, the world's military, weapons knowledge, Chinese defense] Iterator IT = hs.iterator (); 
		the while (it.hasNext ()) { 
			System.out.println ( it.next ()); 
		} 
	}}


Two, HashSet

--- | Itreable interface This interface can use the enhanced for loop 
				--- | Collection describe the set of all common interfaces 
					--- | List interface can have a set of duplicate elements 
                            --- | ArrayList    
                            --- | LinkedList 
					--- | Set the interface must not have a set of duplicate elements 
                            --- | HashSet thread-safe, fast access speed. The underlying hash table is implemented.

HashSet

Side of the hash table is stored hash value. HashSet elements not stored sequentially in the order is stored (and obviously different List) in accordance with the hash value is stored so that access to data according to the acquired hash value.

HashSet not duplicate elements credited rule using equals and hashcode

Since Set collection is not stored in duplicate set of elements. So HashSet also have this characteristic. How to check for duplicate HashSet? HashSet equals method and will be determined by the element division element hashcode () No repeated.

When you try to join objects HashSet, HashSet uses the hashCode object to determine the position of the object to join. Will also be compared to other objects hashCode have joined, if not equal hashCode, HashSet assumes that the object is not repeated.

To put it simply, if hashCode value of the object is different, it is impossible to target HashSet would think equal.

Therefore, we custom class when the need to rewrite hashCode, to ensure that the objects have the same hashCode value.

如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入.

总结:

元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。

哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。

hashtable

v2-e05f07d211fee3831571132993a0e6da_hd.jpg

图1:hashCode值不相同的情况

图2:hashCode值相同,但equals不相同的情况。

HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。

当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。

HashSet到底是如何判断两个元素重复。

通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型

判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。

注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。

HashSet 和ArrayList集合都有判断元素是否相同的方法,

boolean contains(Object o)

HashSet使用hashCode和equals方法,ArrayList使用了equals方法

案例:

使用HashSet存储字符串,并尝试添加重复字符串

回顾String类的equals()、hashCode()两个方法。

public class Demo4 {
	public static void main(String[] args) {
		// Set 集合存和取的顺序不一致。		Set hs = new HashSet();
		hs.add("世界军事");
		hs.add("兵器知识");
		hs.add("舰船知识");
		hs.add("汉和防务");
		// 返回此 set 中的元素的数量		System.out.println(hs.size()); // 4		// 如果此 set 尚未包含指定元素,则返回 true		boolean add = hs.add("世界军事"); // false		System.out.println(add);
		// 返回此 set 中的元素的数量		System.out.println(hs.size());// 4		Iterator it = hs.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}}


使用HashSet存储自定义对象,并尝试添加重复对象(对象的重复的判定)

public class Demo4 {
	public static void main(String[] args) {
		HashSet hs = new HashSet();
		hs.add(new Person("jack", 20));
		hs.add(new Person("rose", 20));
		hs.add(new Person("hmm", 20));
		hs.add(new Person("lilei", 20));
		hs.add(new Person("jack", 20));
		Iterator it = hs.iterator();
		while (it.hasNext()) {
			Object next = it.next();
			System.out.println(next);
		}
	}}class Person {
	private String name;
	private int age;
	Person() {
	}
	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 int hashCode() {
		System.out.println("hashCode:" + this.name);
		return this.name.hashCode() + age * 37;
	}
	@Override
	public boolean equals(Object obj) {
		System.out.println(this + "---equals---" + obj);
		if (obj instanceof Person) {
			Person p = (Person) obj;
			return this.name.equals(p.name) && this.age == p.age;
		} else {
			return false;
		}
	}
	@Override
	public String toString() {
		return "Person@name:" + this.name + " age:" + this.age;
	}}


问题:现在有一批数据,要求不能重复存储元素,而且要排序。ArrayList 、 LinkedList不能去除重复数据。HashSet可以去除重复,但是是无序。

所以这时候就要使用TreeSet了


三,TreeSet

案例:使用TreeSet集合存储字符串元素,并遍历

public class Demo5 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add("ccc");
		ts.add("aaa");
		ts.add("ddd");
		ts.add("bbb");
		System.out.println(ts); // [aaa, bbb, ccc, ddd]	}}


---| Itreable      接口 实现该接口可以使用增强for循环
				---| Collection		描述所有集合共性的接口
					---| List接口	    有序,可以重复,有角标的集合
                            ---| ArrayList   
                            ---|  LinkedList
					---| Set接口	    无序,不可以重复的集合
                            ---| HashSet  线程不安全,存取速度快。底层是以hash表实现的。
                            ---| TreeSet  红-黑树的数据结构,默认对元素进行自然排序(String)。如果在比较的时候两个对象返回值为0,那么元素重复。

红-黑树

红黑树是一种特定类型的二叉树

v2-ba8884cf4d938f2f733971ff19a4f15c_hd.jpg

红黑树算法的规则: 左小右大。

既然TreeSet可以自然排序,那么TreeSet必定是有排序规则的。

1:让存入的元素自定义比较规则。

2:给TreeSet指定排序规则。

方式一:元素自身具备比较性

元素自身具备比较性,需要元素实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。

方式二:容器具备比较性

当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。

注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;

注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,因为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)

通过return 0来判断唯一性。


问题:为什么使用TreeSet存入字符串,字符串默认输出是按升序排列的?因为字符串实现了一个接口,叫做Comparable 接口.字符串重写了该接口的compareTo 方法,所以String对象具备了比较性.那么同样道理,我的自定义元素(例如Person类,Book类)想要存入TreeSet集合,就需要实现该接口,也就是要让自定义对象具备比较性.

存入TreeSet集合中的元素要具备比较性.

比较性要实现Comparable接口,重写该接口的compareTo方法

TreeSet属于Set集合,该集合的元素是不能重复的,TreeSet如何保证元素的唯一性

通过compareTo或者compare方法中的来保证元素的唯一性。

添加的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,说明两个对象相等,此时该对象不会添加进来。

比较器接口

----| Comparable
       		compareTo(Object o)     元素自身具备比较性----| Comparator
       		compare( Object o1, Object o2 )	给容器传入比较器


TreeSet集合排序的两种方式:

一,让元素自身具备比较性。

也就是元素需要实现Comparable接口,覆盖compareTo 方法。

这种方式也作为元素的自然排序,也可称为默认排序。

年龄按照搜要条件,年龄相同再比姓名。

public class Demo4 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet();
		ts.add(new Person("aa", 20, "男"));
		ts.add(new Person("bb", 18, "女"));
		ts.add(new Person("cc", 17, "男"));
		ts.add(new Person("dd", 17, "女"));
		ts.add(new Person("dd", 15, "女"));
		ts.add(new Person("dd", 15, "女"));
		System.out.println(ts);
		System.out.println(ts.size()); // 5	}}class Person implements Comparable {
	private String name;
	private int age;
	private String gender;
	public Person() {
	}
	public Person(String name, int age, String gender) {this.name = name;
		this.age = age;
		this.gender = gender;
	}
	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 String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	@Override
	public int hashCode() {
		return name.hashCode() + age * 37;
	}
	public boolean equals(Object obj) {
		System.err.println(this + "equals :" + obj);
		if (!(obj instanceof Person)) {
			return false;
		}
		Person p = (Person) obj;
		return this.name.equals(p.name) && this.age == p.age;
	}
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", gender=" + gender
				+ "]";
	}
	@Override
	public int compareTo(Object obj) {
		Person p = (Person) obj;
		System.out.println(this+" compareTo:"+p);
		if (this.age > p.age) {
			return 1;
		}
		if (this.age < p.age) {
			return -1;
		}
		return this.name.compareTo(p.name);
	}}

二,让容器自身具备比较性,自定义比较器。

需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。

那么这时只能让容器自身具备。

定义一个类实现Comparator 接口,覆盖compare方法。

并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。

当Comparable比较方式,及Comparator比较方式同时存在,以Comparator

比较方式为主。

public class Demo5 {
	public static void main(String[] args) {
		TreeSet ts = new TreeSet(new MyComparator());
		ts.add(new Book("think in java", 100));
		ts.add(new Book("java 核心技术", 75));
		ts.add(new Book("现代操作系统", 50));
		ts.add(new Book("java就业教程", 35));
		ts.add(new Book("think in java", 100));
		ts.add(new Book("ccc in java", 100));
		System.out.println(ts); 
	}}class MyComparator implements Comparator {
	public int compare(Object o1, Object o2) {
		Book b1 = (Book) o1;
		Book b2 = (Book) o2;
		System.out.println(b1+" comparator "+b2);
		if (b1.getPrice() > b2.getPrice()) {
			return 1;
		}
		if (b1.getPrice() < b2.getPrice()) {
			return -1;
		}
		return b1.getName().compareTo(b2.getName());
	}}class Book {
	private String name;
	private double price;
	public Book() {
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {this.name = name;
	}
	public double getPrice() {
		return price;
	}
	public void setPrice(double price) {
		this.price = price;
	}
	public Book(String name, double price) {this.name = name;
		this.price = price;
	}
	@Override
	public String toString() {
		return "Book [name=" + name + ", price=" + price + "]";
	}}


四,LinkedHashSet

会保存插入的顺序。

看到array,就要想到角标。

看到link,就要想到first,last。

看到hash,就要想到hashCode,equals.

看到tree,就要想到两个接口。Comparable,Comparator。


Guess you like

Origin blog.51cto.com/14440216/2438979