想象一下,我有两个类的实例:
public class MyClass {
public void sayHello() {
System.out.println("Hello");
}
}
a = new MyClass();
b = new MyClass();
现在我将这些添加到另一个对象,例如:
public class OtherClass {
private ArrayList<MyClass> myClsList = new ArrayList<>();
public void add(MyClass obj) {
myClsList.add(obj);
}
public void remove(MyClass obj) {
// ????
}
}
c = new OtherClass();
c.add(a);
c.add(b);
现在我想删除一个特定的实例,例如
c.remove(a);
我是否可以迭代它们并测试相等性,我的意思是理论上这应该可行,因为这两个实例有不同的“内部指针”?
我想使用基于HashMap的方法会更有效率,但我可以将其用作关键点(假设我无法添加唯一的实例ID或其他内容)。
答案 0 :(得分:2)
根据Java doc,
,您可以使用a.toString()
Object类的toString方法返回一个由。组成的字符串 对象是实例的类的名称,at-sign 字符`@&#39;,以及散列的无符号十六进制表示 对象的代码。
这应该为您的类实例提供唯一标识符,因此您可以将其用作哈希键,而无需存储/创建任何额外标识符。
注意:请注意这种做法,不要依赖于`Object.toString()返回的值,因为它与实际的对象相关,请参阅详细解释here。
答案 1 :(得分:1)
虽然你的问题是许多初学者(包括我自己)的问题,但我认为在这种情况下你的担忧是不合理的。您要求的功能已经在规范级别内置于Java语言中。
首先,让我们看一下Object.equals()
。一方面,Language Specification表示
方法equals定义了一个对象相等的概念,它基于值,而不是引用,比较。
但是,Object.equals()
的文档明确指出
类
equals
的{{1}}方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值Object
和x
,当且仅当y
和true
引用同一对象时,此方法才会返回x
(y
的值为x == y
)。
这意味着您可以安全地将true
重定向到ArrayList.remove()
。无论OtherClass.remove
进行比较,其工作方式与唯一ID完全相同。事实上,在许多(但不是全部)实现中,它将内存地址与对象进行比较,这些对象是唯一ID的形式。
可以理解的是,您不希望每次都使用线性迭代。碰巧的是,Object.equals
的机制非常适合与HashSet这样的东西一起使用,顺便说一下,我推荐你在这种情况下使用它。
如果您没有处理大量数据集,我们不需要讨论Object.hashCode()
的优化问题。您只需要知道它将实现与Object
一起正常工作所需的任何合同,以使HashSet.remove
正常工作。
spec itself仅表明
方法
Object.equals
与方法hashCode
在equals
等哈希表中非常有用。
这并没有多说,所以我们转向API参考。两个相关点是:
- 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
- 如果两个对象根据
java.util.Hashmap
(equals
)方法不相等,则不需要在两个对象中的每一个上调用java.lang.Object
方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
简单地说,相等对象的hashCode
必须相同,但相等hashCode
并不一定意味着相等的对象。 hashCode
实施此合约,因此您可以将其与Object
一起使用,该HashSet
由HashMap
支持。
缺少一条信息,使其成为支持不做任何额外工作的正式论据,这就是为什么我一直引用API参考,就好像它是语言规范一样。正如happens:
如上所述,此规范通常是指Java SE平台API的类。特别是,某些类与Java编程语言有特殊的关系。示例包括
Object
,Class
,ClassLoader
,String
,Thread
等类以及包{中的类和接口{1}}等等。 此规范约束此类和接口的行为,但不提供完整的规范。读者可以参考Java SE平台API文档。
[强调我的],但你明白了。就java.lang.reflect
方法的行为而言,Java SE API参考是语言规范。
顺便说一句,你可能希望远离像TreeSet
这样的东西,因为将要求你为你的实现添加一堆机器。至少,Object
个实例必须通过实施Comparable
或向MyClass
分配自定义Comparator
来进行订购。
<强> TL; DR 强>
语言规范声明您至少可以使用以下两个选项,而无需您付出额外的努力: