I have created a clone of the existing HashSet using clone() and then comparing their references like below:
HashSet<Employee> h = new HashSet<>();
HashSet<Employee> h1=(HashSet<Employee>) h.clone();
System.out.println(h==h1);
OUTPUT:
false
Shouldn't this be true since we are creating shallow copies?
HashSet overrides the clone() method of Object class
The general intent is that, for any object x, the expression:
x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be true, but these are not absolute requirements. While it is typically the case that:
x.clone().equals(x)
will be true, this is not an absolute requirement.
By convention, the object returned by this method should be independent of this object (which is being cloned).
In Java, == checks for references not objects so, h==h1 is false in your case.
In java == for objects check if the object its the exact same object.
And if you go and check the clone method:
public Object clone() {
try {
HashSet<E> newSet = (HashSet<E>) super.clone();
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
It easy to see it is creating a new object. So now you have TWO different objects that are shallowly equal
Related
I need help. I tried to remove an element from an ArrayList.
I have two lists. One list from a file, the second list from the database.
I need to find the same elements to later remove them from the original list, and thus have a list with differences.
List<BinInternacionalMarcaDEL> listDiff = new ArrayList<BinInternacionalMarcaDEL>();
ListOriginal= binInternacionalRepositoryDEL.findAllByBin();
public List<BinInternacionalMarcaDEL> Differences(List<BinInternacionalMarcaDEL> listA,
List<BinInternacionalMarcaDEL> listB) {
try {
for(BinInternacionalMarcaDEL elementA: listaA){
for(BinInternacionalMarcaDEL elementB: listaB) {
if(elementA.getNumRangoini().compareTo(elementB.getNumRangoini()) == 0 ){
listDiff.add(elementA);
}
}
}
ListOriginal.removeAll(listDiff);
} catch (Exception e) {
LOGGER.error(e.toString());
}
but this doesn't work.
just you can do one thing
listA.retainAll(listB);
here now listA contains only similar elements in both ListA and ListB.
Example:
List<String> listA = new ArrayList<>(Arrays.asList("12","13","15","2","5")) ;
List<String> listB = new ArrayList<> (Arrays.asList("2","12","48","49","55"));
listA .retainAll(listB );
System.out.println(listA ); //[12, 2]
Java list remove and contains methods are implemented using equality of objects. This logic is implemented in hashCode and equal method in your class and all classes in Java inherit this attribute from the Object class.(to be honest ArrayList doesn't use hashCode in implementing remove and contains metheds but in java contract you should implement these two methods together). here when you are adding element to listDiff you are defining your own equality which is based on equality of attribute numRangoini(using compateTo method) and when you request the list class to remove them from list(with removeAll method). removeAll remove them based on the equality of that two object. Since you haven't defined this logic in your own class.
this behaviour is inherited from object class which is based on strict equality. by default two object are equal if they reference the same object.
Solution: define the logic for equality in your own class in equal method. This method should return true if two object has the same attribute value numRangoini. don't forget to define hashCode as well. and here is the rule if two objects are equal they should return the same hashCode.
here is a simple implementation
#Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null || obj.getClass()!= this.getClass())
return false;
BinInternacionalMarcaDEL binInternacionalMarcaDEL = (BinInternacionalMarcaDEL)obj;
return (national.getNumRangoini().compareTo(this.getNumRangoini()) == 0);
}
#Override
public int hashCode() {
return this.getNumRangoini().intValue();
}
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal. Now I store some instances of that class in a HashSet so that there are no instances with the same names in the HashSet.
My Question: How is it possible to check if the HashSet contains such an object. .contains() wont work in that case, because it works with the .equals() method. I want to check if it is really the same object.
edit:
package testprogram;
import java.util.HashSet;
import java.util.Set;
public class Example {
private static final Set<Example> set = new HashSet<Example>();
private final String name;
private int example;
public Example(String name, int example) {
this.name = name;
this.example = example;
set.add(this);
}
public boolean isThisInList() {
return set.contains(this);
//will return true if this is just equal to any instance in the list
//but it should not
//it should return true if the object is really in the list
}
public boolean remove() {
return set.remove(this);
}
//Override equals and hashCode
}
Sorry, my english skills are not very well. Please feel free to ask again if you don't understand what I mean.
In your situation, the only way to tell if a particular instance of an object is contained in the HashSet, is to iterate the contents of the HashSet, and compare the object identities ( using the == operator instead of the equals() method).
Something like:
boolean isObjectInSet(Object object, Set<? extends Object> set) {
boolean result = false;
for(Object o : set) {
if(o == object) {
result = true;
break;
}
}
return result;
}
The way to check if objects are the same object is by comparing them with == to see that the object references are equal.
Kind Greetings,
Frank
You will have to override the hashCode method also.
try this..
Considering only one property 'name' of your Objects to maintain uniqueness.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (name == null ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
User other = (User) obj;
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
I made my own class with an overridden equals method which just checks, if the names (attributes in the class) are equal.
This breaks the contract of .equals, and you must never do it no matter how convenient it seems.
Instead, if you want to index and look up elements by a certain attribute such as the name, use a HashMap<Name, YourType> to find them. Alternatively, use a TreeSet and pass it a Comparator that compares the name only. You can then remove the incorrect equals method.
There are then three ways if you want to find objects by reference equality:
Your objects have no inherent or useful notion of equality.
Don't implement equals. Leave it to its default. You can then use a HashSet to look for reference equality, and a HashMap or TreeSet to index them by any specific attributes.
Your objects do have a useful, universal notion of equality, but you want to find equivalent instances efficiently anyways.
This is almost never the case. However, you can use e.g. an Apache IdentityMap.
You don't care about efficiency.
Use a for loop and == every element.
HashSet contains uses the equals method to determine if the object is contained - and duplicates are not kept within the HashSet.
Assuming your equals and hashcode are only using a name field...
HashSet<MyObject> objectSet = new HashSet<MyObject>();
MyObject name1Object = new MyObject("name1");
objectSet.add(new MyObject("name1"));
objectSet.add(name1Object);
objectSet.add(new MyObject("name2"));
//HashSet now contains 2 objects, name1Object and the new name2 object
//HashSets do not hold duplicate objects (name1Object and the new object with name1 would be considered duplicates)
objectSet.contains(new MyObject("name1")) // returns true
objectSet.contains(name1Object) // returns true
objectSet.contains(new MyObject("name2")) // returns true
objectSet.contains(new MyObject("name3")) // returns false
If you wanted to check if the object in the HashSet is the exact object you are comparing you would have to pull it out and compare it directly using ==
for (MyObject o : objectSet)
{
if (o == name1Object)
{
return true;
}
}
If you do this alot for specific objects it might be easier to use a HashMap so you don't have to iterate through the list to grab a specific named Object. May be worth looking into for you because then you could do something like this:
(objectMap.get("name") == myNameObject) // with a HashMap<String, MyNameObject> where "name" is the key string.
I have the below class with the fields name and id -
public class MyObj {
private String name;
private String id;
//getters and setters + toString implementation
}
In my main method, I am creating a list of MyObjand adding elements to the list.
public static void main(String[] args) {
List<MyObj> myList = new ArrayList<MyObj>();
MyObj myObj1 = new MyObj();
myObj1.setName("test");
myObj1.setId("123");
myList.add(myObj1);
MyObj myObj2 = new MyObj();
myObj2.setName("testOne");
myObj2.setId("456");
myList.add(myObj2);
}
When I iterate through the list, and print the contents, I have this -
MyObj [name=test, id=123]
MyObj [name=testOne, id=456]
I want to check if my List has a string. For example, if it contains name or id? When I use the contains method, it returns false. Clearly I am doing something wrong. How do I check if a list of objects has a string?
You might want something like Java8 Stream and filter, but if I understand your question (and the answers and comments) you want to get all the MyObj matching a criteria?
In that case, equals is not the way to do it. eg:
MyObj a = ...
a.setName("A");
a.equals("A"); // returns true
"A".equals(a); // returns false!
The javadoc of equals says that:
The equals method implements an equivalence relation on non-null
object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or
consistently return false, provided no information used in equals
comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
And in that case, you have a non symmetric equals (even if javadocs says it should be rather than it must be).
You can use filter, or better Java 8's Stream.
In pre Java 8, for loops, or external library such as Guava is the way to go.
The "simple" use case is the following:
List<MyObj> matching = new ArrayList<>();
for (MyObj o : list) {
if (null != o.getName() || null != o.getId()) {
matching.add(o);
}
}
This says that you have either a name defined (eg: not null), either an id.
If you need to go further, with advanced criteria, you can do that:
interface Predicate<T> {
boolean test(#Nullable T value);
}
public class Lists {
static <T> List<T> filter(List<? extends T> list, Predicate<T> predicate) {
List<MyObj> matching = new ArrayList<>();
for (MyObj o : list) {
if (predicate.test(o)) {
matching.add(o);
}
}
return matching;
}
}
And an example:
Lists.filter(listMyObj, new Predicate<MyObj>() {
public boolean test(MyObj o) {
return null != o.getName() || null != o.getId();
}
});
But you should use Guava since it does the same, and better (my example is more or less what Guava does).
As for Java 8:
myList.stream()
.filter(o -> null != o.getName() || null != o.getId())
.collect(Collectors.toList())
And I think you can do better using MyObj::getName/getId and some Function wrapper, to do the "isNull" test.
You need to implement equals method in your MyObj
I'm doing a school assignment where I need to store a bunch of contacts. Each contact has a HashSet of social network accounts, addresses and phone numbers.
I DO NOT want to store multiple copies of the same object in my HashSet, so I have overridden the hashCode() and equals() method for each object.
But for my social network account object only,my HashSet is storing the same object twice!
I have two different objects:
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
s1.equals(s2) returns true and s1.hashCode() == s2.hashCode() returns true, but s1 == s2 returns false! Why?
This is the hashCode() method I'm using:
public int hashCode() {
int prime = 31;
int result = 1;
result = result*prime + type.hashCode();
result = result*prime + id.hashCode();
return result;
}
The == operator compares references. Since there are two different objects, their references will be different.
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "wallcrawler123");
SocialNetworkAccount s2 = s1;
if (s1 == s2) {
System.out.println("The references are the same.");
}
I suspect that the problem is that your equals method is not overriding Object's equals method, which takes an Object as a parameter.
I suspect that your equals method takes a parameter of SocialNetworkAccount, not Object. I can't know for sure because you haven't posted your equals method, but it is a possible explanation. In this case, the equals method in Object is not overridden, so when HashSet (eventually) calls it, it calls Object's equals method, which compares references to see if they are the same.
If so, modify your equals method to accept an Object instead of a SocialNetworkAccount, so it overrides equals properly.
Also, using the #Override annotation will catch when a method that intends to override another method in fact does not override it.
hashCode method is used to coarsly assign entries to the table, but the equals(...) method has to return true for the two instances to be treated as identical.
Since you don't show us the equals method I assume you have not created your own version, which means the HashTable is useing the default implementation, which does a == b and your two instances are not the same instance, so that returns false, hence two entries in the table.
What you need to do is implement the equals method too:
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof SocialNetworkAccount) {
SocialNetworkAccount their = (SocialNetworkAccount)o;
return xxx.equals(their.xxx ) && yyy.equals(their.yyy) && ...;
}
return false;
}
Replace xxx and yyy and so on with the values in your class.
See the hashCode and equals contract
maybe you have done somthing like this?
SocialNetworkAccount s1 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "foo");
SocialNetworkAccount s2 = new SocialNetworkAccount(SocialNetworkAccount.AccountType.FACEBOOK, "bar");
hashSet.add(s1);
hashSet.add(s2);
s2.setNickname("foo");
System.out.println(s1.equals(s2)); // true
System.out.println(hashSet); // [FACEBOOK:foo, FACEBOOK:foo]
Below is written in javadocs
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).
Does it mean object1.equals(object2) return true only when object1==object2.
Below example at In Java, what is a shallow copy?
class Foo { private Bar myBar; ...
public Foo shallowCopy() {
Foo newFoo = new Foo(); newFoo.myBar = myBar; return newFoo; }
public Foo deepCopy() { Foo newFoo = new Foo(); newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ... return newFoo; } } Foo myFoo = new Foo();
Foo sFoo = myFoo.shallowCopy();
Foo dFoo = myFoo.deepCopy();
myFoo.myBar == sFoo.myBar => true
myFoo.myBar.equals(sFoo.myBar) => true
myFoo.myBar == dFoo.myBar => false
myFoo.myBar.equals(dFoo.myBar) => true
If First understading is correct how come myFoo.myBar.equals(dFoo.myBar) => true
The default implementation for equals is the same as ==
However it is common practice to override this method and give it an implementation where two objects are equal if the type and contents are the same. It should always be true when == is true.
No, o1.equals(o2) should return true when o1 == o2 is true, but it can also return true under other circumstances.
o1 == o2 returns true if o1 and o2 reference the same object, i.e. the same piece of memory.
However we're often interested in whether two objects are the same based on their properties other than their location in memory. For example if I execute new String("Hello World") twice, then the two strings are the same based on the sequence of characters they represent, but they are not the same object in memory.
The JavaDocs are talking about the implementation of equals() provided by the Object class itself, which returns true when the == operator returns true. When you create a subclass of object, you can re-implement the equals method to provide the kind of equality described above.