Почему метод equals в классе String определен как equals(Object anObject), но не как equals(String anObject)?

#java #string #equals

#java #строка #равно

Вопрос:

это equals() из String class

 public boolean equals(Object anObject)
{
    if (this == anObject)
    {
        return true;
    }
    else
    {
        if (anObject instanceof String)
        {
            String aString = (String) anObject;
            if (this.coder() == aString.coder())
            {
                return this.isLatin1() ? StringLatin1.equals(this.value, aString.value) : StringUTF16.equals(this.value, aString.value);
            }
        }
        return false;
    }
}
 
  1. Итак, почему он определен как equals(Object anObject) , но не как equals(String anObject) ?
    Какой смысл иметь возможность получать любой объект, если он возвращает false для любых других объектов, кроме String ?
  2. Если я создаю MyOwnClass , должен ли я переопределить equals() метод как
    equals(Object obj)
    или как
    equals(MyOwnClass obj)
    Если как в первом варианте, то почему?

PS: ковариация работает в возвращаемом типе при переопределении. Я подумал, что если ковариация работает в возвращаемом типе при переопределении, то она должна работать и в аргументах функции.

 {
    public A foo(A o)
    {
        return new A();
    }
}

class B extends A
{
    @Override // everything OK
    public B foo(A o)
    {
        return new B();
    }
}
 

Комментарии:

1.Это происходит потому equals(String anObject) , что не переопределяет Object equals метод, а вместо этого перегружает его.

2. Подсказка: посмотрите на исходный код метода equals в классе java.lang.String

Ответ №1:

Пока нет ответа на суть проблемы.

Система ввода Java является ковариантной (пока вы не перейдете к generics, где вы выбираете, какую дисперсию вы хотите).

Учитывая, что class Apple extends Fruit и class Fruit extends Object , тогда все яблоки также являются фруктами, все фрукты также являются объектами, и все яблоки также являются объектами.

И Object , потому java.lang.Object что так говорит, имеет equals(Object other) метод. Это означает, что яблоки также должны иметь этот метод:

  1. Все яблоки являются объектами.
  2. У всех объектов есть equals(Object) метод
  3. Следовательно, у яблок есть equals(Object) метод.

Итак, почему у объектов есть этот метод? Потому что это полезно. Поскольку он ставит ArrayList contains(Object other) галочку в методе, он создает java.util .Приступайте к работе. Как только вы решили, что у всех объектов есть equals(Object other) метод, остальные (в частности, у яблок есть equals(Object other) метод, который тривиально возвращает false, если вы спросите его, равно ли оно какому-либо объекту, отличному от apple) заблокированы; теперь это так просто, потому что система, которую мы настроили здесь (это ковариантная система типизации, где базовый тип, от которого наследуются все типы, имеет equals(Object) метод), диктует, что это должно быть так.

Да, спецификация языка java фактически гарантирует это; вы не можете «удалить» equals(Object) метод из яблок. Однако суть вопроса в том, почему спецификация Java работает именно так.

Комментарии:

1. Я подумал, что если ковариация работает в возвращаемом типе при переопределении, то она должна работать и в аргументах функции.

2. Хорошо, допустим, у яблок есть только equals(String) . Затем: Apple a = new Apple(); Object o = a; o.equals(new Pear()); — что теперь? как компилятор может знать, что o.equals(Pear) этого не существует? Вы можете расширить свои типы параметров. Не затягивайте их.

3. Я имею в виду параметры, а не аргументы (фактические параметры).

4.@Denis_newbie «Строка x» public boolean equals(String x) — это то, о чем я говорю. термины «параметр» и «аргумент» неоднозначны.


Ответ №2:

Итак, почему он определен как equals(Object anObject), но не как equals(String anObject)?

class String переопределяет Object#equals , который имеет следующую подпись:

 public boolean equals(Object obj)
 

В случае переопределения сигнатура метода (имя и параметры) в дочернем классе должна быть такой же, как в суперклассе. Если вы измените количество и / или тип параметров, метод будет перегружен, а не переопределен.

Если я создаю MyOwnClass, должен ли я переопределить метод equals() как equals(Object obj) или как equals(MyOwnClass obj)

Вы должны переопределить его как

 public boolean equals(Object obj)
 

в противном случае он не будет переопределен; скорее, он будет перегружен, как упоминалось выше.

Ответ №3:

Какой смысл иметь возможность получать любой объект, если он возвращает false для любых других объектов, кроме String ?

Учитывая два Object s , вы можете законно спросить, равны ли они, даже если конкретными типами являются, скажем, Integer и String .

 Object first = 0;   // first is an Integer
Object second = ""; // second is a String

boolean equal = second.equals(first);
 

equals Метод должен принимать самый общий тип.

должен ли я переопределять метод equals() как equals(Object obj) или как equals(MyOwnClass obj) если бы, как в первом варианте, тогда почему?

Первый. Если вы используете второй способ, он будет вызван только в том случае, если и приемник, и параметр имеют тип MyOwnClass (например, , receiver.equals(parameter) ). В противном случае equals(Object) Object будет вызван from , потому что перегрузка метода разрешена компилятором и equals(Object) является единственным известным компилятору, который соответствует получателю и параметру.