How to check if object is an instanceof a class, but not a sub-class?

L

laredotornado

Hi,

I'm using Java 1.6. If I have a object of class "A", I can use the
"instanceof" operator to confirm that the object is of this class.
But if I have an object of class B (extends A), instanceof will also
return true if use "obj instanceof A".

My question is, how can I tell if an object is a direct instantiation
of a class A and not a sub-class of the class A?

Thanks, - Dave
 
M

Mike Schilling

laredotornado said:
Hi,

I'm using Java 1.6. If I have a object of class "A", I can use the
"instanceof" operator to confirm that the object is of this class.
But if I have an object of class B (extends A), instanceof will also
return true if use "obj instanceof A".

My question is, how can I tell if an object is a direct instantiation
of a class A and not a sub-class of the class A?

Having to know this is probably an indication of poor design. But if you
really need to, try

if (a.getClass() == A.class)
 
E

Eric Sosman

laredotornado said:
My question is, how can I tell if an object is a direct instantiation
of a class A and not a sub-class of the class A?

Having to know this is probably an indication of poor design.[...]

It's often necessary in equals() implementations, so at least
some of the design failings are Java's own.
 
D

Daniel Pitts

Having to know this is probably an indication of poor design. But if you
really need to, try

if (a.getClass() == A.class)
There is one use-case I can think of, and that is properly handling the
"equals" contract.
 
L

Lew

Daniel said:
There is one use-case I can think of, and that is properly handling the
"equals" contract.

In that context the idiom is often

if ( other.getClass() != getClass() )
{
return false;
}
...
 
D

Daniel Pitts

In that context the idiom is often

if ( other.getClass() != getClass() )
{
return false;
}
...
Thanks for expounding on my idea. Yes, that is the idiom used to handle
the use-case I was describing.

Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
 
E

Eric Sosman

[... using getClass() in equals() ...]

Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }

Hmm. I usually write

if (other == null || other.getClass() != Thing.class)

Is there a reason to prefer one or the other?
 
D

Daniel Pitts

[... using getClass() in equals() ...]

Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }

Hmm. I usually write

if (other == null || other.getClass() != Thing.class)

Is there a reason to prefer one or the other?
To still allow subclasses to use the parent's equals() implementation
where they don't otherwise change the equal semantics.

E.G. if class SubThing only changed behavior of some method, then your
equals would return false against any SubThing.equals(SubThing), where
the first one could succeed.
 
E

Eric Sosman

[... using getClass() in equals() ...]

Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }

Hmm. I usually write

if (other == null || other.getClass() != Thing.class)

Is there a reason to prefer one or the other?
To still allow subclasses to use the parent's equals() implementation
where they don't otherwise change the equal semantics.

E.G. if class SubThing only changed behavior of some method, then your
equals would return false against any SubThing.equals(SubThing), where
the first one could succeed.

Fair enough. Thanks!
 
A

Andreas Leitgeb

Eric Sosman said:
[... using getClass() in equals() ...]
Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
Hmm. I usually write
if (other == null || other.getClass() != Thing.class)
Is there a reason to prefer one or the other?

I'm rather surprised to see .equals() being called an
exceptional usecase for exact class-check.

From previous discussions here and elsewhere, I had gathered, that
the "really correct" way to handle (non-trivial!) .equals() in a
class hierarchy would be to make all non-leaf-classes abstract.
 
S

Simon Brooke

Eric Sosman said:
[... using getClass() in equals() ...] Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
Hmm. I usually write
if (other == null || other.getClass() != Thing.class)
Is there a reason to prefer one or the other?

I'm rather surprised to see .equals() being called an exceptional
usecase for exact class-check.

From previous discussions here and elsewhere, I had gathered, that
the "really correct" way to handle (non-trivial!) .equals() in a class
hierarchy would be to make all non-leaf-classes abstract.

Making all non-leaf classes abstract is an example of poor design.

public class Bird {
public boolean getCanFly() {
return true;
}
}

public class Penguin extends Bird {
public boolean getCanFly() {
return false;
}
}

Are you saying that class Bird ought not to be instantiable? Are you
saying I ought to add a class:

public class InstantiableBird extends Bird {} ?

