Java中的equals方法和自定义比较器
Object中的equals()方法默认是按地址比较,而不按内容进行比较,
public boolean equals(Object obj) { return (this == obj); }
在String中覆写了Object中的equals方法,以用于判断字符串是否相同,
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
"上帝"Object中equals方法可以被子类重写,然后多态调用,当我们要自定义对象比较时一般要覆写equals方法,比如有Person对象,同姓名同年龄,视为同一个对象,
public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p = (Person)obj; return this.name.equals(p.name) && this.age == p.age; }
List集合判断元素是否相同,依据是元素的equals方法。
如果要将自定义对象存入到HashSet中,则要覆写hashCode()和equals():
public int hashCode() { //System.out.println(this.name+"....hashCode"); return name.hashCode()+age*11; } public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p = (Person)obj; //System.out.println(this.name+"....equals..."+p.name); return this.name.equals(p.name) && this.age==p.age; }
HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
自定义比较器:
当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身具备比较性。
当两种排序都存在时,以比较器为主。
方式1:定义一个类,实现Comparable接口,覆盖compareTo方法。
class Student implements Comparable//该接口强制让学生具备比较性。 { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } //先按年龄从小到大排序,如果年龄相同,再按名字 public int compareTo(Object obj) { if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student)obj; if(this.age>s.age) return 1; if(this.age==s.age) { return this.name.compareTo(s.name); } return -1; } public String getName() { return name; } public int getAge() { return age; } } class Test { public static void main(String[] args) { TreeSet ts = new TreeSet(new Mycompare()); ts.add(new Student("lisi02",22)); ts.add(new Student("lisi02",21)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi007",29)); Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } } }
方式2:定义一个类,还要再自定义一个比较器来实现Comparator接口,覆盖compare方法。
定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
class Student { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } //自定义比较器:先按名字来排序,如果名字相同再按年龄 class Mycompare implements Comparator { public int compare(Object o1,Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int num = s1.getName().compareTo(s2.getName()); if (num == 0) return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); return num; } } class Test { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(new Mycompare()); ts.add(new Student("lisi02",22)); ts.add(new Student("lisi02",21)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi06",18)); ts.add(new Student("lisi007",29)); for (Iterator<Student> it = ts.iterator();it.hasNext() ; ) { Student stu = it.next(); System.out.println(stu.getName()+".."+stu.getAge()); } } }