I have two arraylist with a number of model objects.I want to find the difference of these arraylists.When I use strings instead of models, I got the difference with removeall function in collection framework. But for model objects it doesnot work. Please any one help me
Implement equals and hashCode in your custom object and you can use the same approach as you did with Strings.
Well, the removeAll method is a generic library method which doesn't know anything about your model class. So if you think about it for a second, how is it going to know which ones are "the same"?
The short answer is that you need to override the equals() method in your Model class, as this is what the checks are based on. The implementation should return true for any pair of model instances that you wish to be considered the same - the default inherited behaviour returns true only if they're the same object in memory. (And as always, when you override equals() you must override hashCode() too).
String class has already overridden version of equals and hashCode method so you are able to use remove() method. If you have to use your class in collection (List or Set) then you will have to override these methods in your class otherwise it will use default implementation of these methods.
If two objects are logically equal that means their hashCode must be equal as well as they satisfy equals().
For comparing two ArraList you need two compare two objects.In your case it is your model object,for that you need to override equals method.
Try this code
#Override
public boolean equals(Object compareObj)
{
if (this == compareObj)
return true;
if (compareObj == null)
return false;
if (!(compareObj instanceof MyModel))
return false;
MyModel model = (MyModel)compareObj;
return this.name.equals(model.name); // Are they equal?
}
#Override
public int hashCode()
{
int primeNumber = 31;
return primeNumber + this.name.hashCode();
return 0;
}
Related
This question already has answers here:
Java: Use hashCode() inside of equals() for convenience?
(7 answers)
Closed 7 years ago.
Let's say we have a hashcode() function, which will then be used inside our equals() method to determine the equality of two objects. Is this an allowed/accepted approach?
Assume that we use a simple implementation of a hash code. (For example a few instance variables multiplied by prime numbers.)
This is a terrible way to check for equality, mostly since Objects don't have to be equal to return the same hashcode.
You should always use the equals method for this.
The general rule is:
If the equals method returns true for Objects a and b, the hashCode
method must return the same value for a and b.
This does not mean, that if the hashCode method for a and b returns
the same value, the equals method has to return true for these two
instances.
for instance:
public int hashCode(){
return 5;
}
is a valid, though be it inefficiënt, hashcode implementation.
EDIT:
to use it within an equals method would be something like this:
public class Person{
private String name;
public Person(String name){ this.name = name;}
public String getName(){ return this.name;}
#Override
public boolean equals(Object o){
if ( !(o instanceof Person)){ return false;}
Person p = (Person)o;
boolean nameE = this.name == null ? p.getName() == null : this.name.equals(p.getName());
boolean hashE = nameE ? true : randomTrueOrFalse();
// the only moment you're sure hashE is true, is if the previous check returns true.
// in any other case, it doesn't matter whether they are equal or not, since the nameCheck returns false, so in best case, it's redundant
return nameE && hashE;
}
#Override
public int hashCode(){
int hash = generateValidHashCode();
return hash;
}
}
It is a very bad practice. Hashes are supposed to have a minimal amount of collisions, but usually you have more possibilities for objects than the amount of possible hashes and because of the pigeonhole principle a few distinct objects must have the same hash.
When comparing hashes, you have a certain chance of getting "false positives".
Actually, it is not a bad idea!
But make sure you use this method to determine inequality, not equality. Hashing code may be faster than checking equality, especially when hashcode is stored (for example in java.lang.String).
If two object have different hashcodes they must be different, else they may be the same. For example you may use this method as the following
Object a, b;
if(a.hashCode() == b.hashCode()){
if(a.equals(b)) return true;
}
return false;
Be aware that in some cases code above may be slower than using only equals(), especially when in most cases a does equal b.
From documentation of Object.java:
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 hashtables.
Don't do this
While it is correct that you need to override equals() and hashCode() in pairs, having the same hash is not the same as having the same values.
Put some effort into really thinking the equality thing through. Don't shortcut here it will bite you later.
Can I check if an object is in a HashSet if I have only the object's hash code, but not the object itself?
You can't, since the hashCode is only used to locate the bin in which the object is stored within the HashSet. There may be multiple elements in the same bin, and HashSet uses equals to determine if the searched element exists in the bin that the hashCode was mapped to.
The bin may contain multiple elements having the same hashCode, so knowing only the hashCode is not enough.
You can make a special object, something like this
int hashCode = 1; // your
new Object() {
#Override
public boolean equals(Object obj) {
return true;
}
#Override
public int hashCode() {
return hashCode;
}
};
No you cant. Both equals and hashcode are required for finding an object in a hashed collection. The hashcode method tells which bucket to find the object in and the equals method finds the object in the bucket.
A real world example would be a house with many people in it. If you tell me to go find someone in some house, I am going to ask you two questions :
What house do I go to?
Who do I find?
Here (1) will be answered by hashcode and (2) will be answered by equals method.
A hashCode is not a uniquely identifying property, so no.
No, because 2 objects can have the same hashcode. The unicity of objects in a Set (or keys in a Map) is checked against hashCode() and equals().
All Objects have method hashCode(), called by HashSet, HashMap, ecc..
You can override this method to define your own logic
#Override
public int hashCode() {
return <<MY CODE HERE>>;
}
or, more simple, iterate your HashSet and check hashCode() value
int myHash = 123;
for(Object o:mySet){
if(myHash == o.hashCode()){
// do something..
}
}
I am not able to understand the behaviour (distinction) of equals method in String class and then overriding that equals method manually in custom class.
According to java, if we want two objects to be equal, then we should override equals method to check the equality among them. So, I made a Dog class and override equals method in that class. Further to check the equality among objects I used Set type collection as it does not allow duplicate. But I was confused to see the output. Here is my code:
import java.util.*;
class Dog{
int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean equals(Object o){
if((o instanceof Dog) && ((Dog)o).getType()==this.getType()){
return true;
}
else{
return false;
}
}
}
public class CheckEquality {
public static void main(String[] args) {
Dog d1=new Dog();
Dog d2=new Dog();
d1.setType(12);
d2.setType(12);
Set set=new HashSet();
if(set.add(d1)){
System.out.println("d1 added");
}
if(set.add(d2)){
System.out.println("d2 added");
}
String s1=new String("ad");
String s2=new String("ad");
//String s1="ad";
//String s2="ad";
Set set2=new HashSet();
if(set2.add(s1)){
System.out.println("s1 added");
}
if(set2.add(s2)){
System.out.println("s2 added");
}
}
}
output:
d1 added
d2 added
s1 added
what I expected:
d1 added
s1 added
can any one tell me why am I getting d2 addedd statement, when it can be seen that object with same type has already been added to Set.
While in contrary, String does NOT allow the statement s2 added. Why is it so?. Can anyone clear my doubts.
You are missing hashCode method.
This hash is used by other code when storing or manipulating the
instance – the values are intended to be evenly distributed for varied
inputs in order to use in clustering. This property is important to
the performance of hash tables and other data structures that store
objects in groups ("buckets") based on their computed hash values
You can use Objects class to generate hashcode.
public class Dog {
#Override
public int hashCode() {
return Objects.hash(type);
}
}
Because you have to override hashCode as well. Check the contract of Object#equals:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Add this to your Dog class:
public class Dog {
#Override
public int hashCode() {
return this.type;
}
}
This is just a basic example. It would be better if type is a final field. From Object#hashCode:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
The Set-implementation HashSet is expected to find values by using the hashCode. Your object does not provide a good hashCode but instead uses the version from Object. When implementing equals you should generally also always implement hashCode. It is simply a best practice.
In Java 8 you can provide a good and efficient hash by using the following code:
Objects.hash(value1, value2, value3);
If used properly the HashSet will work as expected. For the simple Dog-class the type can be returned but for more complex objects that contains more attributes the Objects.hash or similar is recommended.
If you does't override hashcode method there is collision issue while storing object in hashset. Hashset internally uses hashtable to key and value pair.
Since you must have to override the hashcode so that hashset found that same hashcode then it will internally call the equals the method.
#Override
public int hashCode() {
return type.hashcode();
}
Below is my class. The insertSymbol method is supposed to add an object to the linked list which is then added to a hash table. But when I print the contents of the hash table it has double entries. I tried to correct this by using "if(temp.contains(value)){return;}" but it isn't working. I read that I need to use #override in a couple of places. Could anyone help me know how and where to use the overrides? Thank you!
import java.util.*;
public class Semantic {
String currentScope;
Stack theStack = new Stack();
HashMap<String, LinkedList> SymbolTable= new HashMap<String, LinkedList>();
public void insertSymbol(String key, SymbolTableItem value){
LinkedList<SymbolTableItem> temp = new LinkedList<SymbolTableItem>();
if(SymbolTable.get(key) == null){
temp.addLast(value);
SymbolTable.put(key, temp);
}else{
temp = SymbolTable.get(key);
if(temp.contains(value)){
return;
}else{
temp.addLast(value);
SymbolTable.put(key, temp);
}
}
}
public String printValues(){
return SymbolTable.toString();
}
public boolean isBoolean(){
return true;
}
public boolean isTypeMatching(){
return true;
}
public void stackPush(String theString){
theStack.add(theString);
}
}
You have multiple options here. You'll need at least to add an equals (and therefor also a hashcode) method to your class.
However, if you want your collection to only contain unique items, why not use a Set instead?
If you still want to use a List, you can use your current approach, it just that the characteristics of a Set are that all items in a Set are unique, so a Set might make sense here.
Adding an equals method can quite easily be done. Apache Equalsbuilder is a good approach in this.
You don't need the 2nd line when you add a new value with the same key:
temp.addLast(value);
SymbolTable.put(key, temp); // <-- Not needed. Its already in there.
Let me explain something that #ErikPragt alludes to regarding this code:
if(temp.contains(value)){
What do you suppose that means?
If you look in the javadocs for LinkedList you will find that if a value in the list is non-null, it uses the equals() method on the value object to see if the list element is the same.
What that means, in your case, is that your class SymbolTableItem needs an equals() method that will compare two of these objects to see if they are the same, whatever that means in your case.
Lets assume the instances will be considered the same if the names are the same. You will need a method like this in the 'SymbolTableItem` class:
#Overrides
public boolean equals(Object that) {
if (that == null) {
return false;
}
if (this.getName() == null) {
return that.getName() == null;
}
return this.getName().equals(that.getName());
}
It it depends on more fields, the equals will be correspondingly more complex.
NOTE: One more thing. If you add an equals method to a class, it is good programming practice to add a hashcode() method too. The rule is that if two instances are equal, they should have the same hashcode and if not equal they don't have to be different hashcodes but it would be very nice if they did.
If you use your existing code where only equals is used, you don't need a hashcode, stricly. But if you don't add a hashcode it could be a problem someday. Maybe today.
In the case where the name is all that matters, your hashcode could just return: this.getName().hashcode().
Again, if there are more things to compare to tell if they are equal, the hashcode method will be more complex.
Given two Lists, each list holding the same object type, I would like to find objects between the two lists that match, based on some property values.
e.g. an object from List1, L1Obj, matches an object from List2, L2Obj, if L1Obj.a == L2Obj.a AND L1Obj.b == L2Obj.c AND L1Obj.c == L2Obj.c
These properties are not the only properties of the of the class, but are all that is needed to uniquely identify an object within a list.
My question is - what is the best way to achieve this?
One way would be to construct to HashMaps based on the lists, with the concataned String value of a+b+c used as the key to index an object. That way I could iterate through the first list, and attempt to lookup an object in the second list with the same key.
How does this sound? Is there a better way of achieving this??
All help is much appreciated!
UPDATE:
Okay, so actually I need a bit more. Upon finding a match, I want to overwrite properties L1Obj.x, L1Obj.y, L1Obj.z with those of L2Obj. HashSet sounds great for finding that matches, but if I'm right it doesn't actually allow me to access these matches.
What can I do about this?
Do the objects you want to look at implement equals(Object) and hashCode() that only take into account the fields you care about? If so, you can create a new HashSet from the first list, and then call retainAll() passing in the second list.
If they don't implement equals(Object) and hashCode() with respect to the properties you care about, you can create a TreeSet and pass in a Comparator that looks at the properties you care about.
Rather than use the String repesntation, use the equals() method a HashSet as so:
class MyObj {
Property a;
Property b;
Property c;
public boolean equals(Object o) {
// use == if Property is primitive, like int or something
return o instanceof MyObj && a.equals(o.a) && b.equals(o.b) && c.equals(o.c);
}
// edit - when you override equals, also override hashcode
public int hashCode() {
return a.hashCode() ^ b.hashCode() ^ c.hashCode();
}
public String toString() {
return a.toString() + " " + b.toString() + " " + c.toString();
}
}
// later in your main method
Set<MyObj> objSet = new HashSet<MyObj>();
for(MyObj o : list1) objSet.add(o);
for(MyObj o : list2) if(objSet.contains(o)) System.out.println(o + " is a match!");
You can do one thing. Have two lists with these objects and override the equals method of the class to which these objects belong.
Your equals method should look like
#Override
public boolean equals(Object obj)
{
return (this.a == obj.a && this.b == obj.b && this.c == obj.c)
}
Also remember, once you override equals method, you need to override int hashCode() method as well.
One thing to note is while implementing hashCode() is that 2 equal objects will have same hashCode, while the converse is not true.
I don't know if I thinking to easy but I would try it like that:
Override the equals method of the object to implement your comparison to check if it is the same object
Then I would iterate over the first list and check with the contains method if the object is also contained in the second list.
Then I would iterate through the second list and check if the object is also in the first list and not already in the result list.
The object in question should implement the boolean equals(Object) method. E.g.:
L1Obj.equals(L2Obj);
You could overload that method so that you can implement the equality operations that you want.