目录
判定原则
猫类 狗类 老虎类的说明
Cat为例引入
ObjectHashSetTest
对Cat和Dog测试的HashCode总结
对HashSet Tiger和LinkedHashSet Tiger总结
ObjectTreeSetTest
compareTo方法具体规则
判定原则
总得来说 判定元素相同有两个原则
1.HashSet和LinkedHashSet判定元素重复的原则
判定两个元素的hashCode返回值是否相同,若不同,返回false
若两者hashCode相同,判定equals方法,若不同,返回false;否则返回true.
hashCode和equals方法是所有类都有的,因为Object类有
2.TreeSet判定元素重复的原则
需要元素继承自Comparable接口
比较两个元素的compareTo方法
猫类 狗类 老虎类的说明
以猫 狗 老虎为例来更了解以上两种原则
class Cat//猫类
{
private int size;
public Cat(int size)
{
this.size = size;
}
}
class Dog { //狗类
private int size;//狗的大小
public Dog(int s) {
size = s;
} //一个构造方法
public int getSize() {
return size;
}//get方法
public boolean equals(Object obj2) {
System.out.println("Dog equals()~~~~~~~~~~~");
if(0==size - ((Dog) obj2).getSize()) {
return true;
} else {
return false;
}
}//判断给的狗是否大小相同
public int hashCode() {
System.out.println("Dog hashCode()~~~~~~~~~~~");
return size;
}
public String toString() {
System.out.print("Dog toString()~~~~~~~~~~~");
return size + "";
}
}
//老虎类
public class Tiger implements Comparable{
private int size;
public Tiger(int s) {
size = s;
}
public int getSize() {
return size;
}
public int compareTo(Object o) {
System.out.println("Tiger compareTo()~~~~~~~~~~~");
return size - ((Tiger) o).getSize();
}
}
Cat为例引入
首先以猫为例
import java.util.HashSet;
public class HashSetJudgeRuleTest {
public static void main(String[] args) {
HashSet<Cat> hs = new HashSet<Cat>();
hs.add(new Cat(1));
hs.add(new Cat(2));
hs.add(new Cat(3));
hs.add(new Cat(3));
System.out.println(hs.size()); //结果为4
}
}
我们在程序中 加入四只猫 输出数量 我们希望做到的是 程序能够将尺寸为三号的猫看作是同一个 但程序判定为不同的猫 输出4
ObjectHashSetTest
再看另一段测试代码ObjectHashSetTest
通过这段代码来看HashSet和LinkedHashSet在加入元素时是如何判断重复的
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.TreeSet;
public class ObjectHashSetTest {
public static void main(String[] args) {
System.out.println("==========Cat HashSet ==============");
HashSet<Cat> hs = new HashSet<Cat>(); //定义
hs.add(new Cat(2));
hs.add(new Cat(1));
hs.add(new Cat(3));
hs.add(new Cat(5));
hs.add(new Cat(4));
hs.add(new Cat(4));
System.out.println(hs.size()); //输出结果6
System.out.println("========================");
LinkedHashSet<Cat> lhs= new LinkedHashSet<Cat>();
lhs.add(new Cat(2));
lhs.add(new Cat(1));
lhs.add(new Cat(3));
lhs.add(new Cat(5));
lhs.add(new Cat(4));
lhs.add(new Cat(4));
System.out.println(lhs.size()); //输出结果6
System.out.println("==========Dog HashSet ==============");
HashSet<Dog> hs2 = new HashSet<Dog>();
hs2.add(new Dog(2));
hs2.add(new Dog(1));
hs2.add(new Dog(3));
hs2.add(new Dog(5));
hs2.add(new Dog(4));
hs2.add(new Dog(4));
System.out.println(hs2.size()); //输出结果5
System.out.println("========================");
LinkedHashSet<Dog> lhs2= new LinkedHashSet<Dog>();
lhs2.add(new Dog(2));
lhs2.add(new Dog(1));
lhs2.add(new Dog(3));
lhs2.add(new Dog(5));
lhs2.add(new Dog(4));
lhs2.add(new Dog(4));
System.out.println(lhs2.size()); //输出结果5
System.out.println("==========Tiger HashSet ==============");
HashSet<Tiger> hs3 = new HashSet<Tiger>();
hs3.add(new Tiger(2));
hs3.add(new Tiger(1));
hs3.add(new Tiger(3));
hs3.add(new Tiger(5));
hs3.add(new Tiger(4));
hs3.add(new Tiger(4));
System.out.println(hs3.size()); //输出结果6
System.out.println("========================");
LinkedHashSet<Tiger> lhs3= new LinkedHashSet<Tiger>();
lhs3.add(new Tiger(2));
lhs3.add(new Tiger(1));
lhs3.add(new Tiger(3));
lhs3.add(new Tiger(5));
lhs3.add(new Tiger(4));
lhs3.add(new Tiger(4));
System.out.println(lhs3.size()); //输出结果6
}
}
(说明:Cat Dog Tiger类在文章开头)
首先看main函数中HashSet Cat 我们期望它能够做到判断最后两只猫是相同的 但Cat这个类中只定义了size 所以输出结果为六只猫 LinkedHashSet也是如此 结果相同
接下来我们重新定义HashSet Dog 在Dog类中也是定义了一个size 一个构造函数 以及一些其他的方法 我们运行程序 结果为5 说明程序认为这两只狗相同 我们注意到 在HashSet里添加元素的时候 它会去调用这个元素的hashCode方法 比较这两个元素的hashCode是否一样 如果一样 继续比较 如果不一样 直接判定为不一样 而cat类中的hashcode是继承于object的 没有自己定义自己的hashcode
对Cat和Dog测试的HashCode总结
- Cat类本身没有hashCode() 而是继承Object类的 而0bject的hashCode()会返回对象信息和内存地址经过运算后的一个int值 两个不同的Cat(4)对象 它们的hashCode()返回值是不同的
- Dog类本身改写了hashCode()方法 其返回值是具体的size 所以两个不同Dog(4) 它们的hashCode()返回值是相同的
在HashCode判定完成后 接下来要再继续判定equals方法 如果HashCode相同 equals不同 就还是不同 如果HashCode相同 equals也相同那么就认为这两个元素重复了 那么第二个add就不会被加入到HashSet里面去(注意:只有hashcode相同时才进行下一步比较)
在LinkedHashSet Dog中 最后两个元素的hashcode和equals都相同 所以判定为相同 所以最后的元素就只有五个
再回看Dog类 对于hashcode方法和equals方法我们需要进行重写 这两个方法也是继承Object类的 同时注意 如果重写了hashcode方法和equals方法 我们也需要将toString方法也进行重写 否则将出现异常情况
接下来 加入老虎 同样看Tiger类的定义 定义了一个Compareto方法 size相同返回0 不相同不返回0 而Tiger本身继承了一个接口 叫Comparable接口 可比较的接口 结果我们发现 程序结果为6 表明HashSet 和LinkedHashSet只根据hashcode和equals方法判定是否重复
对HashSet Tiger和LinkedHashSet Tiger总结
- Tiger实现Comparable接口,所以必须实现compareTo方法来比较大小。
ObjectTreeSetTest
接下来我们看ObjectTreeSetTest
import java.util.TreeSet;
public class ObjectTreeSetTest {
public static void main(String[] args) {
/*
System.out.println("==========Cat TreeSet ==============");
TreeSet<Cat> ts = new TreeSet<Cat>();
ts.add(new Cat(2));
ts.add(new Cat(1));
ts.add(new Cat(3));
ts.add(new Cat(5));
ts.add(new Cat(4));
ts.add(new Cat(4));
System.out.println(ts.size()); //5
System.out.println("==========Dog TreeSet ==============");
TreeSet<Dog> ts2 = new TreeSet<Dog>();
ts2.add(new Dog(2));
ts2.add(new Dog(1));
ts2.add(new Dog(3));
ts2.add(new Dog(5));
ts2.add(new Dog(4));
ts2.add(new Dog(4));
System.out.println(ts2.size()); //结果为5
*/
System.out.println("==========Tiger TreeSet ==============");
TreeSet<Tiger> ts3 = new TreeSet<Tiger>();
ts3.add(new Tiger(2));
ts3.add(new Tiger(1));
ts3.add(new Tiger(3));
ts3.add(new Tiger(5));
ts3.add(new Tiger(4));
ts3.add(new Tiger(4));
System.out.println(ts3.size()); //5
}
}
为什么将前面一段代码注释掉 是因为添加到TreeSet的 需要实现Comparable接口 即实现compareTo方法 实现Comparable接口也是TreeSet的前提条件 而Cat Dog类都没有 只有Tiger有 而其中加入的Integer元素 Integer类本身也是实现了一个Comparable的接口 所以可以加入到TreeSet里面去
程序运行中 在添加Tiger元素的过程中 不断调用Tiger中的CompareTo方法来来判定元素是否重复 而hashcode equals tostring方法都不会被调用 只有当Tiger中的CompareTo方法两个size返回值是0 这两个元素才会被判定为相同
compareTo方法具体规则
- 给出compareTo方法具体规则如下:
- int a = obj1.compareTo(obj2);
- 如果a>0,则obj1>obj2;
- 如果a==0;则obj1==obj2;
- 如果a<0,则obj1<obj2。
最后 以上三种Set我们要根据对于业务的不同需求来选择(ps:有些方法并未严格按照大小写书写 但意思应该能够明白 第一次写请多包涵)