Reputation: 1067
Clarifications on this topic. So for examples purposes Say I have:
public interface Gaming {
void play;
}
public abstract class Console implements Gaming {
void play() {}
}
public class Xbox extends Console {
void play() {}
}
public class XboxOne extends Xbox {
void play() {}
}
Console
directly because it's abstract
I can however instantiate console as an xbox
Console fav = new Xbox();
If all of the classes have a defined play()
method. If I call fav.play();
it will look at the Xbox's play method, if it did not have a play method it would continue up the hierarchy until it found that method?
Also if I did ((XboxOne)fav).play()
it would do the XboxOne's play method?, also is it true that I can only cast an object if it's lower in the hierarchy?
If the Xbox
class had a getGamerscore
method but the console didn't, would I
be able to run fav.getGamerScore()
?
General Questions:
The type on the left of the = shows what class (most specific) java will look in when a method is called? (If it cannot find it there it will continue up the hierarchy until it finds the method?)
The type on the right just stands for the compile type. When compiling java will look and see if the method or data belongs to the compile type and if so everything is good? Java will not look at it's compile type anymore when it's running.
Casting just helps get past compile problems? Like if I want to use a certain method but my objects compile type is like an interface or abstract class or something, so I cast so the compiler doesn't complain when I try to access the runtime type's methods?
Please correct me if I've said anything wrong I just want to get all the rules clear in my head. Also if anyone has any helpful resources that would be great.
**I realize I did not use the gaming interface
Upvotes: 4
Views: 2257
Reputation: 6033
I can never instantiate Console directly because it's abstract
you are right, but... let's say Console
is defined as
public abstract class Console implements Gaming {
// no impl. not needed because already declared in Gaming
// just for clarity
public abstract void play();
}
You can instantiate Console
directly with:
Console myAnonymousConsole = new Console() {
public void play() { System.out.println("Hello there"); }
};
I can however instantiate console as an xbox
right again because Xbox
in not abstract
.
Console fav = new Xbox();
If all of the classes have a defined play() method. If I call fav.play(); it will look at the Xbox's play method, if it did not have a play method it would continue up the hierarchy until it found that method?
Yes, in a sense.
Also if I did ((XboxOne)fav).play() it would do the XboxOne's play method?, also is it true that I can only cast an object if it's lower in the hierarchy?
You cannot downcast relative to the actual instance type. You can write (but it smells not good).
Console a = new XBoxOne();
XBox b = (XBox)a; // ok because a is-a Xbox
XBoxOne c = (XBoxOne)a; // ok because a is-a XBoxOne
Console a = new XBox();
XBox b = (XBox)a; // ok because a is-a Xbox
XBoxOne c = (XBoxOne)a; // ko! because a is-not-a XBoxOne
The check is done at runtime. A ClassCastException
is thrown in the second example.
If the Xbox class had a
getGamerscore
method but the console didn't, would I be able to run fav.getGamerScore()?
No if fav
is declared as a Console. You can declare getGameScore()
in Console
though.
General Questions:
The type on the left of the = shows what class (most specific) java will look in when a method is called? (If it cannot find it there it will continue up the hierarchy until it finds the method?)
Not really. You have to think inheritance from the top to the down: when an class extends
another, it inherits all the public
(and protected
) methods/fields. If, for instance, XBoxOne
does not define the play()
method, it _inherits it from XBox
.
Going back to your question, as far as a method is declared in the left type (Console
here), the right method implementation called will be determined by the actual run-type of the instance - this is polymorphism.
public class XBox extends Console {
public void play() { System.out.println("In XBox");
}
public class PS3 extends Console {
public void play() { System.out.println("In PS3");
}
List<Console> consoles = Arrays.asList(new XBoxOne(), new PS3());
for (Console c : consoles) {
c.play(); // polymorphism here
}
prints
In XBox
In PS3
even if the List
see only the Console
type. Note also, the instanciated type of XBoxOne
that inherits the play()
method from XBox
.
The type on the right just stands for the compile type. When compiling java will look and see if the method or data belongs to the compile type and if so everything is good? Java will not look at it's compile type anymore when it's running.
No, see above.
Casting just helps get past compile problems?
Yes, and can be avoided most of the time.
Like if I want to use a certain method but my objects compile type is like an interface or abstract class or something, so I cast so the compiler doesn't complain when I try to access the runtime type's methods?
I think you mixed right and left here, see the comments above
Upvotes: 0
Reputation: 22553
Yes, if you call the play method on XBox and it is not there, it will call the method in the base class.
You would not be able to cast Xbox to a derived class XboxOne. You can only cast up to Console or down to the type of the actual object you created (XBox). If you didn't create an XBox in the first place you would get a runtime ClassCastException.
If XBox getGamerscore, but console did not. You would not be able to call the method if you constructed in as you did. You could call it if getGamerscore was an abstract method of Console.
For some of your general questions. I encourage you to poke around on the internet. But speaking simply, when you do something like this:
Console fav = new Xbox();
You are construct an object of type Xbox and assign to to a variable of type Console. For the purposes of compile time checking, XBox is now a Console and can be passed to a method that expects a Console. Check out this post here:
explicit casting from super class to subclass
Upvotes: 0
Reputation: 692181
I can never instantiate Console directly because it's abstract
Correct
I can however instantiate console as an xbox
Console fav = new Xbox();
Correct
If all of the classes have a defined
play()
method. If I callfav.play();
it will look at the Xbox's play method, if it did not have a play method it would continue up the hierarchy until it found that method?
Correct. That's not how it really happens in reality (it's optimized), but conceptually, you got it right.
Also if I did
((XboxOne)fav).play()
it would do the XboxOne's play method?
Incorrect. The concrete, runtime type of the object reference by fav is XBox
. And a XBox is NOT an XBoxOne. So such a cast would fail with a ClassCastException. You can cast fav
to XBox
, because fav is indeed an XBox
.
also is it true that I can only cast an object if it's lower in the hierarchy?
Not sure what you mean by this. A cast means: "I know that you, the compiler, only know that fav is a Console. But I know better than you, and I'm sure it's in fact an instance of XBox, so please consider that this variable references an XBox, so that I can call methods present in XBox but not in Console. If the runtime proves me wrong, I acept to get a ClassCastException".
If the Xbox class had a
getGamerscore
method but the console didn't, would I be able to runfav.getGamerScore()
?
No, you wouldn't, since the compile time of fav is Console, and Console doesn't have this method. You would have to cast the variable to XBox:
XBox xbox = (XBox) fav;
xbox.getGamerScore();
General Questions:
The type on the left of the = shows what class (most specific) java will look in when a method is called? (If it cannot find it there it will continue up the hierarchy until it finds the method?)
That would be correct if "left" was replaced by "right".
The type on the right just stands for the compile type. When compiling java will look and see if the method or data belongs to the compile type and if so everything is good? Java will not look at it's compile type anymore when it's running.
That would be correct is "right" was replaced by "left".
Casting just helps get past compile problems? Like if I want to use a certain method but my objects compile type is like an interface or abstract class or something, so I cast so the compiler doesn't complain when I try to access the runtime type's methods?
Correct. But you'll get a ClassCastException at runtime if the object is not, actually, an instance of the type you cast to.
Upvotes: 0
Reputation: 10217
You need differentiate two things
This is what is known at the compile time and what will be used for method signature lookup. So if you have Console fav = new Xbox()
, then the static type of fav
will be Console
.
Thus if you try to call fav.play()
, the compiler will look for play
signature in Console
class; if Console
does not support this method, then Java will not even compile it.
This is what the variable will be during runtime, so after you start the program Console fav = new Xbox()
, the dynamic type of fav
will be Xbox
(but static type is still Console
).
Now for your questions
If all of the classes have a defined play method. If I call fav.play(); it will look at the Xbox's play method, if it did not have a play method it would continue up the hierarchy until it found that method?
If by all classes you mean also the base Console
class (at least abstract method), then yes.
Also if I did ((XboxOne)fav).play() it would do the XboxOne's play method?, also is it true that I can only cast an object if it's lower in the hierarchy?
You can always upcast - going from more specific (Xbox
) to more generic (Console
); downcasting is only possible to some extent — if there is a chance it will succeed. So usually downcasting to dynamic type should succeed. (e.g. Console fav = new Xbox()
+ (Xbox)console)
.
If the Xbox class had a getGamerscore method but the console didn't, would I be able to run fav.getGamerScore()?
No, as mentioned earlier; fav
is Console
and thus doesn't know what you mean by getGamerScore
. You can however still do ((XBox) fav).getGamerScore
.
Casting just helps get past compile problems?
Casting can be quite dangerous, because you are making assumptions about the variable.
If you are calling ((XBox) fav).getGamerScore
, then you already know that the type must be Xbox
and having Console fav
may be wrong, because you cannot assign any kind of Console in there.
Upvotes: 3
Reputation: 17568
Yes, if you have overridden play() in Xbox, then it will be called, otherwise it will use the default implementation in the abstract class.
You can't cast Console to XboxOne. However, if you had declared fav to be of type Xbox, then you would be able to cast it as XboxOne
No
Upvotes: 0