Equals方法的对象比较

C# 对象比较

 最近工作中接触到这个,有点迷糊。

.Net 中主要有四种相等比较,分别是:

  • ==操作符、
  • Object.Equals方法、
  • Object.ReferenceEquals方法、
  • 对象实例的Equals方法。

Object 的 Equals 静态方法实际上是对实例Equals方法的扩展,

增加了 null 的判断,适用于比较两个可能为空引用的对象。

对于值类型,和 Equals 实例方法完全一样。

复制代码

public static bool Equals(object objA, object objB)
{
  if (objA == objB)
  {
    return true;
  }
  if (objA != null && objB != null)
  {
    return objA.Equals(objB);
  }
  return false;
}

复制代码

ReferenceEquals 方法是比较两个对象的引用是否相同,即栈上的地址是否一样

对于值类型没有意义,参数中若有值类型参数出现,必定返回false。

对于引用类型,如果方法结果为True,这个相等是最严格、最纯粹、如假包换的相等,说明这两个参数其实是同一个对象,当然无论用其他哪种相等比较方式,同样也应返回True。

public static bool ReferenceEquals(object objA, object objB)
{
    return objA == objB;
}

==,

上面,我们说两个Object静态方法区别在值类型和引用类型上,对于其他相等比较区别也主要在此。

一般情况下,不是所有,对于引用类型 == 和 ReferenceEquals 静态方法作用相同;

值类型在这里则有区分,对于一些原生值类型,如int,long,char等,==是直接比较其数值,而且不同类型间可以互相比较,比如int和char,'A’==65返回的是True;

而对于一般的Struct,如果没有在代码中定义==(也包括!=)操作符,是不能用==比较的。

引用类型也可以定义 == 操作符,覆盖CLR原生支持的比较。

最常见的是String类型,它就定义了==操作符,很合理地放宽了相等的条件,使得String类型像原生值类型一样按值比较。String类的 == 操作符其实就是直接调用的被自己重写过Equals方法。

String类是最常用也最特别的一个类,大部分面试都会问到String的特点,除了不可变和内存驻留机制外,其他主要特点就是相等的特殊性了。

public virtual bool Equals(object obj)
{
    return RuntimeHelpers.Equals(this, obj);
}

实例 Equals 方法,这是个 Virtual 方法。

定义并使用操作符固然方便,不过除了像String之类的特殊情况,引用类型让 == 保持默认规则是更好的选择,而让 Equals 方法实现业务上的“值”相等。

如果不覆写,Equals 方法也是比较对象的引用。


对于值类型,实现==操作像一个点缀,

而如果想实现相等比较操作,应该优先重写Equals方法(同样若要实现大小比较,应该优先实现 IComparable 接口,而不是实现比较操作符),

从 Object 继承的 Equals 方法用于值类型时,比较两个对象的所有字段,全相等才为True。

为什么一定要优先重写它?

因为所有 .Net Framework 键值集合,都是用Equals实例方法做比较的,

所以它实际上成了.Net中的“潜规则”,无论是原生类型、结构或类的实例,都应以Equals方法作为其标准的相等比较方式,包括我们自己实现的类型。

用实例方法的好处也可以理解,更灵活,我们可以添加一些重载的Equals方法,申明不同的比较前提条件。

与重写的默认Equals方法配合,构成一套完整的比较规则,以符合现实复杂多变的标准。

.Net Framework 为较为复杂的比较提供了一个接口 System.Collections.IEqualityComparer,并提供了内置的实现,

如 StringComparer、EqualityComparer 我们自己写的比较类也可以实现这个接口。



总结:

==操作符、   只能比较基本类型,对于引用类型 == 和 ReferenceEquals 静态方法作用相同;结构体需要重载==比较符才能比较
Object.Equals方法、  使用对象实例的Equals方法,增加null判断
Object.ReferenceEquals方法、 比较两个对象引用地址是否一致,判断是否是同一个对象。 值类型返回false
对象实例的Equals方法。     比较两个对象引用是否一致,可以重载

String 被重载所以可以比较

java

“==”比较两个变量本身的值,即两个对象在内存中的首地址。

“equals()”比较字符串中所包含的内容是否相同。

equals()比较内容前提是对象重载了object的equals()方法,比如String类型,才能成功比较内容是否相同

 equal方法有以下五个性质:

  1. 自反性
  2. 对称性:不管谁调equal方法都不会影响结果
  3. 传递性
  4. 一致性:多次比较不会影响判断结果
  5. 任何非空对象与调用equal(null)均返回false

  java中需要选用合适的方法比较

  1. 对象域,使用equals方法 。
  2. 类型安全的枚举,使用equals或== 。
  3. 可能为null的对象域 : 使用 == 和 equals 。
  4. 数组域 : 使用 Arrays.equals 。
  5. 除float和double外的原始数据类型 : 使用 == 。
  6. float类型: 使用Float.floatToIntBits转换成int类型,然后使用==。
  7. double类型: 使用Double.doubleToLongBit转换成long类型,然后使用==。

  总的来说:类一般调用equal判断,当然首先需要对类进行判空,除了float和double之外的内置类型直接使用==进行内容比较,而float和double使用Float和Double的方法比较,也可以先生成Float或者Double对象调用equal方法,从前面Double的equal方法中可以看出,实质上还是调用了[float/double]To[Int/Long]Bit方法,建议直接使用该方法,避免不必要的开销。

从最新的JDK8而言,有三种实现对象比较的方法:

一、覆写Object类的equals()方法;

二、继承Comparable接口,并实现compareTo()方法;

三、定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法。

总结:

对于float和double的比较使用BigDecimal的compareTo方法

如果需要保证精度,最好是不要使用BigDecimal的double参数的构造函数,因为存在损失double参数精度的可能,最好是使用BigDecimal的String参数的构造函数。最好是杜绝使用BigDecimal的double参数的构造函数。

 参考文献:

https://www.cnblogs.com/Aaxuan/p/9520883.html

https://www.cnblogs.com/blueSkyline/p/5655620.html

https://www.jb51.net/article/125173.htm

https://blog.csdn.net/asdfsadfasdfsa/article/details/79332012

https://www.cnblogs.com/softidea/p/4364290.html

猜你喜欢

转载自blog.csdn.net/qq_25744257/article/details/84939309