Casting an object in equals Java 5

C

crazzybugger

Hi,
I am stuck with a compiler warning while trying to cast an
object inside equals method.
Consider class A<I>{ }
inside this class, I am trying to override equals method. However, I
am not able to cast the received object into the proper type without
compiler warning.

Consider this implementation of equals
public boolean equals(Object that){
if(that instanceof A){
A<I> that1 = this.getClass().cast(that); // here I am
getting compiler warning.
// perform comparisons...
}
}

what is the right way to cast here ?
thank you...
 
C

crazzybugger

Since you already test if "that" is an instance of "A", do you even need
to cast it (assuming "A" is the class that implements this "equals()")?

A cast only tells the compiler to pretend/handle it as if that this
object is of type X, it does not convert the object in any way.

<http://mindprod.com/jgloss/cast.html>

If I donot cast it as an object of A<I> how can I access the methods &
attributes of A ? Besides If I try casting it as object of type 'A'
and not as A<I>, I get the 'not parameterised' warning!!!
 
A

Andreas Leitgeb

crazzybugger said:
Consider class A<I>{ }
public boolean equals(Object that){
if(that instanceof A){
A<I> that1 = this.getClass().cast(that); // here I am getting compiler warning.

Casting from Object to a parameterized type is fragile, because
not even at runtime can it be verified that the complete type
is correct. You can always cast to "A": A that1 = (A)that;
Sometimes that may be enough to determine equality.

If you look at how Sun did it, e.g. in AbstractMap<K,V>, then
you'll see that they simply did it analogously to

A<I> that1 = (A<I>) that;

and either ignored or suppressed the resulting warning.

PS: I think, that "normal" programs should never have a need
for .getClass(). (Application servers are not "normal" and
neither are class viewers in this context :)
 
R

RedGrittyBrick

crazzybugger said:
If I donot cast it as an object of A<I> how can I access the methods &
attributes of A ?

You can't. But I don't understand your "this.getClass().cast(that);"
I'd try

A<I> that1 = (A<I>) that;
that1.methodOfA();


By the way, your choice of example variable names confuses me. I'd maybe
have chosen them like this ...

public boolean equals(Object object) {
if (object instanceof A) {
A<I> a = (A<I>) object;
...

Besides If I try casting it as object of type 'A'
and not as A<I>, I get the 'not parameterised' warning!!!

Which is as it should be, why would you expect anything else?
 
R

Roland de Ruiter

Hi,
I am stuck with a compiler warning while trying to cast an
object inside equals method.
Consider class A<I>{ }
inside this class, I am trying to override equals method. However, I
am not able to cast the received object into the proper type without
compiler warning.

Consider this implementation of equals
public boolean equals(Object that){
if(that instanceof A){
A<I> that1 = this.getClass().cast(that); // here I am
getting compiler warning.
// perform comparisons...
}
}

what is the right way to cast here ?
thank you...

if (that instanceof A) {
A<?> that1 = (A<?>)that;
...
}

The actual type parameter of "that" isn't known at runtime, so you can
only cast it safely to an A of unknown type, i.e. A<?>.

I wouldn't use getClass().cast() if A can have subclasses, let's say B
and C, because this cast will fail if "this" is an instance of B and
"that" is an instance of C.
 
A

Andreas Leitgeb

Eric Sosman said:
One of the few places where .getClass() seems essential is in
implementing .equals() for non-final classes:

In my Java classes they told me not to do that at all.
Either make these classes (or equals() itself, along with
hashCode()) final or abstract.

Btw., I think that class-equality is not a necessary
condition for a contract-fulfilling (and non-trivial)
equals(). It's quite feasible, that a subclass, while
adding new fields and stuff, still adheres to the base-
class' definition of equality. Proper implementation
of this behaviour would have final equals() & hashCode()
in the non-final baseclass.

Apart from that case there is the situation that one should
either avoid entirely, or solve with reflection (and getClass()
is kind of an entry-point of reflection).

Any examples of where such a class-hierarchy with non-leaf
classes having to be non-abstract really and inevitably
comes up? (I'd like to know. I don't deny the possibility)
class Super {
public boolean equals(Object obj) {
if (obj.getClass() != Super.class) return false;

If it were really necessary, I'd probably rather do it
as: if (obj.getClass() != getClass()) return false;
to also deal with classes that do not override equals()
but still want their instances to be able to equal other
instances of the same subclass, or even themselves, based
only on baseclass features.
Does anyone know of a smoother way to do this?
Yes: avoid the situation :)

Make all leaf-classes final, and all others abstract.
OR: Allow subhierarchies where subclass instances can legally
equal instances of any other class within that subhierarchy.
 
A

Andreas Leitgeb

Another caveat with this approach:
if some subclass's equals() calls super.equals(), it may
get (unexpected) wrong negatives, even for identical
objects...
 
P

Patricia Shanahan

Andreas said:
In my Java classes they told me not to do that at all.
Either make these classes (or equals() itself, along with
hashCode()) final or abstract.
....

I take a rather different position. If a non-final class overrides
equals and hashCode, its documentation should include rules for subclass
equality.

Treating an object as being unequal from instances of its class's
subclasses is one possible rule, but not the only one.

For example, the List interface has a set of rules for equals and
hashCode that allow equality comparison of any two instances of any
class implementing List, regardless of whether the two objects are of
the same class or not.

AbstractList implements those rules using only the methods any List
implementation must have.

Patricia
 
A

Andreas Leitgeb

Maybe I've misunderstood, but this seems crazy.

In that class we had our "hands-on" example, some class
describing a (3D-)Point, and it had an equals() that compared
all three coordinates, and a hashCode() that was consistent
with equals().

Then the instructor raised the point of deriving a "ColoredPoint"
and showed us the bad effect of the naive approach for overriding
equals (and hashCode()) in ColoredPoint.

Generally (my own words):
One can only weaken(**) the equality relation when deriving
instanciable classes from other instanciable classes.
Otherwise, it results in an asymmetric (thus broken)
relation. (**): i.e.: grow the equivalence classes

But in subhierarchies, one generally wants to make the
subclasses equality more fine-grained. That's the problem.

The solutions for this problem are these:

- Document some appropriate contract for all subclasses

- Only care about leaf-classes' equals(). Let non-leaf
classes inherit Object's equals() or make them
abstract.

- Prevent subclassing (make the class final).

- Just prevent subclasses from fiddling with .equals()
or hashCode() (make these methods final)

- Make the baseclass's .equals() artificially more finegrained,
by growing only those equivalence classes that only
contain direct baseclass-instances.
This requires using getClass(), and the result is, that
any subclass cannot tell it apart from Object.equals().

While technically ok and legal, it (imho) contradicts
OO-principles, just like having any other method that does
something useful for instances of the class it's defined
in, but does nothing for any subclass-instance. brrr.

Those who use getClass() for equals() probably also torture
baby dogs in their leisure time ;-)
 
A

Andreas Leitgeb

Lew said:
He [Bloch] does recommend to "Design and document for inheritance or
else prohibit it" (Item 17), which Andreas's instructors might have twisted.

Don't attribute to my instructor's what you can attribute to me :)

I was just omitting the omnipresent principle of that my class can
have any cruel behaviour, that may require the user/subclasser to
jump through hoops, as long as I document each and every such hoop.

With that implicit alternative it's pretty well the same as how
I understood Bloch.
 
A

Andreas Leitgeb

That was just part of the whole message. These three lines
alone do not represent my nor (as I believe) my instructor's view.

The other crucial part was the context referred to by "that".

"That" (roughly): "designing a class and its .equals() such,
that it requires getClass() for its implementation"
I take a rather different position. If a non-final class overrides
equals and hashCode, its documentation should include rules for subclass
equality.
These rules, however may have to be quite restrictive then.
For example, the List interface has a set of rules for equals and
hashCode that allow equality comparison of any two instances of any
class implementing List, regardless of whether the two objects are of
the same class or not.

The above mentioned rules probably disallow overriding .equals() to
make it more restrictive - e.g. not let it depend on a new subclass-
specific independent(on baseclass) attribute.

In most other cases than collection classes, such rules would be de facto
prohibitive (against overriding .equals() at all).
 
T

Tom Anderson

In that class we had our "hands-on" example, some class
describing a (3D-)Point, and it had an equals() that compared
all three coordinates, and a hashCode() that was consistent
with equals().

Then the instructor raised the point of deriving a "ColoredPoint"
and showed us the bad effect of the naive approach for overriding
equals (and hashCode()) in ColoredPoint.

My take on this is that subclassing, and overriding equals, is okay, as
long as the symmetry of equals is preserved. So, ColouredPoint can
override equals and compare colour as well as position when it's comparing
itself to another ColouredPoint, but when comparing itself to a normal
Point, it should just compare coordinates, as a Point would. Like this:

public boolean equals(Object that) {
if (that instanceof Point) return equals((Point)that) ;
else return false ;
}

public boolean equals(Point that) {
if (that instanceof ColouredPoint) return equals((ColouredPoint)that) ;
else return (this.x == that.x) && (this.y == that.y) ;
}

public boolean equals(ColouredPoint that) {
return (this.x == that.x) && (this.y == that.y) && (this.colour.equals(that.colour)) ;
}

An equals method implemented like this is reflexive, and symmetric even in
the presence of mixed types. What it isn't is transitive:

Point p = new Point(5, 5) ;
Point q = new ColouredPoint(5, 5, Color.RED) ;
Point r = new ColouredPoint(5, 5, Color.BLUE) ;
p.equals(q) ; // true
p.equals(r) ; // true
q.equals(r) ; // false!

Which could be a problem. Or might not be. It's definitely not pretty, and
feels like an accident waiting to happen.

As for hashCode, if you want to to be consistent with equals, which is
generally considered a must, then you can't override the version in Point,
since the version of equals in Point is serving as the benchmark for
equality. I doubt this will be a huge problem in practice.

tom
 
Z

zerg

Andreas said:
Then the instructor raised the point of deriving a "ColoredPoint"
and showed us the bad effect of the naive approach for overriding
equals (and hashCode()) in ColoredPoint.

This sort of situation should induce one to reassess the object
relations in an OO design.

In particular, ColoredPoint may not make much sense as a "kind of"
point, so much as a combination of a point and a color. Which means
instead of inheriting from Point (or Color) maybe it ought to be a new
direct Object subclass that contains one of each.

Composition in place of inheritance is often what is needed in these
cases, rather than kludging the inherited methods to sort-of work.

Of course, it also depends on whether your design ever needs to use
ColoredPoints as generic points. Most likely, anywhere it seems to do so
it really can be changed to operate on myColoredPoint.getPoint().

More generally, with value-type classes it's generally the case that
composited ones should be exactly that -- composited. Equality
comparisons between them rarely make sense, though there are exceptions
(integers are a subset of fractions, which are a subset of real numbers,
which are a subset of complex numbers, is the textbook example).

The other cases where cross-comparisons make much sense tend to be
collections that have the same semantics but different implementations,
like the various List implementations, as mentioned elsewhere in this
thread.

In any event, warty equals-and-hashCode implementations or thorny
problems trying to develop these parts of a class tend to indicate the
need for a refactoring, and often for replacing inheritance with
composition somewhere up the class hierarchy from the problem class or
classes.
 
M

Mike Schilling

zerg said:
This sort of situation should induce one to reassess the object
relations in an OO design.

In particular, ColoredPoint may not make much sense as a "kind of"
point, so much as a combination of a point and a color. Which means
instead of inheriting from Point (or Color) maybe it ought to be a
new
direct Object subclass that contains one of each.

Composition in place of inheritance is often what is needed in these
cases, rather than kludging the inherited methods to sort-of work.

Of course, it also depends on whether your design ever needs to use
ColoredPoints as generic points. Most likely, anywhere it seems to
do
so it really can be changed to operate on myColoredPoint.getPoint().

More generally, with value-type classes it's generally the case that
composited ones should be exactly that -- composited. Equality
comparisons between them rarely make sense, though there are
exceptions (integers are a subset of fractions, which are a subset
of
real numbers, which are a subset of complex numbers, is the textbook
example).
The other cases where cross-comparisons make much sense tend to be
collections that have the same semantics but different
implementations, like the various List implementations, as mentioned
elsewhere in this thread.

In any event, warty equals-and-hashCode implementations or thorny
problems trying to develop these parts of a class tend to indicate
the
need for a refactoring, and often for replacing inheritance with
composition somewhere up the class hierarchy from the problem class
or
classes.

I know I give you a hard time sometimes, but I have to say: this is an
excellent post, very thorough and well-reasoned. .
 
A

Andreas Leitgeb

Tom Anderson said:
My take on this is that subclassing, and overriding equals, is okay, as
long as the symmetry of equals is preserved.

According to Object.equals()'s javadoc:
The equals method implements an *equivalence relation* on non-null
object references
Further down in the docs, transitivity is explicitly required for
the contract.
[transitivity broken]
Which could be a problem. Or might not be. It's definitely not pretty, and
feels like an accident waiting to happen.
It's a breach of the contract. It's no better than implementing equals
as "... { return myAtomicDrivenRandom.randomBoolean(); }" :)

My fault, that I forgot to mention it as another strong reason against
sharpening the relation.
 
A

Andreas Leitgeb

zerg said:
This sort of situation should induce one to reassess the object
relations in an OO design.

You've hit the nail on its head: The conclusion in that lesson was,
that this design of both-instanciable and subclass-related and both
custom-equals()ified ... (I hope I haven't forgotten any further
necessary attributes) ... Point and ColoredPoint was indeed *wrong*.

Whether the alternative is having Object as lowest common baseclass
of these classes, or making Point (or some other lowest common baseclass)
abstract (and derive a MonochromePoint from that, instead, for usage),
or making Point final (thus prevent the ColoredPoint to derive from
it), or prevent ColoredPoint from overriding equals(), or ..., or ...
The point is, that the design was broken, and one shouldn't do it.

My claim is, that if one needs getClass() to implement .equals() in
ones class design, then one has made an error some steps earlier.
An error just like the one in the lesson (where it was made on
purpose for demonstration, of course).

Anyone still argueing against this claim?

If not, we're back to searching for other uses of getClass() in
"normal" applications, for a specific definition of "normal"
made up a couple of postings upthread. I still think there is
none.
 
A

Andreas Leitgeb

Lew said:
So you prefer casting the argument from 'Object' to the type?
How do you make sure the argument type matches the target type?

I'm not sure I understand your question. Of course one needs to cast(*)
the argument to something, if one intends to do anything interesting
(beyond comparing e.g. toString()-results) in the equals() method.

*: after first verifying that the cast is legal, per "instanceof".
(or by catch'ing the ClassCastException).

Btw., "instanceof" is principially different from getClass(),
if that was the point of your question.
 
T

Tom Anderson

According to Object.equals()'s javadoc:
The equals method implements an *equivalence relation* on non-null
object references
Further down in the docs, transitivity is explicitly required for
the contract.

Sue me! :)
[transitivity broken]
Which could be a problem. Or might not be. It's definitely not pretty, and
feels like an accident waiting to happen.
It's a breach of the contract. It's no better than implementing equals
as "... { return myAtomicDrivenRandom.randomBoolean(); }" :)

That's patent nonsense, but i take your point.

There might well be situations in which you're quite confident that the
failure of transitivity won't be a problem, but i would readily agree that
it's a really bad idea for general-purpose classes.

tom
 
J

J. Stoever

Tom said:
There might well be situations in which you're quite confident that the
failure of transitivity won't be a problem, but i would readily agree
that it's a really bad idea for general-purpose classes.

There might also well be situations in which you're quite confident that
you have godlike superpowers. Sadly, just because a programmer is
confident of something doesn't make it so ;)
 
L

Lew

There might also well be situations in which you're quite confident that
you have godlike superpowers. Sadly, just because a programmer is
confident of something doesn't make it so ;)

Cute, but off the point. In fact as a developer of an API, Tom very
well can be confident of something because he actually did make it so,
and that was his point. You had it exactly backwards - confidence
didn't make it safe, making it safe made him confident.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top