While your question is one that many beginners have (including myself), I believe that your concern is not justified in this case. The features you are asking for are already built into the Java language at the specification level.
First of all, let's look at Object.equals()
. On the one hand, the Language Specification states that
The method equals defines a notion of object equality, which is based on value, not reference, comparison.
However, the documentation for Object.equals()
clearly states that
The equals
method for class Object
implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x
and y
, this method returns true
if and only if x
and y
refer to the same object (x == y
has the value true
).
This means that you can safely redirect OtherClass.remove
to ArrayList.remove()
. Whatever Object.equals
is comparing works exactly like a unique ID. In fact, in many (but not all) implementations, it compares the memory addresses to the objects, which are a form of unique ID.
Quite understandably, you do not wish to use linear iteration every time. As it happens, the machinery of Object
is perfectly suited for use with something like a HashSet, which, by the way is the solution I recommend you use in this case.
If you are not dealing with some huge data set, we do not need to discuss the optimization of Object.hashCode()
. You just need to know that it will implement whatever contract is necessary to work correctly with Object.equals
to make HashSet.remove
work correctly.
The spec itself only states that
The method hashCode
is very useful, together with the method equals
, in hashtables such as java.util.Hashmap
.
This does not really say much, so we turn to the API reference. The two relevant point are:
- If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
- It is not required that if two objects are unequal according to the
equals
(java.lang.Object
) method, then calling the hashCode
method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
Simply put, the hashCode
of equal objects must be the same, but an equal hashCode
does not necessarily mean equal objects. Object
implements this contract, so you can use it with a HashSet
, which is backed by a HashMap
.
The one piece of information that is missing to make this a formal argument in favor of not doing any additional work, is why I keep citing the API reference as if it was the language specification. As it happens:
As noted above, this specification often refers to classes of the Java SE platform API. In particular, some classes have a special relationship with the Java programming language. Examples include classes such as Object
, Class
, ClassLoader
, String
, Thread
, and the classes and interfaces in package java.lang.reflect
, among others. This specification constrains the behavior of such classes and interfaces, but does not provide a complete specification for them. The reader is referred to the Java SE platform API documentation.
[emphasis mine], but you get the idea. The Java SE API reference is the language spec as far as the behavior of the methods of Object
is concerned.
As an aside, you will probably want to stay away from something like TreeSet
, because that will require you to add a bunch of machinery to your implementation. As a minimum, MyClass
instances will have to be orderable, either by implementing Comparable
, or by assigning a custom Comparator
to the Set
.
TL;DR
The language specification states that you have at least the following two options available to you with no additional effort on your part:
- Make
myClsList
an ArrayList
and use the appropriate add()
/remove()
methods as you see fit.
- Make
myClsList
a HashSet
and use the appropriate add()
/remove()
methods.
I recommend the second option. In fact, instead of containment, you may consider extending HashSet
so you don't have to bother implementing your own add
/remove
methods.
Final Note
All this works as long as MyClass
overrides neither Object.equals
nor Object.hashCode
. The moment you do that, you put the burden of satisfying contractual requirements entirely on yourself.