Joseph hooper
Joseph hooper

Reputation: 1067

Java Polymorphism/Casting/Methods

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() {}
}
  1. I can never instantiate Console directly because it's abstract
  2. I can however instantiate console as an xbox

    Console fav = new Xbox();

  3. 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?

  4. 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?

  5. 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

Answers (5)

T.Gounelle
T.Gounelle

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

Robert Moskal
Robert Moskal

Reputation: 22553

  1. Yes, if you call the play method on XBox and it is not there, it will call the method in the base class.

  2. 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.

  3. 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

JB Nizet
JB Nizet

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 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?

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 run fav.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

Peter Uhnak
Peter Uhnak

Reputation: 10217

You need differentiate two things

  1. Static type

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.

  1. Dynamic type

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

James Wierzba
James Wierzba

Reputation: 17568

  1. Yes, if you have overridden play() in Xbox, then it will be called, otherwise it will use the default implementation in the abstract class.

  2. 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

  3. No

Upvotes: 0

Related Questions