找到一个特定的实例,最好的方法是什么

时间:2017-08-20 00:47:56

标签: java filter

想象一下,我有两个类的实例:

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);
  1. 我是否可以迭代它们并测试相等性,我的意思是理论上这应该可行,因为这两个实例有不同的“内部指针”?

  2. 我想使用基于HashMap的方法会更有效率,但我可以将其用作关键点(假设我无法添加唯一的实例ID或其他内容)。

  3. 编辑:对于我想知道的内容存在一些疑惑。 这里的关键是我想知道是否有任何方法可以从c的ArrayList或我可能使用的任何聚合器对象中删除该特定实例,只需提供相应的对象引用即可。 我想这可以通过保持ArrayList和测试相等来完成(虽然我不是100%肯定)但如果没有遍历整个列表可能会更清晰。 我想知道Java中是否有类似的东西。 (我知道如何通过使用其他信息来解决它,但线索是只有相应的对象引用用于过滤/检索目的。

2 个答案:

答案 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}}方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值Objectx,当且仅当ytrue引用同一对象时,此方法才会返回xy的值为x == y)。

这意味着您可以安全地将true重定向到ArrayList.remove()。无论OtherClass.remove进行比较,其工作方式与唯一ID完全相同。事实上,在许多(但不是全部)实现中,它将内存地址与对象进行比较,这些对象是唯一ID的形式。

可以理解的是,您不希望每次都使用线性迭代。碰巧的是,Object.equals的机制非常适合与HashSet这样的东西一起使用,顺便说一下,我推荐你在这种情况下使用它。

如果您没有处理大量数据集,我们不需要讨论Object.hashCode()的优化问题。您只需要知道它将实现与Object一起正常工作所需的任何合同,以使HashSet.remove正常工作。

spec itself仅表明

  

方法Object.equals与方法hashCodeequals等哈希表中非常有用。

这并没有多说,所以我们转向API参考。两个相关点是:

  
      
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  •   
  • 如果两个对象根据java.util.Hashmapequals)方法不相等,则不需要在两个对象中的每一个上调用java.lang.Object方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
  •   

简单地说,相等对象的hashCode必须相同,但相等hashCode并不一定意味着相等的对象。 hashCode实施此合约,因此您可以将其与Object一起使用,该HashSetHashMap支持。

缺少一条信息,使其成为支持不做任何额外工作的正式论据,这就是为什么我一直引用API参考,就好像它是语言规范一样。正如happens

  

如上所述,此规范通常是指Java SE平台API的类。特别是,某些类与Java编程语言有特殊的关系。示例包括 Object ClassClassLoaderStringThread等类以及包{中的类和接口{1}}等等。 此规范约束此类和接口的行为,但不提供完整的规范。读者可以参考Java SE平台API文档。

[强调我的],但你明白了。就java.lang.reflect方法的行为而言,Java SE API参考语言规范。

顺便说一句,你可能希望远离像TreeSet这样的东西,因为要求你为你的实现添加一堆机器。至少,Object个实例必须通过实施Comparable或向MyClass分配自定义Comparator来进行订购。

<强> TL; DR

语言规范声明您至少可以使用以下两个选项,而无需您付出额外的努力:

  1. Set设为ArrayList,并根据需要使用相应的add() / remove()方法。
  2. myClsList成为HashSet并使用相应的add() / remove()方法。
  3. 我推荐第二个选项。事实上,您可以考虑延长myClsList而不是遏制,这样您就不必费心实施自己的HashSet / add方法了。

    最后的注释

    只要remove覆盖 MyClassObject.equals,所有这一切都有效。你这样做的那一刻,你把满足合同要求的负担完全放在你自己身上。