跳转到内容

比较对象

75% developed
来自 Wikibooks,开放世界中的开放书籍

导航 聚合 主题:v  d  e )

在 Java 中,我们可以区分两种类型的等式。

  • 对象引用等式:当两个对象引用指向同一个对象时。
  • 对象值等式:当两个独立的对象恰好具有相同的数值/状态时。

如果两个对象在引用方面相等,它们在值方面也相等。

比较引用等式

[编辑 | 编辑源代码]

== 运算符可用于检查两个对象引用是否指向同一个对象。

Example 代码部分 5.19:引用等式。
if (objRef1 == objRef2) {
    // The two object references point to the same object
}

比较值等式

[编辑 | 编辑源代码]

为了能够比较同一个类的两个 Java 对象,boolean equals(Object obj) 方法必须被该类覆盖并实现。

实现者决定哪些值必须相等才能认为两个对象相等。例如,在下面的类中,nameaddress 必须相等,但 description 不必。

Computer code 代码清单 5.5:Customer.java
public class Customer {
    private String name;
    private String address;
    private String description;
    // ...
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        } else if (obj == null) {
            return false;
        } else if (obj instanceof Customer cust) {
            if ( ((cust.getName() == null && name == null) || cust.getName().equals(name)) 
              && ((cust.getAddress() == null && address == null) || cust.getAddress().equals(address))
               ) {
                return true;
            }
        }
        return false;
    }

}

equals() 方法被覆盖后,来自同一个类的两个对象可以这样比较

Example 代码部分 5.20:方法用法。
Customer cust1 = new Customer();
Customer cust2 = new Customer();
//...
if (cust1.equals(cust2)) {
    // Two Customers are equal, by name and address
}

注意,相等的对象必须具有相等的哈希码。因此,当覆盖 equals 方法时,您也必须覆盖 hashCode 方法。未能做到这一点将违反 hashCode 方法的一般约定,并且任何使用哈希码的类(例如 HashMap)将无法正常运行。

排序/排序

[编辑 | 编辑源代码]

在 Java 中,有几种现有的方法已经对来自任何类的对象进行了排序,例如 Collections.sort(List<T> list)。但是,Java 需要知道两个对象之间的比较规则。因此,当您定义一个新类并希望您的类的对象可排序时,您必须实现 Comparable 并重新定义 compareTo(Object obj) 方法。

int compareTo(T o)
比较两个对象并返回一个整数
  • 负整数表示当前对象在自然排序中位于参数对象之前。
  • 零表示当前对象和参数对象相等。
  • 正整数表示当前对象在自然排序中位于参数对象之后。

假设名称比地址更重要,而描述被忽略。

Computer code 代码清单 5.6:SortableCustomer.java
public class SortableCustomer implements Comparable<SortableCustomer> {
    private String name;
    private String address;
    private String description;
    // ...
    public int compareTo(SortableCustomer anotherCustomer) {
        if (name.compareTo(anotherCustomer.getName()) == 0) {
            return address.compareTo(anotherCustomer.getAddress());
        } else {
            return name.compareTo(anotherCustomer.getName());
        }
    }

}

实现此接口的对象可以用作排序地图中的键或排序集中的元素,而无需指定比较器。

如果且仅当对于类 C 的每个 e1 和 e2,e1.compareTo((Object) e2) == 0e1.equals((Object) e2) 具有相同的布尔值,则类 C 的自然排序被认为与 equals 一致。注意,null 不是任何类的实例,并且 e.compareTo(null) 应该抛出一个 NullPointerException,即使 e.equals(null) 返回 false。

强烈建议(但不是必需)自然排序与 equals 一致。这是因为没有显式比较器的排序集(和排序地图)在与自然排序与 equals 不一致的元素(或键)一起使用时,行为“奇怪”。特别是,这样的排序集(或排序地图)违反了集合(或地图)的一般约定,集合(或地图)的一般约定是在 equals 方法的定义中定义的。

更改排序/排序

[编辑 | 编辑源代码]

有时我们可能希望更改来自同一个类的对象集合的排序方式。我们可能希望按降序或升序排序。我们可能希望按nameaddress 排序。

我们需要为每种排序方式创建一个类。它必须实现 Comparator 接口。

从 Java 5.0 开始,Comparator 接口是泛型的;这意味着当您实现它时,您可以指定比较器可以比较的对象类型。

Computer code 代码清单 5.7:CustomerComparator.java
public class CustomerComparator implements Comparator<Customer> {
    public int compare(Customer cust1, Customer cust2) {
        return cust1.getName().compareTo(cust2.getName());
    }
}

上面的类然后可以与 SortedSet 或其他支持排序的集合关联。

Example 代码部分 5.21:比较器用法。
Collection<Customer> orderedCustomers = new TreeSet<Customer>(new CustomerComparator());

使用迭代器,可以按name 排序的顺序遍历 orderedCustomers 集合。

列表可以通过 Collectionssort 方法进行排序。

Example 代码部分 5.22:自定义比较。
java.util.Collections.sort(custList, new CustomerComparator());

根据指定比较器引起的顺序,对指定列表进行排序。列表中的所有元素都必须使用指定的比较器相互比较。

对象数组也可以在 Comparator 的帮助下进行排序。

Example 代码部分 5.23:数组排序。
SortableCustomer[] customerArray;
//...
java.util.Arrays.sort(customerArray, new CustomerComparator());

根据指定比较器引起的顺序,对指定的 Customer 对象数组(customerArray)进行排序。数组中的所有元素都必须使用指定的比较器相互比较。


Clipboard

待办事项
添加一些类似于变量 中的练习


华夏公益教科书