which has no new semantic content, which overrides or specialises
nothing, and that's 'really correct'?
 
A

Andreas Leitgeb

Simon Brooke said:
Eric Sosman said:
On 6/23/2010 5:27 PM, Daniel Pitts wrote:
[... using getClass() in equals() ...] Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
Hmm. I usually write
if (other == null || other.getClass() != Thing.class)
Is there a reason to prefer one or the other?
I'm rather surprised to see .equals() being called an exceptional
usecase for exact class-check.
From previous discussions here and elsewhere, I had gathered, that
the "really correct" way to handle (non-trivial!) .equals() in a class
hierarchy would be to make all non-leaf-classes abstract.
Making all non-leaf classes abstract is an example of poor design.

Maybe, you just missed one constraint that I mentioned: My comment
about abstract non-leaf-classes was constrained to hierarchies, that
define their custom .equals() in a way that seems to require exact
class-check. (My previous statement was in itself more general but
it was in the context of needing direct class-check, so it was still
correct in the given context)

It would indeed make no sense at all, to apply my comment generally
to all hierarchies.
[Bird, Penguin extends Bird - should Bird be abstract?]
Actually, you won't ever find a real instance of Bird in nature that
isn't really of some more specific class. Be it Hawk, Craw, Ostrich,
Turkey, Chicken, ...
Are you saying that class Bird ought not to be instantiable?

If (AND ONLY if) you were to define some *finer* equality for
Penguin than you did for Bird, then my claim applies.

More precisely, equal and inheritence work well, as long as the
subclass's .equal() is "equal or coarser" than the superclass's.
Everything is "equal or coarser" than Object's .equals().

The opposite of coarser happens with classes like (partially pseudocode)
class Circle { int radius; ... equals(o) { radius==o.radius;} }
class ColoredCircle extends Circle
{ int color; ... equals(o) { super.equals(o) && color==o.color;} }

ColoredCircle's .equals() is now finer than Circle's.
That's where problems creep in. To solve them, either you resort
to reflection by checking exact class (imho: bad design), or you
make sure, that no direct Circle-instances can exist, and instead
define an "UncoloredCircle" as a separate leaf-class.
 
T

Tom Anderson

Eric Sosman said:
On 6/23/2010 5:27 PM, Daniel Pitts wrote:
[... using getClass() in equals() ...] Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
Hmm. I usually write
if (other == null || other.getClass() != Thing.class)
Is there a reason to prefer one or the other?

I'm rather surprised to see .equals() being called an exceptional
usecase for exact class-check.

From previous discussions here and elsewhere, I had gathered, that
the "really correct" way to handle (non-trivial!) .equals() in a class
hierarchy would be to make all non-leaf-classes abstract.

Making all non-leaf classes abstract is an example of poor design.

On the contrary, it's a sign of well-factored code. It's not an iron rule,
but in general, if you have concrete classes extending other concrete
classes, there are abstractions you haven't identified.
public class Bird {
public boolean getCanFly() {
return true;
}
}

public class Penguin extends Bird {
public boolean getCanFly() {
return false;
}
}

Are you saying that class Bird ought not to be instantiable? Are you
saying I ought to add a class:

public class InstantiableBird extends Bird {} ?

which has no new semantic content, which overrides or specialises
nothing, and that's 'really correct'?

In this example, it's hard to say, because modelling kinds of birds as an
inheritance hierarchy is itself not good OO design. The idea of mapping
zoological hierarchies onto executable ones is - if you'll excuse the
expression - a canard. This would be a time to use the Type Object
pattern, and push the taxonomy out into a set of flyweight instances of a
BirdType class.

But sticking with the example, yes, you should pull out more classes:

Bird
FlyingBird
Swallow
AfricanSwallow
EuropeanSwallow
FlightlessBird
Penguin

With the obvious abstract and concrete methods.

tom
 
A

Arne Vajhøj

Eric Sosman said:
On 6/23/2010 5:27 PM, Daniel Pitts wrote:
[... using getClass() in equals() ...] Actually, I would use:
if (other == this) { return true; }
if (other == null || other.getClass() != getClass() { return false; }
Hmm. I usually write
if (other == null || other.getClass() != Thing.class)
Is there a reason to prefer one or the other?

I'm rather surprised to see .equals() being called an exceptional
usecase for exact class-check.

From previous discussions here and elsewhere, I had gathered, that
the "really correct" way to handle (non-trivial!) .equals() in a class
hierarchy would be to make all non-leaf-classes abstract.

Making all non-leaf classes abstract is an example of poor design.

No.

It is good design.
public class Bird {
public boolean getCanFly() {
return true;
}
}

public class Penguin extends Bird {
public boolean getCanFly() {
return false;
}
}

Are you saying that class Bird ought not to be instantiable?

Yes.

There are no bird instances in the real world. They are all
instances of some type of bird.

Are you
saying I ought to add a class:

public class InstantiableBird extends Bird {} ?

which has no new semantic content, which overrides or specialises
nothing, and that's 'really correct'?

Usually you will only have subclasses for the specific birds
you need.

In the rare case that you need something to represent any bird
not represented by a specific sub class, then it would be good
design to have an OtherBird class.

Usually there will also be at least on abstract method
that requires overriding to return the display name
of the bird type.

Arne
 
C

ClassCastException

Simon Brooke said:
[Bird, Penguin extends Bird - should Bird be abstract?]
Actually, you won't ever find a real instance of Bird in nature that
isn't really of some more specific class. Be it Hawk, Craw, Ostrich,
Turkey, Chicken, ...

Misspellings like that really stick in my crow... :)
 
E

Eric Sosman

[...]
Are you saying that class Bird ought not to be instantiable?

Yes.

There are no bird instances in the real world. They are all
instances of some type of bird.

That way lies madness. There are no Parrot instances in
the real world, only Polly and Snoofles and FeatheredBastard and
so on. Even Polly has no instances: There's Polly son of Polly
daughter of Polly son of Gawain, and PollyOfUnknownAntecedents,
and so on and so forth. Since the human mind is too small to
encompass all individual things in Nature or in imagination, it
is eventually necessary to generalize, to lump a whole aviary
of Pollys and Snoofleses and FeatheredBastards and so on into
Parrot. Or, let it be said, into Bird.

"Must every little attribute have a class all its own?"
 
S

Screamin Lord Byron

That way lies madness. There are no Parrot instances in
the real world,
True.

Since the human mind is too small to
encompass all individual things in Nature or in imagination, it
is eventually necessary to generalize,

True again, but it has nothing to do with the size of the human mind.
Even if the human mind was infinite, you still wouldn't have actual
animals and birds and parrots and Pollys in it, only their abstract
representations.

to lump a whole aviary
of Pollys and Snoofleses and FeatheredBastards and so on into
Parrot. Or, let it be said, into Bird.

You will lump it according to your lowest needed level of abstraction.
If your lowest level of abstraction is bird, then you'll only have
instances of the Bird class, but not instances of the Animal class. If
your generalization needs to be more specific, then you'd have instances
of the Parrot class, but not of the Bird and the Animal classes.
 
A

Arved Sandstrom

Eric said:
[...]
Are you saying that class Bird ought not to be instantiable?

Yes.

There are no bird instances in the real world. They are all
instances of some type of bird.

That way lies madness. There are no Parrot instances in
the real world, only Polly and Snoofles and FeatheredBastard and
so on. Even Polly has no instances: There's Polly son of Polly
daughter of Polly son of Gawain, and PollyOfUnknownAntecedents,
and so on and so forth. Since the human mind is too small to
encompass all individual things in Nature or in imagination, it
is eventually necessary to generalize, to lump a whole aviary
of Pollys and Snoofleses and FeatheredBastards and so on into
Parrot. Or, let it be said, into Bird.

"Must every little attribute have a class all its own?"

I'm an amateur bird-watcher - very amateur - and I routinely classify
birds as Birds. I'm not totally helpless - if I spot crows or robins or
grackles or eagles I know what they are specifically - but most birds
for me are Birds. Usually only if they are ducks or geese can I tell you
exactly what they are. :) For most of my mental models - and for quite
a few software models that I can imagine - Bird would suffice as a
template. A thing could genuinely and practically be an instance of Bird.

