在值类型和引用类型的上下文中,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,我假设它们最初会返回 true,但它们不相等是有道理的。但是 == 和 .Equals 之间到底有什么区别呢?
在情况 3 中,对字符串使用 '==' 运算符比较它们的值而不是内存地址。
在情况 6 中,.Equals 方法比较的值类型不同,而该方法期望它们具有相同的类型。因此它返回 false。
我仍然不明白的是情况7。为什么在这种情况下对象具有相同的哈希码?抱歉代码太长,提前致谢!
I've come across this question quite a few times, and while the answers make sense, i wanted to check it out myself with a simple console app.
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;
}
}
}
Assumption 1 : What i understood from the commonly posted replies was that for reference types, a==b compares references , whereas a.Equals(b) compares the actual values referenced. This is what threw me off when viewing the results of my program.
With reference to my program, In Case 2 - Though the referenced memory addresses for a and c are different, their fields are assigned the same values. Still a.Equals(c) returns false as they still are not equal as they have different hashcodes. I had assumed they would return true initially based on Assumption 1, but it makes sense they are not equal. But then what really is the exact difference between == and .Equals?
In case 3 , using the '==' operator with strings compares their values not memory addresses.
In case 6, the value types being compared by the .Equals method are different, whereas the method expects them to be of the same type. Hence it returns false.
What I still don't understand is case 7. Why do the objects have the same hashcode in this case? Sorry for the lengthy code and thanks in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我认为要记住的关键一点是,使用
a == b
时,编译器通过查看a
和的类型来确定在编译时调用哪个函数。 b。如果
a
和b
都是object
类型,编译器将生成对ReferenceEquals
的调用,而如果它们两者都是string
类型,编译器将生成对string.Equals
的调用。然而,当编译器看到
a.Equals(b)
时,它会生成对a
的Equals
方法的调用,该方法在运行时,因为它是一个虚拟方法。如果a
是一个字符串,那么它将调用进行字符串比较的重载(如您所期望的)。如果a
是某个其他对象,那么它将调用该对象上的重载Equals
方法(如果该对象有一个),或者object.Equals
(这确实ReferenceEquals
比较)(如果不存在)。I think a key thing to remember is that with
a == b
the compiler determines what function to call at compile-time by looking at the types ofa
andb
. Ifa
andb
are both of typeobject
, the compiler will generate a call toReferenceEquals
, whereas if they are both of typestring
the compiler will generate a call tostring.Equals
.When the compiler sees
a.Equals(b)
, however, it generates a call to thea
'sEquals
method, which is determined at runtime because it's a virtual method. Ifa
is a string then it will call the overload that does a string comparison (as you expect). Ifa
is some other object then it will call the overloadedEquals
method on that object if it has one, orobject.Equals
(which does aReferenceEquals
comparison) if it doesn't.a.Equals(b)
只会执行您编写代码的操作。这只是一个虚拟方法调用。默认行为(对于引用类型)是仅比较引用。
a.Equals(b)
will only do what you've written code for. It's just a virtual method call.The default behaviour (for reference types) is to just compare references.
你是如何在 Class1 中实现 Equals() 的?如果您不提供覆盖 Equals 的方法,它将使用默认的 Equals 方法,该方法仅比较参考值。
How are you implementing Equals() in Class1? If you don't provide a method to override Equals it'll use the default Equals method which will just compare the reference values.
a.equals 是 java.lang.Object 类中存在的方法,它将传递给它的对象的引用与调用它的对象进行比较。
== 是再次检查引用的运算符。
b.由于 equals 是 Object 类中的方法,因此它可以被重写并可用于执行任何操作,可以比较对象内的值、比较引用或计算哈希码并比较它们。
因此,在 String 类中,equals 方法已被重写以比较传递给它的对象的值。
a.equals is the method present in the java.lang.Object class which compares the references of the object passed to it with object on which it was called.
== is a operator to check again the references.
b. Since equals is method in Object class it can be overridden and can be used to do anything, either to compare values inside the objects, compare references or calculate hash codes and compare them.
So incase of String class the equals method have been overidden to compare the values of the objects passed to it.