【发布时间】:2023-03-21 09:03:01
【问题描述】:
OOP (Object Oriented Programming) 中的身份和平等有什么区别?
【问题讨论】:
OOP (Object Oriented Programming) 中的身份和平等有什么区别?
【问题讨论】:
identity:一个变量持有 与另一个变量相同的实例。
平等:两个不同对象可以 可以互换使用。他们经常 具有相同的 id。
例如:
Integer a = new Integer(1);
Integer b = a;
a 与 b 相同。
在 Java 中,使用 == 测试身份。例如,if( a == b )。
Integer c = new Integer(1);
Integer d = new Integer(1);
c 与d 相等但不相同。
当然,两个相同的变量总是相等的。
【讨论】:
身份确定两个对象是否共享相同的内存地址。相等性确定两个对象是否包含相同的状态。
如果两个对象相同,那么它们也相等,但仅仅因为两个对象相等并不意味着它们共享相同的内存地址。
字符串有一个特殊情况,但这是题外话,您需要询问其他人它是如何工作的;-)
【讨论】:
同一性意味着它是同一个对象实例,而相等意味着您比较的对象是一个对象的不同实例,但恰好包含相同的数据。
插图(在 java 中)
Date a = new Date(123);
Date b = new Date(123);
System.out.println(a==b); //false
System.out.println(a.equals(b)); //true
所以 a 和 b 是不同的实例(内存中的不同分配),但在“数据”级别上它们是相等的。
【讨论】:
例如,
在 StackOverFlow 中:
身份:我是迈克尔,你是 sevugarajan,所以我们不一样。
平等:如果我们有相同的声誉 分数,我们在某些方面是平等的。
【讨论】:
在“泄露”对象引用抽象的 Java 和类似语言中,您可以测试两个引用是否引用同一个对象。如果它们引用相同的对象,则引用是相同的。在 Java 中,这是 == 运算符。
还有一个equals 方法用于测试两个对象是否具有相同的值,例如用作HashSet 的键时(相等对象的哈希码也应该相等)。客户端代码使用时,相等的对象应该具有相同的“值”和语义。
更纯粹的面向对象语言没有身份比较,因为客户端代码通常不关心两个对象是否具有相同的内存地址。如果对象代表同一个现实世界的实体,那么最好使用一些 ID 或键值而不是身份进行建模,然后成为 equals 合约的一部分。不依赖对象的内存地址来表示真实世界的身份简化了缓存和分布式行为,并且抑制 == 将消除字符串比较中的许多错误或 Java 中原语装箱的一些使用。
【讨论】:
想想“相同”和“等效”这两个词。如果两个事物相同,则它们具有相同的身份;他们是同一件事。如果它们是等价的,则可以在不影响结果的情况下替换另一个;它们具有相同的行为和属性。
【讨论】:
身份:对同一个对象的两个引用 (o1 == o2)。
平等:方法o1.equals( o2 )返回true。这并不一定意味着这两个对象包含(全部)相同的数据。
理论上,即使对于相同的对象,也可以覆盖方法 equals() 以返回 false。但这会破坏Object.equals() 的规范:
equals 方法在非空对象引用上实现等价关系:
- 它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true。
- 它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。
- 它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true .
- 这是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。李>
- 对于任何非空引用值 x,x.equals(null) 应返回 false。
【讨论】:
身份概念非常具有哲学意义,这就是为什么您不应该将其仅还原为引用。
如果对第一个的更改反映在第二个上,则可以说两个身份相同,反之亦然。当然,这也包括共享相同的内存地址,但一般而言,虽然身份与对象的属性相关,但相等性用于检查两个对象是否相同,但这不包括身份。
反之亦然,如果两个项目具有相同的身份,它们也是相等的(在可互换的平等方面)。
【讨论】:
For primitive types ( int , boolean , char, long , float ... )
== 和 != 是相等测试
and for Objects
== 和 != 是身份测试。 [它只比较参考]
equals 方法用于对象的相等性测试[可以覆盖它来比较特定属性]
我找到了一篇关于此的优秀文章 http://www.cs.cornell.edu/courses/cs211/2006sp/Lectures/L14-Comparison/L14cs211sp06.pdf
引用
我喜欢猪。狗仰望我们。猫看不起我们。猪对我们一视同仁。 :DSir Winston Churchill
【讨论】:
x == y 仅当变量x 和y 引用相同的对象时才为真。
x.equals(y) 依赖于x.equals() 的实现,通常没有上述那么严格,因为它比较对象的内容。 (在Java中,如果x.equals(y),那么x.hashCode() == y.hashCode();也一定是真的)
例子:
Integer w = new Integer(3);
Integer x = new Integer(1);
Integer y = x;
Integer z = new Integer(1);
// all of these evaluate to true
y.equals(x) // it's the same object, of course the content is same
x.equals(z) // different objects, same content (`1`)
z.equals(y)
!w.equals(x); // the content is different (`3` vs `1`)
!w.equals(y);
!w.equals(z);
x == y // same object
z != x // different objects
y != z
w != x
【讨论】:
相同与相等的对象
如果表示两个对象状态的图在各个方面(包括每个级别的 OID)都相同,则称两个对象具有相同的状态(深度相等)。
如果表示它们状态的图相同,包括所有对应的原子值,则称两个对象具有相同的状态(浅相等)。但是,两个图中的一些对应的内部节点可能具有具有不同 OID 的对象。 示例:此示例说明了比较对象的两种定义之间的区别 平等的国家。
o2 = (i 2 , tuple, <a 1 :i 5 , a 2 :i 6 >)
o3 = (i 3 , tuple, <a 1 :i 4 , a 2 :i 6 >)
o4 = (i 4 , atom, 10)
o5 = (i 5 , atom, 10)
o6 = (i 6 , atom, 20)
在此示例中,对象 o1 和 o2 具有相等的状态(浅相等),因为它们在原子级别上的状态相同,但值是通过不同的对象 o 4 和 o 5 达到的。
但是,对象 o1 和 o3 具有相同的状态(深度相等),尽管对象本身并不是因为它们具有不同的 OID。类似地,虽然 o4 和 o5 的状态相同,但实际的对象 o4 和 o5 是相等的,但并不完全相同,因为它们具有不同的 OID。
【讨论】:
补充一点,identity 也称为 referential 校验(对对象的引用,明白了吗?)和 equality 被一些作者称为 structural 校验。归根结底,内存抽象中的对象只是在某个内存地址索引的映射/表结构。可以有一个或多个指向它的引用(内存地址)。它们都在引用上完全相同。当同一个对象的内容被复制到另一个对应对象时,那么两者在结构上是相等的。
【讨论】: