Can I use Set collection to eliminate duplicate by two different equals? - java

I have a project in Java. First I need to create a collection with no duplicates in the name of object & its number, so I use the Set collection and this equals method:
public boolean equals(Object obj) {
Course<?> c=(Course<?>)obj;
return (c.number==number&& c.Name.equals(Name));
}
next ..i need to create collection of the same object but now i need to insure that only his name is not duplicate. so its a problem because i cant use two diffrents methods of equals
what can i do??

I'd use a TreeSet instead and specifying the comparator to use for that specific set instead of overriding equals.
https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html#TreeSet-java.util.Comparator-
If you don't want them actually sorted, but just remove dupes, the comparator just has to return 0 when they are equal.
TreeSet<Course> tree1 = new TreeSet<Course>((c1, c2) -> c1.number==c2.number && c1.Name.equals(c2.Name) ? 0 : 1);
and
TreeSet<Course> tree2 = new TreeSet<Course>((c1, c2) -> c1.Name.equals(c2.Name) ? 0 : 1);

You can wrap your class in a wrapper class that will implement the hashcode and equals functions the way you want:
public NameWrapper {
private Course c;
public NameWrapper(Course c) {
this.c = c;
}
public void equals(Object other) {
// ...
return this.name.equals(other.name);
}
// + hashCode
// + getter
}
// Similarly with number and name wrapper
And then you can wrap, distinct and unwrap your elements:
Collection<Course> courses = // ...
Collection<Course> distincts =
courses.stream()
.map(NameWrapper::new) // wrap
.distinct()
.map(NameWrapper::getCourse) // unwrap
.map(NumberNameWrapper::new) // wrap
.distinct()
.map(NumberNameWrapper::getCourse) // unwrap
.collect(Collectors.toList())

One easy, but probably not really great solution would be to use two specific wrapper classes that each have different equals methods.
And instead of directly using your own class, you put objects of those "wrapper" classes into those collections.
Like:
class Course { ... your class
class CourseWrapperForName {
Course wrappedCourse;
...
Course getWrappedCourse() { return wrappedCourse; }
#Override
public boolean equals(Object other) {
... compares names
class CourseWrapperForNumber {
Course wrappedCourse;
...
#Override
public boolean equals(Object other) {
... compares numbers
Now, eliminating duplicates can be done by putting your Course objects into the corresponding wrapper; adding wrappers to Sets; and then retrieving the course.
But obviously, that is a lot of boilerplate; and more reasonable solutions could be
A) using a TreeSet with a different
B) the later can be enhanced with a lot of black lambda magic; there is a nice presentation how to do that (it is in German, but mainly code; the interesting part starts at page 40).

I would take the Set<Course> with this equals method implemented (that will give me the course which are unique in name & number both).
Further, I would make a subclass of Course 'SubCourse' and override the equals method:
class SubCourse extends Course{
public boolean equals(Object o){
if(o instanceof SubCourse){
return (this.Name.equals(((SubCourse)o).Name));
}else{
return false;
}
}
}
And then make a Set<SubCourse> that will give you a unique courses in terms of numbers (not in name as we excluded that condition). You need to make the instance variables of Course as protected.

Related

What is a good design pattern for tracking issues in a class?

I have a class that has a custom equals() method. When I compare two objects using this equals method, not only am I interested in whether or not they are equal, but if they are not equal, what was different about them. Finally, I want to be able to retrieve the differences arising from an unequal situation.
I currently use logging to display where my objects are unequal. This works, but I have a new requirement of being able to extract the actual results of the equals check for display later. I suspect there is an object-oriented design pattern for handling this type of situation.
public class MyClass {
int x;
public boolean equals(Object obj) {
// make sure obj is instance of MyClass
MyClass that = (MyClass)obj;
if(this.x != that.x) {
// issue that I would like to store and reference later, after I call equals
System.out.println("this.x = " + this.x);
System.out.println("that.x = " + that.x);
return false;
} else {
// assume equality
return true
}
}
}
Are there any good design pattern suggestions where some sort of work is being done, but a secondary object collects information about how well that work was done which can later be retrieved and displayed?
Your problem is that you are trying to use the boolean equals(Object) API for something it was not designed for. I don't think there is any design pattern that will allow you to do this.
Instead, you should be doing something like this:
public class Difference {
private Object thisObject;
private Object otherObject;
String difference;
...
}
public interface Differenceable {
/** Report the differences between 'this' and 'other'. ... **/
public List<Difference> differences(Object other);
}
Then implement this for all classes where you want "differenceable" functionality. For example:
public class MyClass implements Differenceable {
int x;
...
public List<Difference> differences(Object obj) {
List<Difference> diffs = new ArrayList<>();
if (!(obj instanceof MyClass)) {
diffs.add(new Difference<>(this, obj, "types differ");
} else {
MyClass other = (MyClass) obj;
if (this.x != other.x) {
diffs.add(new Difference<>(this, obj, "field 'x' differs");
}
// If fields of 'this' are themselves differenceable, you could
// recurse and then merge the result lists into 'diffs'.
}
return diffs;
}
}
I am unaware of a particular design pattern for this. One problem with this requirement is that to find out all differences between two unequal objects you would need to continue additional comparisons after the first false result (which is typically not necessary).
If I were doing this I might consider doing a normal equality test and if not equal, kick off a thread to determine why and log the results rather than incorporate such logic in the equals method itself. This might be done in a special method outside of the equals method.

How to remove duplicates from an ArrayLlist of ArrayLists that are composed of custom objects

I have a recursive function that generates a list of lists that keeps tracks of valid hand combinations for a card game:
List<List<HandComponent>> validSCompArrangements = new ArrayList<>();
This list is populated by the recursive function successfully but often has duplicate sub-lists (by content but not by not order) that are unavoidable due to the required nature of the function. I wish to remove these duplicate sub-list entries (List<\HandComponent>) so that the above list in the end only features sub-lists that are unique in content, as order does not matter.
Here is the important part of the HandComponent class:
public class HandComponent {
private Type mType;
private Card mCard; // For runs this is the middle card
private Source mSource;
public HandComponent(Type type, Card card, Source source)
{
init(type, card, source);
}
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
...
}
A sub-list List should only be considered equal to another sub-list if it contains the same exact HandComponents (i.e. the Type, Card, and Source between components of each list must be the same). Card is another enum defined in another file.
So, if two lists in "validSCompArrangements" are
(PAIR,CARD1,STOLEN), (TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET)
and
(TRIPLE,CARD7,STOLEN), (RUN, CARD8, SECRET), (PAIR,CARD1, STOLEN)
they should be considered the same since they ultimately contain the same HandComponents even though the order is different and one should be removed so that "validSCompArrangements" only contains that unique list once.
Looking into this I've found bits and pieces on how to solve this problem but nothing that features this combination of a list of lists with custom objects.
One method seems to be to implement a custom Comparator that compares HandComponent instances to use with Collections in order to sort the sub-lists and then another custom Comparator to compare these sorted sub-lists for duplicates, though that seems a tad clunky and I'm not entirely sure how to override the compare method and what kind of return it expects for each comparator I'd need to make. The only other thing I've seen gestured at is that since for my usage the order of both the sub-lists and the main "validSCompArrangements" list itself don't matter, that I should be using Sets and a HashSet to solve this problem instead, I have no idea how to use those to fix this issue, other than that I might need to override the hashCode and equals methods for my HandComponent class, again, not being sure how to do so.
Overall I'm just a bit confused since any example I can manage to find thats remotely related to this usually is talking about just one list of custom objects that contain primatives and not enums, or a list of lists that uses only primatives and no custom objects at all. The fact this is a list of lists of custom objects who's members are enums has me a tad lost on how to go about this.
For example the marked answer in this question: Using collection to remove duplicate Lists, that only handles a portion of my problem, doesn't even seem to work for me despite the OP saying it does. Running that code as is, other than changing
Set<Integer> dedupedCollection = new HashSet<Integer>();
to
Set<List<Integer>> dedupedCollection = new HashSet<>();
as it was clearly meant to be, produces a collection of 3 entries where the second entry of 5, 10, 5 isn't seen as a duplicate and ignored as the OP suggested it should.
EDIT:
So far the closest thing I've found is converting my top-level list to a HashSet using:
Set<List<HandComponent>> handSet = new HashSet<>(validSCompArrangments);
but this only eliminates duplicate lists if their order is the same (which I am guessing is due to the nature of List's default implementation of "equals()"), while I need it to consider lists that are the same in content but different in order as duplicates also. One way around this would be to use Sets for the HandComponent sub-lists as well since they don't care about order innately, but this would prevent those sets from having duplicate HandComponents which I do need to be allowed.
As you said, you just need to implement equals :)
I've provided you how to implement equals method in the HandComponent class and how to use HashSet to getting only the combinations without duplicates.
I've implemented it in Java 8, you can also try to change it using for loop if you want :)
Here is the equals implementation of `HandComponent
public class HandComponent {
public enum Type {PAIR, TRIPLE, QUAD, RUN}
public enum Source {STOLEN, SECRET, EITHER}
public enum Card {ACE, ONE, TWO, TRHEE}
private Type type;
private Card card;
private Source source;
public HandComponent(Type type, Card card, Source source) {
this.type = type;
this.card = card;
this.source = source;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof HandComponent)) {
return false;
}
HandComponent handComponent = (HandComponent) o;
if (type != handComponent.type) {
return false;
}
if (card != handComponent.card) {
return false;
}
if (source != handComponent.source) {
return false;
}
return true;
}
#Override
public String toString() {
return "HandComponent=[" + String.join(", ", Arrays.asList(type.toString(), card.toString(), source.toString())) + "]";
}
}
And below you can see how you can use it
public class Main {
public static void main(String[] args) {
// Creating 2 hand components
HandComponent handComponent1 = new HandComponent(HandComponent.Type.PAIR, HandComponent.Card.ACE, HandComponent.Source.STOLEN);
HandComponent handComponent2 = new HandComponent(HandComponent.Type.QUAD, HandComponent.Card.TRHEE, HandComponent.Source.EITHER);
// 2 combinations with the same card, but different order => they are the same
List<HandComponent> firstCombination = Arrays.asList(handComponent1, handComponent2);
List<HandComponent> secondCombination = Arrays.asList(handComponent2, handComponent1);
// Mixing 2 combinations together
List<List<HandComponent>> combinations = Arrays.asList(firstCombination, secondCombination);
// printing the mix
System.out.println("Before: " + combinations);
// removing duplicates
List<ArrayList<HandComponent>> collect = combinations.stream() // having a stream of list<HandComponent>
.map(HashSet::new) // converting to HashSet, which mean there won't be duplicate in the combinations.
.distinct() // getting only the distinct combinations
.map(ArrayList::new) // reconverting to array list
.collect(Collectors.toList()); // collecting them as list
// result without duplicates
System.out.println("After: " + collect);
// You can now implement it with loop and no java 8 :)
}
}
What ended up working best for me was to implement the "equals()" method for my HandComponent class as suggested by Jiajie Xu, along with the "hashCode()" method automatically generated by Android Studio by using the option in the context menu or Alt + Insert:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HandComponent that = (HandComponent) o;
return mType == that.mType &&
mCard == that.mCard &&
mSource == that.mSource;
}
#Override
public int hashCode() {
return Objects.hash(mType, mCard, mSource);
}
I then also made the class implement the Comparable interface for use with the Collections class and specified the sort order priority of HandComponent instances within the "compareTo()" method like so:
#Override
public int compareTo(#NonNull HandComponent other) {
// Check Type first
int compareResult = mType.compareTo(other.mType);
if(compareResult == 0)
{
// Check Card second
compareResult = mCard.compareTo(other.mCard);
if(compareResult == 0)
{
// Check Source last
compareResult = mSource.compareTo(other.mSource);
}
}
return compareResult;
}
Since the default implementation of Comparable for List requires list order to be the same in order to return "true" when comparing two lists, I needed to sort my List of Lists every time I wanted to remove duplicates, which was perfectly fine as I benefited from the organization later on.
Ultimately, this allowed me remove the duplicates from my List of Lists of custom objects by first making sure the sub-lists of HandComponent were all sorted and then creating a HashSet of the top-level list.
List<List<HandComponent>> unsortedList = new ArrayList<>();
... // Populate list
for(int i = 0; i < unsortedList.size(); i++)
{
Collections.sort(unsortedList.get(i));
}
Set<List<HandComponent>> sortedDeDupedSet = new HashSet<>(unsortedList);
// Convert back to list since I need order to matter again later on
List<List<HandComponenet>> sortedDeDupedList = new ArrayList<>(sortedDeDupedSet);
This correctly removes duplicates from the top-level list now that I have properly implemented the "equals()" and "hashCode()" methods, as well as sorted the lists before hand with "compareTo()" by leveraging List's default Comparable implementation. Having to use a for loop to sort the lists themselves since I'm restricted to Java 7 does feel a little bad, but like I said before ultimately it was useful to have the lists sorted for other purposes and a lot of time and code is still saved from using a HashSet, versus the nested for loops that would be required to compare each List entry manually.

How do I compare two lists?

CompareList removedList = new CompareList();
CompareList addedList = new CompareList();
This is how I'm adding elements inside
addedList.add(new Objec("Var_a", "1"));
and class Objec has two strings.
How can I compare that? I can't use contains like I could with ArrayList of Strings?
In CompareList I have
public boolean equals(CompareList l) {
if (l.containsAll(this)) {
if (this.containsAll(l)) {
return true;
}
}
return false;
}
and in Objec
public Objec(String n, String s) {
this.name=n;
this.surname=s;
}
public String toString() {
return " Name: " + name + ", Surname: " + surname;
}
I see that many people are confused with my question. So what I want?
List 1:
Samy Joe
Emma Than
Julia Rob
List 2:
Samy Joe
Emma Than
Anna Sky
Removed Julia Rob and added Anna Sky. But I don't know how to do it when my lists contains of object that have two strings?
This piece of code compares if the lists are equal, that is, contains the same elements.
static boolean same(Collection<?> a, Collection<?> b) {
if (a.size() != b.size()) {
return false;
}
List<?> c = new ArrayList<>(a);
c.removeAll(b);
return c.isEmpty();
}
If the sizes are not equal, then the lists are never equal.
Else, if the sizes are equal, then we know that both lists contain one or more elements that are not present in the other list. So we make a new list from one of the lists (list a in my case), and then we remove the elements of b.
You don't need to use your own class CompareList, instead you could just use an ArrayList or something.
In order to compare your Objec to another one, you'll need to implement equals(Object) and hashCode() correctly.
If you want to know which elements are not contained in the other list, then you can use this:
static HashMap<Collection<?>, Collection<?>> disjoints(Collection<?> a, Collection<?> b) {
List<?> aa = new ArrayList<>(a);
aa.removeAll(b);
List<?> bb = new ArrayList<>(b);
bb.removeAll(a);
HashMap<Collection<?>, Collection<?>> map = new HashMap<>();
map.put(a, aa);
map.put(b, bb);
return map;
}
It returns a map with as keys the two collections and as values the elements of the collection specified by the key, which are not contained in the other collection. For example, if you want to know the elements of a not present in b, then call disjoints(a, b).get(a).
Note: I call the lists collections, because they are. In Java, a List is a subtype of Collection.
You need to override the equals method in your custom object like this:
public class MyObject {
private String name;
private String surname;
#Override
public boolean equals(MyObject myObject) {
// assert that name and surename can not be null or check for this
if (!this.name.equals(myObject.name)) {
return false;
}
if (!this.surname.equals(myObject.surname)) {
return false;
}
return true;
}
}
The contains-Method of a list will be use the equals method to check the equality of your objects.
But the link that #Prakash has posted is the better way do do that. I think no one understand what your attention is to do with yout CompareList and why you use a custom one ;)
EDIT:
Sorry, had mistake in the Signature.
#Override
public boolean equals(Object obj) {
if (!(obj instanceof MyObject) {
return false;
}
// else cast and use code above
}
You're question: "How can I compare that?"
The first thing to keep in mind is that you can compare in 2 ways.
so think about that first.
Equality:
When comparing for equality
use equals() and while you're at it implement hashCode().
Comparing / sorting:
When are 2 objects considered lower then, same, or higher then the other?
implement "Comparable" interface and override compareTo.
You're post contains the equals() so lets say that is what you want to do.
If you want to use containsAll(), keep in mind that it uses equals from the class the list contains to figure out to return true/false. So you should probably:
add equals() to your "Objec" class.

Java List.contains(Object with field value equal to x)

I want to check whether a List contains an object that has a field with a certain value. Now, I could use a loop to go through and check, but I was curious if there was anything more code efficient.
Something like;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
I know the above code doesn't do anything, it's just to demonstrate roughly what I am trying to achieve.
Also, just to clarify, the reason I don't want to use a simple loop is because this code will currently go inside a loop that is inside a loop which is inside a loop. For readability I don't want to keep adding loops to these loops. So I wondered if there were any simple(ish) alternatives.
Streams
If you are using Java 8, perhaps you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
Or alternatively, you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
This method will return true if the List<MyObject> contains a MyObject with the name name. If you want to perform an operation on each of the MyObjects that getName().equals(name), then you could try something like this:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Where o represents a MyObject instance.
Alternatively, as the comments suggest (Thanks MK10), you could use the Stream#anyMatch method:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> name.equals(o.getName()));
}
You have two choices.
1. The first choice, which is preferable, is to override the `equals()` method in your Object class.
Let's say, for example, you have this Object class:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Now let's say you only care about the MyObject's name, that it should be unique so if two `MyObject`s have the same name they should be considered equal. In that case, you would want to override the `equals()` method (and also the `hashcode()` method) so that it compares the names to determine equality.
Once you've done this, you can check to see if a Collection contains a MyObject with the name "foo" by like so:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
However, this might not be an option for you if:
You are using both the name and location to check for equality, but you only want to check if a Collection has any `MyObject`s with a certain location. In this case, you've already overridden `equals()`.
`MyObject` is part of an API that you don't have liberty to change.
If either of these are the case, you'll want option 2:
2. Write your own utility method:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Alternatively, you could extend ArrayList (or some other collection) and then add your own method to it:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Unfortunately there's not a better way around it.
This is how to do it using Java 8+ :
boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());
Google Guava
If you're using Guava, you can take a functional approach and do the following
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
which looks a little verbose. However the predicate is an object and you can provide different variants for different searches. Note how the library itself separates the iteration of the collection and the function you wish to apply. You don't have to override equals() for a particular behaviour.
As noted below, the java.util.Stream framework built into Java 8 and later provides something similar.
Collection.contains() is implemented by calling equals() on each object until one returns true.
So one way to implement this is to override equals() but of course, you can only have one equals.
Frameworks like Guava therefore use predicates for this. With Iterables.find(list, predicate), you can search for arbitrary fields by putting the test into the predicate.
Other languages built on top of the VM have this built in. In Groovy, for example, you simply write:
def result = list.find{ it.name == 'John' }
Java 8 made all our lives easier, too:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
If you care about things like this, I suggest the book "Beyond Java". It contains many examples for the numerous shortcomings of Java and how other languages do better.
Binary Search
You can use Collections.binarySearch to search an element in your list (assuming the list is sorted):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
which will return a negative number if the object is not present in the collection or else it will return the index of the object. With this you can search for objects with different searching strategies.
Map
You could create a Hashmap<String, Object> using one of the values as a key, and then seeing if yourHashMap.keySet().contains(yourValue) returns true.
Eclipse Collections
If you're using Eclipse Collections, you can use the anySatisfy() method. Either adapt your List in a ListAdapter or change your List into a ListIterable if possible.
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
If you'll do operations like this frequently, it's better to extract a method which answers whether the type has the attribute.
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
You can use the alternate form anySatisfyWith() together with a method reference.
boolean result = list.anySatisfyWith(MyObject::named, "John");
If you cannot change your List into a ListIterable, here's how you'd use ListAdapter.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Note: I am a committer for Eclipse ollections.
Predicate
If you dont use Java 8, or library which gives you more functionality for dealing with collections, you could implement something which can be more reusable than your solution.
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
i'm using something like that, i have predicate interface, and i'm passing it implementation to my util class.
What is advantage of doing this in my way? you have one method which deals with searching in any type collection. and you dont have to create separate methods if you want to search by different field. alll what you need to do is provide different predicate which can be destroyed as soon as it no longer usefull/
if you want to use it, all what you need to do is call method and define tyour predicate
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});
Here is a solution using Guava
private boolean checkUserListContainName(List<User> userList, final String targetName){
return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
#Override
public boolean apply(#Nullable User input) {
return input.getName().equals(targetName);
}
});
}
contains method uses equals internally. So you need to override the equals method for your class as per your need.
Btw this does not look syntatically correct:
new Object().setName("John")
If you need to perform this List.contains(Object with field value equal to x) repeatedly, a simple and efficient workaround would be:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Then the List.contains(Object with field value equal to x) would be have the same result as fieldOfInterestValues.contains(x);
Despite JAVA 8 SDK there is a lot of collection tools libraries can help you to work with, for instance:
http://commons.apache.org/proper/commons-collections/
Predicate condition = new Predicate() {
boolean evaluate(Object obj) {
return ((Sample)obj).myField.equals("myVal");
}
};
List result = CollectionUtils.select( list, condition );

java prevent class from overriding equals

I want to use java.util.Set (and other collections) but with a twist: I want contains() , add(), etc. to call Object's equals() at all times (that is operate based on identity rather than equality more generally). I think I have a way, but it has big drawbacks. Is there a proper way to do this? Sorry if I'm missing something obvious.
Here's what I've done:
public class OnlySelfEqual {
public final boolean equals(Object o){
return super.equals(o);
}
}
public class Example{
private Set<T extends OnlySelfEqual> set;
//etc
}
The main problem I see with this (there may be numerous others) is that all Ts have to extend from a class rather than implement an interface, which is pretty restrictive. I think what I want would be something like a 'reverse' interface which lists methods that subtypes cannot implement (override). I'm pretty sure that doesn't exist though. Any suggestions?
java.util.IdentityHashMap is a Map implementation that deliberately violates the Map contract by using == rather than equals(), so you could get a Set with the same behaviour using e.g.
Set<String> set = Collections.newSetFromMap(new IdentityHashMap<String, Boolean>());
You could wrap your objects inside a container which will implement equals() using the wrapped objects' identity:
public class Wrapper<T> {
// Either public (it's final), or private with a getter
public final T element;
public Wrapper(T element) {
this.element = element;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o == null || o.getClass() != getClass()) {
return false;
}
return element == ((Wrapper<?>) o).element;
}
public int hashCode() {
return System.identityHashCode(element);
}
}
You then use Set<Wrapper<T>>, List<Wrapper<T>>, etc.
If you use Guava (which contains a lot of useful stuff complementing the JDK), you can directly use its Equivalence class (and Equivalence.Wrapper) to get that result, or other ones based on different strategies.
If I recall correctly, what you're looking for is:
T t = ...
((Object)t).equals( other );
I might be mistaken as to the syntax..

Categories

Resources