I have the code below:
class Animal {
int i;
public Animal(){
i=13;
}
public String toString(){
return "Animal "+i;
}
}
//
public class NewMain {
public static void main(String[] args) {
HashSet hs=new HashSet();
boolean b=hs.add(new Animal());
boolean b1=hs.add(new Animal());
System.out.println(b+" "+b1);
for(Object o:hs)
{
System.out.println(hs);
}
}
}
I know that Set does not allow duplicates, but why does the above code seem to allow two identical values?
Because Java has no way of knowing that your two instances are the same.
You need to override equals() and hashcode()
.
As has already been pointed out, you need to override hashCode and equals. You can compare on the int i with something like,
class Animal {
int i;
public Animal() {
i = 13;
}
#Override
public String toString() {
return "Animal " + i;
}
#Override
public int hashCode() {
return Integer.hashCode(i);
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Animal) {
return ((Animal) obj).i == i;
}
return false;
}
}
Then I would suggest you use generics with your Collection. Also, you should print the instance (not the Collection) in your loop. Something like,
public static void main(String[] args) {
Set<Animal> hs = new HashSet<>();
boolean b = hs.add(new Animal());
boolean b1 = hs.add(new Animal());
System.out.println(b + " " + b1);
for (Animal a : hs) {
System.out.println(a);
}
}
And I get (the expected)
true false
Animal 13
You haven't overridden hashcode and equals in the Animal class. Therefore, these methods are inherited from java.lang.Object.
The inherited behaviour (from Object) is that objects are only equal if they are the same object.
In this case, a suitable pair of overrides for equals and hashcode would be something like this:
#Override
public boolean equals(Object other) {
return other instanceof Animal &&
other != null &&
((Animal) other).i == this.i;
}
#Override
public int hashCode() {
return i;
}
(Note that if you start creating subclasses of Animal, you need to think carefully on how best to implement equals(Object). By code above doesn't attempt to deal with that ...)
Related
Here I am trying to override both equals method as well as hash code method. But containsValue() method throwing False. Even the hashcode overridden class is getting called but i think equals method is not getting properly called. please help me with this.
import java.util.*;
class Test{
int i;
Test(int i)
{
this.i=i;
}
public boolean equals(Test t)
{
if(this.i==t.i){
return true;
}
else{
return false;
}
}
public int hashCode() { //Overriding hashCode class
int result = 17;
result = 37*result + Integer.toString(i).hashCode();
result = 37*result;
return result;
}
}
class TestCollection13{
public static void main(String args[]){
HashMap<Integer,Test> hm=new HashMap<Integer,Test>();
hm.put(1,new Test(1));
hm.put(2,new Test(2));
hm.put(3,new Test(1));
hm.put(4,new Test(4));
for(Map.Entry m:hm.entrySet()){
Test t2=(Test)m.getValue();
System.out.println(m.getKey()+" "+t2.hashCode());
}
System.out.println(hm.containsValue(new Test(2)));
}
}
Your method public boolean equals(Test t) does not override Object.equals(Object). You need to update your method signature and check the class type:
#Override
public boolean equals(Object o) {
return o instanceof Test
&& ((Test)o).i == this.i;
}
equals should be defined to take an Object, not a Test:
#Override
public boolean equals(Object other)
You could easily detect this by explicitly annotating the method with #Override in which case the compiler would detect this bug.
Method equals() takes Object as a parameter, so in your code you are not overriding equals() method but overloading it. So you need to change the incoming parameter to Object. Your method should be something like this:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Test)) return false;
Test test = (Test) o;
return this.i == test.i;
}
Also I would add getter and setter for your i member.
I am a new learner of java. I have overridden equals and hashcode for my Animal class. I would expect that, using a HashSet<Animal> as below, only one Animal will be inserted into the HashSet. However the second Animal object is getting added to the set despite having the same properties. Can anyone look into it?
import java.util.*;
class SetTest
{
public static void main(String [] args)
{
Set<Animal>s=new HashSet<Animal>();
Animal a=new Animal(2);
boolean b1=s.add(a);
System.out.println("hi "+b1);
Animal b=new Animal(2);
boolean b2=s.add(b);
System.out.println("hi "+b2);
}
}
class Animal
{
int t;
Animal(int a)
{
t=a;
}
public boolean equals(Object O)
{
if(O instanceof Animal && ((Animal)O).t==t)
return true;
return false;
}
public int hashcode()
{
return t;
}
}
Output:
hi true
hi true
Thanks a Lot.
You didn't override hashCode(). You introduced another method called hashcode(). Case matters.
When your intention is to override a method, always use the #Override annotation:
#Override
public int hashcode()
If you had done that, the compiler would have noticed the typo and have refused to compile the class.
Your code has a mistype hashcode: write hashCode not hashcode .
import java.util.*;
class SetTest {
public static void main(String [] args) {
Set<Animal>s=new HashSet<Animal>();
Animal a=new Animal(2);
boolean b1=s.add(a);
System.out.println("hi "+b1);
Animal b=new Animal(2);
boolean b2=s.add(b);
System.out.println("hi "+b2);
}
}
class Animal {
int t;
public Animal(int a) {
t=a;
}
#Override
public boolean equals(Object O) {
return O instanceof Animal
&& ((Animal)O).t==t;
}
#Override
public int hashCode() {
return t;
}
}
If you are using eclipse, you can make use of the source code generator and there by avoiding the common human error(the like you did it over here. Right click on the class -> source -> generate hashcode and equals methods. which will pop up window. There you can choose the fields which you need to consider for equals(equality of object) and hashcode generation.
Java uses hashCode and equals method to check if two objects are equal. HashSet internally uses HashMap. You can refer HashMap.put(K key, V value) method for more details.
I've been dealing with a domain issue where I have classes that implement a common interface and I want to be able to get hashes from these objects differently depending on if the object is accessed as an interface or as a concrete class instance. Basically what I want is the following:
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
public class B implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
public class C implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int Bar.hashCode(){ return 123;}
}
Bar interfaceObject = new A();
interfaceObject.hashCode(); //return 123
Bar aObject = new A();
aObject.hashCode();// return 1
As far as I know there isn't a way to do this, and I can think of lots of reasons why this could cause issues, but I wanted to ask those smarter than I if they had any nice ways of doing this outside of making the interface have a function like public int getCustomHashCodeForJustThisInterface(). I like being able to use these objects in hashMaps without having to jump through hoops, but with their current implementation of hashCode they would break, since these objects can have multiple views of their identity depending on how they are used, and I don't want to change their base implementation of hashCode;
You can't do that, because Java does not support non-polymorphic instance methods (static methods are not polymorphic, as the previous answer showed).
What you can do is to make your classes not directly implement Bar, but another interface (e.g. BarProvider) with a toBar() or getBar() method, which returns a custom object of type Bar, which behaves as you want.
public class A implements BarProvider{
#Override
public int hashCode(){ return 1;}
#Override
public Bar toBar() {
return new Bar() {
#Override
public int hashCode() { return 123; }
};
}
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
Bar interfaceObject = aObject.toBar();
interfaceObject.hashCode(); // return 123
Several improvements are possible, such as having the Bar object stored as a final field (to avoid multiple initializations), and having a reverse reference that allows you to get back from the Bar to its BarProvider.
Another possibility is to use an external provider, that makes your computations
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
}
public final class BarHasher implements Hasher<Bar> }
#Override
public int hashFor(Bar object) { return 123; }
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
BarHasher.hashFor(aObject); // return 123
or a static method that calls some other method
public class A implements Bar{
#Override
public int hashCode(){ return 1;}
#Override
public int hashAsBar() { return 123; }
}
public interface BarHasher implements Hasher<Bar> {
#Override
public int hashFor(Bar object) { return object.hashAsBar(); }
}
A aObject = new A();
interfaceObject.hashCode(); //return 1;
BarHasher.hashFor(aObject); // return 123
In case you don't know it, what you're trying to do is possible (and it's the default behavior) in C++ (you must declare methods as virtual to have the same behavior as Java) and in C# (but you will have a warning, unless you use the modifier new on the overriding method)
There's no way to do this that I know of.
Here's something you can do that you may not have known of (I'm not suggesting this is a good idea):
package com.sandbox;
import java.io.IOException;
public class Sandbox {
public static void main(String[] args) throws IOException {
A.speak();
B.speak();
A a = new A();
a.speak(); //my ide rightly gives a warning here. static function accessed through instance
A b = new B();
b.speak(); //my ide rightly gives a warning here. static function accessed through instance
}
public static class A {
public static void speak() {
System.out.println("A");
}
}
public static class B extends A {
public static void speak() {
System.out.println("B");
}
}
}
This will print:
A
B
A
A
Just to reiterate: This is NOT a good idea. I'm just letting you know for educational purposes.
It's easy to invoke different methods based on the declared type of a variable. That's called overriding, and here's an example of it:
public class Example {
public static void main(String[] argv) throws Exception {
Integer v1 = 12;
Number v2 = v1;
System.out.println(v1.hashCode() + " -> " + new KeyWrapper(v1).hashCode());
System.out.println(v2.hashCode() + " -> " + new KeyWrapper(v2).hashCode());
}
private static class KeyWrapper {
private Object obj;
private int hash;
public KeyWrapper(Integer v) {
this.hash = v.hashCode() * 3;
}
public KeyWrapper(Number v) {
this.hash = v.hashCode() * 5;
}
#Override
public int hashCode() {
return hash;
}
}
}
When you run this, you get the following output:
12 -> 36
12 -> 60
Why this is a bad idea is that you can't implement equals() in in a way that preserves its contract (which is that two equal objects must have equal hashcodes). At compile-time you have information about how the values are referenced, but at runtime you only know what they are.
That said, if you want to use different hashcode calculations for objects that do implement an interface, versus those that don't, you can write a KeyWrapper that uses instanceof.
public class Example {
public static void main(String[] argv) throws Exception {
Integer v1 = 12;
String v2 = "foo";
System.out.println(v1.hashCode() + " -> " + new KeyWrapper(v1).hashCode());
System.out.println(v2.hashCode() + " -> " + new KeyWrapper(v2).hashCode());
}
private static class KeyWrapper {
private Object wrapped;
public KeyWrapper(Object obj) {
this.wrapped = obj;
}
#Override
public boolean equals(Object obj) {
return wrapped.equals(obj);
}
#Override
public int hashCode() {
return (wrapped instanceof Number) ? wrapped.hashCode() * 3 : wrapped.hashCode() * 5;
}
}
}
This, of course, doesn't care about the declared type of the variable, only its actual type.
I tried to override equals and hashcode methods in a class. It is a subclass of another class which does not implement the equals method and hashCode methods.
Eclipse gave the below warning .
The super class ABC does not implement equals() and hashCode() methods.
The resulting code may not work correctly.
Why is the above warning given ? Under what circumstances it may not work correctly ?
If you say a.equals(b) versus b.equals(a) it is reasonable to expect the behaviour to be the same. But if they are of corresponding types B and A related by inheritance and only one of them properly implements equals then the behaviour will be different in those two examples.
Here, A is the superclass and does not implement equals at all (so it inherits java.lang.Object.equals). Subclass B overrides equals to depend on the name field.
class A {
String name;
public A() {
this.name = "Fred";
}
}
class B extends A {
public boolean equals(Object o) {
A a = (A)o;
return a != null && a.name.equals(this.name);
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
B b = new B();
System.out.println(a.equals(b) == b.equals(a));
}
}
Unsurprisingly, the output is false, thus breaking symmetry.
Have you tried super class override the equals ... and then auto generate subclass override implementation...
I am sure it will be differnt. it will have call to super.equals()
in current auto generated implementation it is only checking values in child class..
Consider below scenario and you will understand why warning.
abstract Class A{
private int a;
public void setA(int a){
this.a=a;
}
}
Class B extends A{
private int x;
public void setX(int x){
this.x=x;
}
#Override
public boolean equals(Object obj) { // This does not call Super.equals
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
B other = (B) obj;
if (x != other.x)
return false;
return true;
}
}
and in main Method try
B b1= new B();
b1.setA(10);
b1.setX(20);
B b2= new B();
b2.setA(20);
b2.setX(20);
if(b1.equals(b2)){
System.out.println("Warning was Right");
}
I have an abstract class named Xpto and two subclasses that extend it named Person and Car. I have also a class named Test with main() and a method foo() that verifies if two persons or cars (or any object of a class that extends Xpto) are equals. Thus, I redefined equals() in both Person and Car classes. Two persons are equal when they have the same name and two cars are equal when they have the same registration.
However, when I call foo() in the Test class I always get "false". I understand why: the equals() is not redefined in Xpto abstract class. So... how can I compare two persons or cars (or any object of a class that extends Xpto) in that foo() method?
In summary, this is the code I have:
public abstract class Xpto {
}
public class Person extends Xpto{
protected String name;
public Person(String name){
this.name = name;
}
public boolean equals(Person p){
System.out.println("Person equals()?");
return this.name.compareTo(p.name) == 0 ? true : false;
}
}
public class Car extends Xpto{
protected String registration;
public Car(String registration){
this.registration = registration;
}
public boolean equals(Car car){
System.out.println("Car equals()?");
return this.registration.compareTo(car.registration) == 0 ? true : false;
}
}
public class Teste {
public static void foo(Xpto xpto1, Xpto xpto2){
if(xpto1.equals(xpto2))
System.out.println("xpto1.equals(xpto2) -> true");
else
System.out.println("xpto1.equals(xpto2) -> false");
}
public static void main(String argv[]){
Car c1 = new Car("ABC");
Car c2 = new Car("DEF");
Person p1 = new Person("Manel");
Person p2 = new Person("Manel");
foo(p1,p2);
}
}
As the others say, the signature of the method you override must be exactly the same. When overriding methods, to make sure you are overriding, use the #Override annotation above the function, so IDEs like Eclipse will warn you if you changed the method.
This is what it would look like:
#Override
public boolean equals(Object obj){
...Your code here...
}
I would suggest to override hashCode() as well because when inserting items into lists, sets, hastables, etc... for equality (and performande) hashCode() is used (and sometimes equals() is not!)
So your final code would be:
#Override
public boolean equals(Object obj){
...Your code here...
}
#Override
public int hashCode(){
...Your code here...
}
More info at the javadoc
I understand why: the equals() is not
redefined in Xpto abstract class.
Actually equals() isn't redefined anywhere in your code. To override it, your method has to have Object as parameter type and you have to cast it (after testing with instanceof to return false when instances of two different subclasses are compared).
declaring public boolean equals(Person p) or public boolean equals(Car p) does not override Object's public boolean equals(Object o), it's just a new method that is never called.
Here's how I would go about it:
public abstract class Xpto {
}
public class Person extends Xpto{
protected String name;
public Person(String name){
this.name = name;
}
public boolean equals(Object o){
if(o == null || !getClass().equals(o.getClass())
return false;
Person p = (Person) o;
System.out.println("Person equals()?");
return this.name.compareTo(p.name) == 0 ? true : false;
}
}
public class Car extends Xpto {
protected String registration;
public Car(String registration){
this.registration = registration;
}
public boolean equals(Object o){
if(o == null || !getClass().equals(o.getClass())
return false;
Car car = (Car) o;
System.out.println("Car equals()?");
return this.registration.compareTo(car.registration) == 0 ? true : false;
}
}
public class Teste {
public static void foo(Xpto xpto1, Xpto xpto2){
if(xpto1.equals(xpto2))
System.out.println("xpto1.equals(xpto2) -> true");
else
System.out.println("xpto1.equals(xpto2) -> false");
}
public static void main(String argv[]){
Car c1 = new Car("ABC");
Car c2 = new Car("DEF");
Person p1 = new Person("Manel");
Person p2 = new Person("Manel");
foo(p1,p2);
}
}
Every class inherit an equals(Object) method from the Object class. Thus, Xpto does not need to define such a method.
When one overrides this method in subclasses (namely: Person, Car) one must define it with the exact same signature. In other words, the parameter of the equals method must be of type Object, and the method implementation must downcast it.
The Javadoc states that you need to override the equals method with object as a parameter.
Indicates whether some other object is
"equal to" this one.
Therefore your subclasses equals methods should look something like this:
public class Car extends Xpto
{
protected String registration;
public Car(String registration)
{
this.registration = registration;
}
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (obj == this)
{
return true;
}
if (!obj.getClass().isAssignableFrom(getClass()))
{
return false;
}
Car car = (Car) obj;
return this.registration.compareTo(car.registration) == 0 ? true : false;
}
}
It is generally very difficult/impossible to fully fulfill the equals contract and still have two different classes in the hierarchy equal to each other, and it is generally not done. Generally an equals method tests for the class being the same (so two instances of the same subclass will equal each other, but two instances of two different subclasses will not).
However, in your case it is possible to implement an equals in Xpto since there is only one property. The obvious way to do this is to define an abstract method in Xpto, and then override equals in Xpto as well:
public class Xpto {
protected abstract String getIdentity();
#Override
public boolean equals(Object o) {
if (o == null) return false;
//Typical implementation
//if (getClass() != o.getClass()) return false;
if (!(o instanceof Xpto)) return false; //risky implementation, but will allow a car to compare to a person
return getIdentity().equals((Xpto) o.getIdentity());
}
#Override
public int hashCode() {
return getIdentity().hashCode();
}
}
Others have pointed out that you did not actually override equals in your implementation. In the future you can get the compiler to help you out with that by using the #Override annotation. In your case you would have gotten a compile error early which would have saved you some time.
Your equals method should look like:
#Override public boolean equals(Object o) {
if (!(o instanceof YourType)) {
return false;
}
YourType yt = (YourType)o;
... // rest here
}
Also, don't forget to override hashCode as well, to be able to properly use your types in collections.
You are not overriding the equals() method, instead you overload it. Change the signature to
public boolean equals(Object o)
And then cast o to Person/Car and do the comparison.
And BTW, you could compare the strings with equals() as well:
return registration.equals(car.registration);
Your subclasses are defining equals(Person) or equals(Car), neither of which is going to like being passed an Xpto. If you declare them both as equals(Xpto), or better yet equals(Object) so that they'll work in collections, then your problem should go away.
Note, if you redeclare the equals() methods this way, (1) you'll need to check the classes of the objects you get passed, since you can't guarantee they're Cars or Persons anymore, and (2) you'll probably want to override getHashCode() as well, especially if you decide to make them both equals(Object), cause getHashCode() should return equal hash codes for two objects that are equal.