Reputation: 3887
I'm a little confused exactly about how polymorphism and extending classes etc... works in Java when creating objects from these classes.
I recently had a problem which someone on here helped me resolved (see Not able to access object sub class's variable? (Java / Android)) for background.
I was attempting to create an object like so:
Quad hero = new Hero();
Where Hero was a subclass of Quad();
I had variables in my Hero class which I wasn't above to access.
The solution was to change my object creation to:
Hero hero = new Hero();
doing this, through my hero object, I was able to access all methods and variables in both my Quad and Hero classes.
My question now is - Why is this?
And with this in mind, when would it be useful to use my original method:
Quad hero = new Hero();
That one makes sense to me as Hero is also a quad. I've seen this type of declaration many times in Java code examples, and thought I understood, it but recent events have proved otherwise.
Would be grateful if someone could explain this for me - thanks
Upvotes: 2
Views: 1434
Reputation: 29233
If you store your object in a variable of Quad
then, for all the compiler knows, the object stored in that variable is a Quad
and nothing more. It may be of a subtype, sure, but the compiler has no idea what that subtype is. For all it knows, that subtype will be introducing absolutely zero members to the base type. If the compiler has no guarantee that the object is anything more than a Quad
, then it doesn't want to allow you to do anything more than what it would allow you to do with a Quad
.
Granted, you can see that this variable is only ever assigned a new Hero()
expression. And, granted, you may know that a specific variable will only hold objects of the Hero
type. But this is runtime information that you can deduce in practice. The compiler can't bother to calculate all these scenarios. That's why it has you. If you know that objects stored in that variable will always be of type Hero
, you can go on and express it to the compiler.
One reason the language allows you to cast an object to a super type is because in many occasions you want to pass that object to a method that doesn't have to know about all the possible subtypes of the base class (say, Hero
) but only that the passed object is at least of a base class (say, Quad
). Another typical scenario is when you want to store various objects that are not all of the same specific type (they are not all Hero
), but they all have a common ancestor (they are all Quad
) and you want to do something with them, collectively. In general, then, casting objects to an ancestor class is permitted because it is useful to make objects compatible with their base type in situations where that base type is required.
Upvotes: 2
Reputation: 13831
Declaring the variable type as Quad
, means that the variable also can reference other types of subclasses of Quad
, not only Hero
. And if you pass that reference around, the receiver would only know that it is "some kind of quad", and can't rely on it being a Hero
. Hence, it can not access the fields of the reference that are declared only in the subclass.
As for when to use that kind of assignment, I usually only do it when working with interface types. Like:
public List<SomeObject> doSomething() {
List<SomeObject> result = new ArrayList<>();
// do something
return result;
}
But it's really just a habit.
Upvotes: 2
Reputation: 37843
Assume OtherHero
is also a subclass from Quad
with different behaviour:
This will work fine:
Quad hero = new Hero();
// some code
hero = new OtherHero();
Whereas the following won't compile:
Hero hero = new Hero();
// some code
hero = new OtherHero();
This doesn't seem to be useful. Now assume you have a method, that has Quad
as return type. I'll write it in pseudocode:
Quad method() {
if (condition)
return new Hero();
else
return new OtherHero();
}
So you actually don't know if it will return a Hero
or an OtherHero
Now, you can write:
Quad foo = method();
Now, you actually don't know the exact type of foo
, but you can use it as Quad
.
A popular example is java.util.List
You can write:
List<Integer> list = Arrays.asList(1,2,3,4,5,6);
Collections.shuffle(list);
List
is an interface, implemented by ArrayList
, LinkedList
and many other classes. Without knowing the code, we don't know which class exactly is returned by Arrays.asList()
, but we can use it as a List
.
Upvotes: 4