比较器:等于方法功能

spa*_*wal 5 java compare comparator

其实我经历在其中提到,当我们需要实现比较接口,我们可以覆盖equals方法教程之一(不过没有必要重写).

所以只是为了更好地理解

我重写方法如下

Test.java

 import java.util.TreeSet;

public class Test
{
    public static void main(String[] args)
    {
        TreeSet t = new TreeSet(new MyComparator());
        t.add(1);
        t.add(1);
        t.add(2);
        System.out.println(t);
    }
}
Run Code Online (Sandbox Code Playgroud)

MyComparator.java

import java.util.Comparator;

public class MyComparator
    implements Comparator
{
    @Override
    public int compare(Object o1, Object o2)
    {
        Integer i1 = (Integer) o1;
        Integer i2 = (Integer) o2;
        return i1.compareTo(i2);
    }

    @Override
    public boolean equals(Object o1)
    {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于其他场景

import java.util.Comparator;

public class MyComparator
    implements Comparator
{
    @Override
    public int compare(Object o1, Object o2)
    {
        Integer i1 = (Integer) o1;
        Integer i2 = (Integer) o2;
        return i1.compareTo(i2);
    }

    @Override
    public boolean equals(Object o1)
    {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在无论我从equals方法返回的是true还是false ..它返回相同的treeset值.如果有人能够清除equals方法的功能性概念请

Mik*_*kis 7

equals()在a上实现该方法Comparator允许您指示一个比较器提供与另一个比较器相同的顺序.它与元素的排序方式无关.它是一种非常先进且极少需要的功能.您极不可能遇到equals()实际调用比较器方法的情况.我建议你忽略它.


fg7*_*8nc 5

equals()类的方法,Comparator并且Comparator需要等于一致性,因为如果compareTo()equals()方法没有返回一致的结果,一些 Java 集合类可能会表现得不可预测。

Java 使用 == 运算符来比较两个原语和/或检查两个变量是否引用同一个对象。例子 :

String apple1 = new String("apple");
String apple2 = new String("apple"); 
System.out.println(apple1.equals(apple2)); // true

StringBuilder app1 = new StringBuilder("apple"); 
StringBuilder app2 = new StringBuilder("apple"); 
System.out.println(app1.equals(app2));   // false
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我们得到了不同的行为。这是为什么?发生这种情况是因为 String 类实现了一个 equals() 方法,该方法检查值是否相同。另一方面,StringBuilder 没有实现 equals() 方法,而是使用Object类提供的 equals() 实现。由Object类提供(继承)的实现只是简单地检查两个引用的对象是否相同。

因此,要检查两个对象是否等效,Java 会使用该equals()方法,并且每当您引入自己的类型时,equals()如果您不想依赖方法的Object类实现,则必须覆盖该equals()方法

例如,让我们介绍我们自己的类型:简单类 Apple

public class Apple  {

    private int weight;
    private int cost;
    private String color;
Run Code Online (Sandbox Code Playgroud)

现在你将如何决定两个苹果是否相等?按颜色、重量、价格或其他什么?这就是为什么您需要明确提供您自己的 equals 方法,以便可以比较您的类型的对象是否相等。

下面的示例比较两个Apple对象是否相等,如果它们属于同一个“Apple”类并且它们的重量和成本相同,则表示两个对象相等。请注意,我们不按颜色进行比较,我们假设颜色在我们的案例中无关紧要,这意味着我们接受这样一个事实,即不同颜色但具有相同重量和相同成本的苹果被认为是相等的。

    @Override
    public boolean equals(Object obj) {
        if ( !(obj instanceof Apple)) return false;    
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Apple other = (Apple) obj;
        if (cost != other.cost and weight != other.weight )
            return false;
        return true;
    }
Run Code Online (Sandbox Code Playgroud)

您可以为您的equals()方法实现您喜欢的任何逻辑。Javaequals()方法非常重要,它提供了开发者应遵循的契约或重要规则。我不会列出它们,你可以从这里得到它们,它们是合乎逻辑的并且非常直接。

还有另一个契约equals()- 每当您覆盖时equals(),您也应该覆盖hashCode()方法。这背后的原因是因为当对象作为键存储在映射中时,某些 Java 集合在内部使用哈希码。

哈希码是一个将对象分类的数字。想象一下,您收到各种苹果(红色、绿色、黄色),并在要求您提供特定种类时要求将它们归还。如果您对它们进行分类,将它们相应地放入不同的桶中,并在要求进行特定排序时(为简单起见,假设为红苹果),那么效率会更高,速度更快,并且由于您已经对它们进行了排序和分类,因此可以更快地检索它们. 希望现在清楚为什么您需要实施hashcode(). hashcode()有自己的合同或规则与equals()方法相同。他们几乎是常识:

首先,hashcode()同一程序内的结果不会改变。这意味着在你的hascode()计算中你不应该包括我在程序执行过程中改变的变量。例如,如果 Apple 的成本是可变的,即它可能会改变,那么将它们包含在 hashcode() 计算中并不是一个好主意,否则结果将不一致。

第二条规则说,当使用两个对象equals()调用hashCode()时,如果返回 true,则调用这些对象中的每一个都必须检索相同的结果。但是,如果equals()在使用两个对象调用时返回 false,则调用hashCode()这些对象中的每一个都不必返回不同的结果。令人困惑?为什么?因为hashCode()在对不等的对象调用时,结果不需要是唯一的 - 您可以将两个不等的对象放在一个桶中。

现在关于Comparator- 当您引入自己的类型而不是使用内置类型时,更容易理解它的逻辑。

例如,让我们说我们有一流的Apple具有两个属性:weightprice,并希望把out对象这种类型的进入有序集合TreeSet

public class Apple  {

    private int weight;
    private int cost;
Run Code Online (Sandbox Code Playgroud)

现在,您希望如何在集合中对这些苹果进行排序 - 您是要按weight还是按对它们进行排序price?编译器将如何决定?

提供适当的ComparatorComparable允许您传递您的意图。让我们尝试将对象添加到集合中。

  public class Apple {

    private int weight;
    private int cost;

  public static void main(String[] args) {
    Apple redApple = new Apple();
    redApple.setCost(10);
    redApple.setWeight(2);

    Apple greenApple = new Apple();
    greenApple.setCost(12);
    greenApple.setWeight(3);

    Set<Apple> apples = new TreeSet<>();
    apples.add(redApple);
    apples.add(greenApple);

    System.out.println(apples);
   } 

    public int getWeight() {
       return weight;
    }

   public void setWeight(int weight) {
       this.weight = weight;
    }

   public int getCost() {
       return cost;
   }

   public void setCost(int cost) {
     this.cost = cost;
    }

   @Override
   public String toString() {
       return "Apple [weight=" + weight + ", cost=" + cost + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你运行上面的代码,你会得到 RuntimeError : Apple cannot be cast to java.lang.Comparable,因为编译器必须弄清楚你想如何比较你的苹果。所以让我们修复它:让我们实现Comparable接口

  public class Apple implements Comparable<Apple> {
Run Code Online (Sandbox Code Playgroud)

和覆盖compareTo方法

 @Override
    public int compareTo(Object obj) {

        int cost = ((Apple) obj).getCost();
        return this.getCost() - cost; // sorting in ascending order.

        // change to this to sort in Descending order
        // return cost - this.getCost();
    }
Run Code Online (Sandbox Code Playgroud)

现在有了这些更改,让我们运行我们的代码:

[Apple [weight=2, cost=10], Apple [weight=3, cost=12]]
Run Code Online (Sandbox Code Playgroud)

我们的收藏按成本升序排列。

现在,如果您无权访问Apple类并且无法更改源代码以实现Comparable.

这是有Comparator帮助的地方。

删除implements Comparable,因为我们假设我们不能修改这个类

public class Apple {
Run Code Online (Sandbox Code Playgroud)

和删除方法

@Override
public String toString() {
    return "Apple [weight=" + weight + ", cost=" + cost + "]";
}
Run Code Online (Sandbox Code Playgroud)

添加比较器实现:

  public class AppleComparator implements Comparator<Apple> {

        @Override
        public int compare(Apple app1, Apple app2) {
            return app1.getCost() - app2.getCost();
        }

}
Run Code Online (Sandbox Code Playgroud)

现在我可以只提供Comparator给收藏来表达我的意图

Set<Apple> apples = new TreeSet<>(new AppleComparator());
Run Code Online (Sandbox Code Playgroud)

集合将再次按成本排序,对应于提供的比较器。因此,我们需要提供ComparatorComparable以便将它们存储在集合中,特别是在TreeSet.

现在关于您的问题:Comparatorequals()method之间没有联系。Comparable(compareTo() method ) 和equals()method之间只需要一致性。

示例 - 在上面提到的Apple类中,在实现 Comparable 的版本中,我们引入了用于确定相等性的新逻辑。compareTo()如果两个对象相等,则该方法返回 0,而如果两个对象相等,则您的equals()方法返回 true。

compareTo()当 x.compareTo(y) 等于 0 时,使用required 与 equals 一致的自然顺序为真。 所以你必须使你的Comparable类与 equals 一致,因为如果compareTo()equals()方法没有返回一致的结果。

以下示例显示了与 equals 不一致的 compareTo() 方法:

public class Apple implements Comparable<Apple> { 

private int weight;
private int cost;
private String color;

public boolean equals(Object obj) {
   if(!(obj instanceof Apple)) { 
      return false;
  }
   Apple other = (Apple) obj; 
    return this.weight == other.weight;
  }

public int compareTo(Apple obj) {
    return this.cost.compareTo(obj.cost); }
 }
Run Code Online (Sandbox Code Playgroud)

如果我们想按成本对 Apple 对象进行排序,但成本可能不是唯一的。可能有两个具有相同成本的对象。因此,compareTo()比较两个相等的Apple对象时, 的返回值可能不为0 ,这意味着该compareTo()方法与 不一致equals()

  • The first sentence of this answer is incorrect. `Comparator&lt;T&gt;::compare(:T, :T)` must be consistent with `T::equals(:T)`. It has nothing to do with `Comparator&lt;T&gt;::equals(Comparator&lt;T&gt;)`. (2认同)

azr*_*zro 1

您覆盖的方法equals()位于 中,MyComparator class因此如果您需要比较 2 个实例,则会使用该方法Mycomparator;)

这不是你正在做的,你正在比较int,所以是的,该compare()方法很有用,因为它将用于sortingTreeset这里不会使用 equals 方法

在 99% 的情况下,您不需要override equals在类中使用方法implements Comparator,因为它们在这里只是为了将compare自己的值而不是另一个值,事实上,因为大多数时候它们必须具有属性,所以您不会有 comparatorequals 。