override equals and hashcode

L

lowenbrau

Hi,

I have a class Obj. I created three objects o1,o2,03. Objects are equal if their id is equal. For example, o1 and o3 are equal. I tried adding these three objects to a HashSet, and when I print the size of the hashset I get "3" and not "2". Something is not right with the equals or hashcode method. Can someone shed some light?

code snippet:

import java.util.*;

public class Test
{
public static void main (String[] args)
{
Set hs = new HashSet();
Obj o1 = new Obj ("w", 10);
Obj o2 = new Obj ("r", 20);
Obj o3 = new Obj ("w", 30);

hs.add(o1);
hs.add(o2);
hs.add(o3);

System.out.println(hs.size());
}

public static class Obj
{
String id;
int length;

Obj (String id, int length)
{
this.id = id;
this.length = length;
}

boolean equals (Obj o)
{

if (o == null)
return false;
else if (o instanceof Obj)
return (this.id.equals(o.id));
else return false;
}

public int hashCode()
{
return id.hashCode();
}
}
}
 
L

Lew

lowenbrau said:
Hi,

I have a class Obj. I created three objects o1,o2,03. Objects are equal
if their id is equal. For example, o1 and o3 are equal. I tried adding
these three objects to a HashSet, and when I print the size of the
hashset I get "3" and not "2". Something is not right with the equals or
hashcode method. Can someone shed some light?

code snippet:
boolean equals (Obj o)
{

if (o == null)
return false;
else if (o instanceof Obj)
return (this.id.equals(o.id));
else return false;
}

From the JLS
If a public class has a method or constructor with default access, then this method or constructor is not accessible to or inherited by a subclass declared outside this package.

You didn't override equals().
 
T

Thomas Fritsch

lowenbrau said:
Something is not right with the equals or hashcode method. Can someone shed some light? [...]
boolean equals (Obj o)
In order to override
equals(Object o)
you have to declare it as
equals(Object o)
and not
equals(Obj o)
 
L

lowenbrau

lowenbrau said:
Something is not right with the equals or hashcode method. Can someone
shed some light? [...]
boolean equals (Obj o)
In order to override
equals(Object o)
you have to declare it as
equals(Object o)
and not
equals(Obj o)
{
if (o == null)
return false;
else if (o instanceof Obj)
return (this.id.equals(o.id));
else return false; }

Thankyou!
 
T

Thomas Fritsch

lowenbrau said:
default access?
He means: If the overridden method is public (in your case:
equals(Object) of class java.lang.Object), then the overriding method
(in your case: equals(Object) of your class Obj) must be public too.
Doing not so will cause the compiler to complain.
I don't have a subclass? or any package?
You *have* a subclass: Your class Obj is a subclass of java.lang.Object.
You also *have* a package (the name-less default package), which is
different from the package "java.lang".
 
P

Patricia Shanahan

lowenbrau said:
default access?
I don't have a subclass? or any package?
Can you be help some more?

The equals method in Object is declared "public boolean equals(Object obj)"

To override it, you must declare an equals with the same signature. The
only thing you can safely change is the identifier for the parameter:

public boolean equals(Object o)

is fine. Changing anything else will prevent your method from overriding
the Object equals.

Note that when testing an equals implementation it is important to
include tests where the parameter has type Object, even if it references
an instance of your class:

Test someTest = new Test...
Object o1 = someTest;

and use o1 as the equals parameter. That is how it will be used, in
effect, in java.util collections.

[If it were "public boolean equals(SomeClass obj)" you could replace
"SomeClass" with a superclass or super-interface. Object has no
superclasses, so that is not an option for equals.]

Patricia
 
R

Roedy Green

boolean equals (Obj o)
when you override you must exactly match the signature of the beast in
base class. equals should be public.
I have not experimented with the @override annotation to make sure it
generates an error message if my signature does not exactly match
something in the base class.
 
R

Roedy Green

The signature must exactly match:
public boolean equals( Object o )
not
boolean equals( Obj o )
Unfortunately you won't get an error message. Javac does not know you
are trying to override equals. It thinks you are making up an
overloaded variant.
if (o == null)
return false;
else if (o instanceof Obj)
return (this.id.equals(o.id));
else return false;
If you ever fed that to IntelliJ likely it would ask if you wanted it
converted to:
return o != null && o instanceof Obj && this.id.equals(o.id);
What does instanceof do with nulls?
 
R

Roedy Green

return o != null && o instanceof Obj && this.id.equals(o.id);
What does instanceof do with nulls?

null instanceof SomeClass is always false.

Therefore you can collapse that expression to:
return o instanceof Obj && this.id.equals(o.id);
The way you wrote your code, o HAD to be an Obj so the instanceof was
nugatory.

Had you written the code correctly, there could be some doubt.

e.g.

public boolean equals (Object o)
{
return o instanceof Obj && this.id.equals(((Obj)o).id);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,699
Latest member
AnneRosen

Latest Threads

Top