HashSet的课堂练习题如下
具体代码如下
public class HashSetExercise { public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add(new Employee("tom", 20)); hashSet.add(new Employee("jack", 19)); hashSet.add(new Employee("tom", 20)); System.out.println(hashSet); } } class Employee { private String name; private int age; @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + '}'; } public Employee(String name, int age) { this.name = name; this.age = age; } //如果name和age相同,则返回相同的hash值 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return age == employee.age && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
输出结果如下
[Employee{name='tom', age=20}, Employee{name='jack', age=19}]
六、LinkedHashSet的使用
1、LinkedHashSet的全面说明
2、LinkedHashSet底层机制示意图
3、LinkedHashSet作为HashSet的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据
优点:对于频繁的遍历操作,LinkedHashSet效率高于HashSet
@Test public void SetTest(){ Set hashSet = new LinkedHashSet(); hashSet.add("hello"); hashSet.add("AA"); hashSet.add(12); hashSet.add(12); hashSet.add("cc"); hashSet.add(new User("小红",13)); hashSet.add(new User("小红",13)); Iterator iterator = hashSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } }
遍历的结果:是按照添加的顺序,进行遍历的。
hello
AA
12
cc
www.entity.User@168edbb
LinkedHashSet底层源码分析
@SuppressWarnings({"all"}) public class LinkedHashSetResource { public static void main(String[] args) { //分析一下LinkedHashSet的底层机制 Set set = new LinkedHashSet(); set.add(new String("AA")); set.add(456); set.add(456); set.add(new Customer("刘", 1001)); set.add(123); set.add("ly"); System.out.println("set=" + set); //1.LinkedHashSet 加入顺序和取出元素/数据的顺序一致 //2.LinkedHashSet底层维护的是一个LinkedHashMap(是HashMap的子类) //3.LinkedHashSet底层结构(数组+双向链表) //4.添加第一次时,直接将数组table扩容到16,存放的结点类型是LinkedHashMap$Entry //5.数组是HashMap$Node[]存放的元素/数据是LinkedHashMap$Entry类型 /* //继承关系是在内部类完成 static class Entry<K,V> extends HashMap.Node<K,V> { Entry<K,V> before, after; Entry(int hash, K key, V value, Node<K,V> next) { super(hash, key, value, next); } } */ } } class Customer { private String name; private int no; public Customer(String name, int no) { this.name = name; this.no = no; } @Override public String toString() { return "Customer{" + "name='" + name + '\'' + ", no=" + no + '}'; } }
输出结果如下
set=[AA, 456, Customer{name='刘', no=1001}, 123, ly]
LinkedHashSet对应的练习题
具体代码如下
public class LinkedHashSetExercise { public static void main(String[] args) { LinkedHashSet linkedHashSet = new LinkedHashSet(); linkedHashSet.add(new Car("奥迪", 10000)); linkedHashSet.add(new Car("保时捷", 1000000)); linkedHashSet.add(new Car("奥迪", 10000)); System.out.println("linkedHashSet=" + linkedHashSet); } } class Car { private String name; private double price; public Car(String name, double price) { this.name = name; this.price = price; } @Override public String toString() { return "Car{" + "name='" + name + '\'' + ", price=" + price + '}'; } //重写equals方法,和hashCode //当name和price相同时,就返回相同的hashCode,equals返回true @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Car car = (Car) o; return Double.compare(car.price, price) == 0 && Objects.equals(name, car.name); } @Override public int hashCode() { return Objects.hash(name, price); } }
输出结果如下
linkedHashSet=[Car{name='奥迪', price=10000.0}, Car{name='保时捷', price=1000000.0}]
TreeSet类的详解
TreeSet最大的特点就是可以排序,具体案例代码如下
public class TreeSet_ { public static void main(String[] args) { //1.当我们使用无参构造器,创建TreeSet时,仍然是无序的 //2.希望添加的元素,按照字符串大小来排序 //3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类) //并制定排序规则 //简单看看源码 //源码解读 /* 1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性this.comparator public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } 2.在调用add方法时treeSet.add("tom");,在底层会执行到 if (cpr != null) {//cpr 就是我们的匿名内部类(对象) do { parent = t; //动态绑定到我们的匿名内部类(对象)compare cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else //如果相等,即返回0,这个Key就没有加入 return t.setValue(value); } while (t != null); } */ // TreeSet treeSet = new TreeSet(); TreeSet treeSet = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { //下面调用String的compareTo方法 进行字符串大小比较,从小到大排序 // return ((String) o1).compareTo((String) o2); //下面调用String的compareTo方法 进行字符串大小比较,从大到小排序 // return ((String) o2).compareTo((String) o1); //要求加入的元素,按照长度从小到大排序 // return ((String) o1).length() - ((String) o2).length(); //要求加入的元素,按照长度从大到小排序 return ((String) o2).length() - ((String) o1).length(); } }); //添加数据 treeSet.add("jack"); treeSet.add("tom");//字符串长度为3 treeSet.add("sp"); treeSet.add("a"); // treeSet.add("abc");//字符串长度为3 加入不进去 因为长度与 treeSet.add("tom");一致,所以加不进去 System.out.println("treeset=" + treeSet); } }
输出结果如下
treeset=[jack, tom, sp, a]
四、TreeSet的使用
- 向TreeSet中添加的数据,要求是相同类的对象
- 两种排序方式:自然排序和定制排序
- 自然排序中,比较两个对象是否相同的标准为:CompareTo()返回0,不再是equals
@Test public void TreeSetTest(){ TreeSet set = new TreeSet(); //失败:不能添加不同类的对象 // set.add("hello"); // set.add("AA"); // set.add(12); // set.add(12); // set.add("cc"); // set.add(new User("Tom",13)); //举例1. Integer类型 按照从小到大的顺序排列 // set.add(23); // set.add(77); // set.add(-53); // set.add(12); // set.add(56); //举例2. String类型 按照从小到大的顺序排列 // set.add("23"); // set.add("abe"); // set.add("android"); // set.add("JAVA"); // set.add("IOS"); //举例3. 对象 按照从小到大的顺序排列 set.add(new User("Tom",13)); set.add(new User("Jack",23)); set.add(new User("Mary",15)); set.add(new User("Jerry",20)); set.add(new User("Jim",33)); set.add(new User("Jim",33)); Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } }
User类:
package www.entity; import java.util.Objects; public class User implements Comparable { private String name; private int age; @Override public boolean equals(Object o) { System.out.println("执行了"); if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return age == user.age && Objects.equals(name, user.name); } @Override public int hashCode() { return Objects.hash(name, age); } public User(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 compareTo(Object o) { if (o instanceof User){ User user = (User) o; int compare = -this.name.compareTo(user.name); if (compare!=0){ return compare; }else { return Integer.compare(this.age, user.age); } }else { throw new RuntimeException("输入的类型不匹配!"); } } }
4.定制排序:比较两个对象是否相同的标准为:CompareTo()返回0,不再是equals
@Test public void test4() { Comparator comparator = new Comparator() { @Override public int compare(Object o1, Object o2) { //按照年龄从小到大排序 if (o1 instanceof User && o2 instanceof User) { User u1 = (User) o1; User u2 = (User) o2; return Integer.compare(u1.getAge(), u2.getAge()); } else { throw new RuntimeException("输入的数据类型不匹配"); } } }; TreeSet set = new TreeSet(comparator); set.add(new User("Tom", 13)); set.add(new User("Jack", 23)); set.add(new User("Mary", 15)); set.add(new User("Jerry", 20)); set.add(new User("Jim", 33)); set.add(new User("Toke", 33)); Iterator iterator = set.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); } }
输出结果:年龄从小到大排序,如果有相同年龄的,按自上而下的顺序,输出,后面哪个就不再输出。