Problems like this is why I am less and less enthused with inheritance
and rigid class trees by the year. I've never actually used inheritance
a lot, and I use it less now than I ever did at the beginning of
learning OOP. My canonical example of inheritance frustration is
Vehicle: I've never come up with an inheritance tree starting with
Vehicle that doesn't leave a bad taste in my mouth. For a lot of my
mental models, and for quite a few software models that I can think of,
Vehicle is sufficient as a template. Objects could in fact be instances
of Vehicle.

Here's another example: Fastener. Go ahead and do up an inheritance tree
for Fastener that leaves you feeling warm and fuzzy.

I have very flat inheritance trees these days; always have had for the
most part. Aggregation/composition and interfaces go a lot further for
me than inheritance ever will. I don't mean to suggest that I make
minimal use of inheritance - I still use it a fair bit - but in recent
years almost all my use of it has been for implementation concerns like
re-using common code in JPA domain objects, _not_ for high-level design
per se.

Moving outside Java, and not focusing on any one other given language,
for me the object ideal is that of a fairly generic instance with
identity, that assumes characteristics and responsibilities as required,
and sheds them when it no longer needs them. If there were any inherent
"type" or classification, it might well be as high-level as Bird or
Vehicle or Human. A Human, at various points, might have the
characteristics and/or behaviours of a Student or Teacher or Employee or
Employer or Voter or Driver or DeceasedPerson or Felon, but those are
precisely characteristics and behaviours that the instance of Human
claims through composition/aggregation, and through implementation of
interfaces. There is no need to describe any of this through
inheritance, not in a high-level model/design sense, and I myself think
it's counter-productive.

I was going to extol some other languages in comparison to Java, but
then it occurred to me that while other languages might have features
that make some of these things easier to do, all of these concepts can
be implemented with no great difficulty in Java.

AHS
 
E

Eric Sosman

What are you supposed to do if the appropriate level of abstraction
varies at run time?

I'll sometimes think "There's a peacock" or "There's a mallard duck",
but at other times "That's a very elegant brown bird". The level of
abstraction changes depending on the information I have about the bird.

class Bird { ... }
class Duck extends Bird { ... }
class Mallard extends Duck { ... }
class Peacock extends Bird { ... }

Bird[] observed = {
new Peacock("There's a peacock"),
new Mallard("There's a mallard duck"),
new Bird("There's a very elegant brown bird"),
};
if (moreInformationBecomesAvailable()) {
observed[2] = new Wren(observed[2]);
}
Sometimes I have enough information to classify the bird by species,
sometimes by general type - I can tell the difference between a duck and
a vulture, without necessarily knowing the exact species - and sometimes
just by "bird" plus description.

It seems to me that the choice of taxonomy is driven not by the
nature of the things "out there" in the world, but by their nature
in the program's model of the world. One program may find it useful
to distinguish between Thrush and Swallow. Another may need to go
further and distinguish Goose from Gander. Still another may just
use Bird, with a single parameter describing how much damage it does
when sucked into an aircraft engine. The features chosen for modeling
have more to do with the nature of the model than with the true nature
(whatever *that* is) of the thing modeled.
 
A

Arved Sandstrom

Eric said:
On 6/26/2010 9:40 AM, Patricia Shanahan wrote:
[ SNIP ]
It seems to me that the choice of taxonomy is driven not by the
nature of the things "out there" in the world, but by their nature
in the program's model of the world. One program may find it useful
to distinguish between Thrush and Swallow. Another may need to go
further and distinguish Goose from Gander. Still another may just
use Bird, with a single parameter describing how much damage it does
when sucked into an aircraft engine. The features chosen for modeling
have more to do with the nature of the model than with the true nature
(whatever *that* is) of the thing modeled.

This is all true. But I'll wager that rarely - maybe even very rarely -
do you really benefit from trying to capture any of those distinguishing
features in an inheritance tree. Not just for this Bird example but for
a whole bunch of other examples.

My main point would be that a real-world taxonomy is not often modelled
best with a programming taxonomy implemented with traditional
inheritance. For a variety of reasons.

AHS
 

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

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,529
Members
45,001
Latest member
Kendra00E1

Latest Threads

Top