В чем разница между a==b и a.Equals(b) в контексте значений и ссылочных типов?

Я сталкивался с этим вопросом довольно много раз, и хотя ответы на него имеют смысл, я хотел сам проверить это с помощью простого консольного приложения.

    class Program
{
    static void Main(string[] args)
    {
        // Case 1 : FOR REFERENCE TYPES where class b is a copy of class a
        Class1 a = new Class1("Hello");
        Class1 b = a;
        Console.WriteLine("case 1");
        Console.WriteLine(a.GetHashCode());
        Console.WriteLine(b.GetHashCode());
        Console.WriteLine(a==b); //true
        Console.WriteLine(a.Equals(b)); //true

        // Case 2 : FOR REFERENCE TYPES where class b is not a copy of class a, but it assigned the same values
        // Though the referenced memory addresses are different, the fields of the class are assigned the same values, but will have different hashcodes and are therfore not equal.
        Class1 c = new Class1("Hello");
        Console.WriteLine(" ");
        Console.WriteLine("case 2");
        Console.WriteLine(a.GetHashCode());
        Console.WriteLine(c.GetHashCode());
        Console.WriteLine(a==c);//false
        Console.WriteLine(a.Equals(c));//false

        // Case 3 : FOR REFERENCE TYPES where two strings are assigned the same values, an exception to the way value types behave.
        // using the '==' operstor with strings compares their values not memory addresses.
        string s1 = "hi";
        string s2 = "hi";
        Console.WriteLine(" ");
        Console.WriteLine("case 3");
        Console.WriteLine(s1 == s2);//true
        Console.WriteLine(s1.Equals(s2));//true

        //Case 4 : FOR VALUE TYPES - they are the same when comparing the same type.
        int x = 5;
        int y = 5;
        Console.WriteLine(" ");
        Console.WriteLine("case 4");
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(x == y);//true
        Console.WriteLine(x.Equals(y));//true

        // Case 5 : Another value type scenario for completeness
        x = y;
        Console.WriteLine(" ");
        Console.WriteLine("case 5");
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(x.GetType());
        Console.WriteLine(y.GetType());
        Console.WriteLine(x == y);//true
        Console.WriteLine(x.Equals(y));//true

        // Case 6 : Yet Another value type scenario for completeness, with different value types.
        float z = 5;
        Console.WriteLine(" ");
        Console.WriteLine("case 6");
        Console.WriteLine(x.GetType());
        Console.WriteLine(z.GetType());
        Console.WriteLine(x);
        Console.WriteLine(z);
        Console.WriteLine(x == z);//true
        Console.WriteLine(x.Equals(z));//false, as the values being compared are of two different types- int and float. The .Equals method expects them to be the same type.

        // Case 7 : For giggles, Yet Another ref type scenario for completeness, with objects.
        string s3 = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
        string s4 = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
        object obj1 = s3;
        object obj2 = s4;
        Console.WriteLine(" ");
        Console.WriteLine("case 7");
        Console.WriteLine(obj1.ToString());
        Console.WriteLine(obj2.ToString());
        Console.WriteLine(obj1.GetHashCode());
        Console.WriteLine(obj2.GetHashCode());
        Console.WriteLine(obj1 == obj2);//false - as they refer to different addresses.
        Console.WriteLine(obj1.Equals(obj2));//true - in this case both objects have the same hashcode.
        Console.ReadKey();

    }

    public class Class1
    {
            string name;
            public Class1(string strName)
            {
                name = strName;
            }
     }

}

Предположение 1: Что я понял из часто публикуемых ответов, так это то, что для ссылочных типов a==b сравнивает ссылки, тогда как a.Equals(b) сравнивает фактические значения, на которые ссылаются. Это то, что меня оттолкнуло при просмотре результатов моей программы.

Что касается моей программы, в случае 2 - Хотя адреса памяти, на которые ссылаются, для a и c различны, их полям присваиваются одинаковые значения. Тем не менее a.Equals(c) возвращает false, поскольку они по-прежнему не равны, поскольку имеют разные хэш-коды. Я предполагал, что они вернут истину первоначально на основе предположения 1, но имеет смысл, что они не равны. Но тогда в чем же разница между == и.Equals?

В случае 3 использование оператора '==' со строками сравнивает их значения, а не адреса памяти.

В случае 6 типы значений, сравниваемые методом.Equals, различаются, тогда как метод ожидает, что они будут одного типа. Следовательно, он возвращает ложь.

Чего я до сих пор не понимаю, так это случая 7. Почему в этом случае объекты имеют одинаковый хэш-код? Извините за длинный код и спасибо заранее!

4 ответа

Решение

Я думаю, что ключевым моментом, который нужно помнить, является то, что с a == b компилятор определяет, какую функцию вызывать во время компиляции, просматривая типы a а также b, Если a а также b оба типа objectкомпилятор сгенерирует вызов ReferenceEqualsтогда как если они оба типа string компилятор сгенерирует вызов string.Equals,

Когда компилятор видит a.Equals(b)Однако он генерирует вызов к a"s Equals метод, который определяется во время выполнения, потому что это виртуальный метод. Если a это строка, тогда она вызовет перегрузку, которая выполняет сравнение строк (как вы ожидаете). Если a это какой-то другой объект, то он будет вызывать перегруженный Equals метод для этого объекта, если он есть, или object.Equals (который делает ReferenceEquals сравнение) если это не так.

Как вы реализуете Equals() в Class1? Если вы не предоставите метод для переопределения Equals, он будет использовать метод Equals по умолчанию, который будет просто сравнивать контрольные значения.

a.Equals(b) будет делать только то, для чего вы написали код. Это просто вызов виртуального метода.

Поведение по умолчанию (для ссылочных типов) - просто сравнивать ссылки.

a.equals - это метод, представленный в классе java.lang.Object, который сравнивает ссылки переданного ему объекта с объектом, для которого он был вызван.

== является оператором для повторной проверки ссылок.

б. Поскольку метод equals является методом в классе Object, он может быть переопределен и может использоваться для любых действий: для сравнения значений внутри объектов, сравнения ссылок или вычисления хеш-кодов и их сравнения. Таким образом, в случае использования класса String метод equals был переопределен для сравнения значений переданных ему объектов.

Другие вопросы по тегам