可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Possible Duplicate:
What does Base b2 = new Child(); signify?
I'm a Java beginner. I understand the concepts of class inheritance, but there's one thing I don't quite understand. I'm reading through Java for Dummies, and it's explaining polymorphism. It gives this code as an example:
class Player {
public void move() {...
class BetterPlayer extends Player {
public void move() {...
public class TicTacToeApp {
public static void main(String[] args) {
Player p1 = new Player();
Player p2 = new BetterPlayer();
playTheGame(p1, p2);
}
public static void playTheGame(Player p1, Player p2) {
p1.move();
p2.move();
}
}
Why was p2 created as a Player object? Here's my understanding:
If p2 were a BetterPlayer object (declared like this: BetterPlayer p2 = new BetterPlayer...):
-upcasting is automatic, so it would still work with the playTheGame method
-p2 can be used by any methods requiring a BetterPlayer object
But since it was created as a Player object, now any time p2 is used by a method requiring a BetterPlayer object, it must be explicitly cast to a BetterPlayer object, right? That seems like more work with no benefit, so I'm guessing there has to be some benefit to doing it that way; what is it?
回答1:
The variable p2 was not created as a Player object. It's a reference that points to a BetterPlayer object.
Regardless whether p2 is declared as a Player or BetterPlayer reference, it can be used as a Player reference.
An advantage of declaring it as a Player is that you are prevented from coupling any code that works only with BetterPlayer, keeping open the option of using the code for another subclass option in the future -- e.g., BestPlayer.
回答2:
Any Player can, logically speaking, play the game (that's what makes the Player a player); so playTheGame should not care that the Player is a BetterPlayer. The advantage of polymorphism is exactly that playTheGame is not forced to care about something that it shouldn't care about.
We don't cause a real problem by assigning the BetterPlayer to a Player variable (p2) because if we knew we were going to call a bunch of functions that required a BetterPlayer specifically, then we simply wouldn't do that. "Doctor, it hurts when I tell the type system to forget things that actually are important." In the current case, it isn't important, so we have no problem throwing away the specific type information.
But further, even if we declared p2 to be a BetterPlayer, we could still pass it to playTheGame without writing any casts. The upcast when calling the function would be implicit, and inside the function we don't need to downcast because we don't care if we have a BetterPlayer - since we're only using the base Player interface. And then again, a lot of the time (including in the current code) we don't need a variable at all in the first place, so it matters even less what the types are. playTheGame(new Player(), new BetterPlayer())
works just fine.
回答3:
The book declared p2 as a Player only for illustrative purposes. It could be declared a BetterPlayer and the program would perform exactly the same. they wanted to show that a BetterPlayer could be assigned to a variable of type Player.
回答4:
The key is that a BetterPlayer
can be passed to playTheGame()
as if it were a Player
. When playTheGame()
calls p2.Move()
, it calls the function BetterPlayer.move()
, not Player.move()
.
This means that you can come up with any subclass of Player
and it will work fine in playTheGame()
without doing any change whatsoever to playTheGame()
. This means that you can create whatever Player
subclass you like, with whatever .move()
behavior you like, and playTheGame()
will work fine with it.
For one thing, you are having old code call new code without any change in the old code, and this can be important.
For another, you're providing a way to plug in anything that's a Player
to some pre-existing code, and therefore providing an abstraction barrier. playTheGame()
not only doesn't have to know anything about Player
, it doesn't have to insist on it being called with a Player
.
回答5:
Subclasses have an IS-A relationship to superclasses. BetterPlayer IS-A Player.
For your first question about 'upcasting' your wording is flawed. You can pass p2 into the method because it takes a Player, and BetterPlayer IS-A Player.
For your second question, yes.
For your third question, you are again correct. You can just define p2 as a BetterPlayer to start with though, and then you can use it anywhere you need a Player, and anywhere you need a BetterPlayer.
回答6:
The advantage is that p1.move()
and p2.move()
call different functions, without playTheGame
having to do something like this (in pseudocode as my Java is rusty):
if (p1 is Player)
call Player.move(p1)
else if (p1 is BetterPlayer)
call BetterPlayer.move(p1)
if (p2 is Player)
call Player.move(p2)
else if (p2 is BetterPlayer)
call BetterPlayer.move(p2)
回答7:
That's good to make maintaining the code easier - in case you need a StupidPlayer
, you just have to change
Player p2 = new BetterPlayer();
to
Player p2 = new StupidPlayer();
and it's finished. No need to modify other methods.
回答8:
What is the advantage to declaring an object of one type as in instance of another?
In this example, there is no advantage.
A more practical example of polymorphism would be an array of players (Player[]
) or list (List<Player>
) that could contain Players, BetterPlayers, and any other Player subclass.
回答9:
A pretty typical analogy is a system which draws shapes.
You create many different shapes and need to place them on your screen. Writing code to do this without polymorphism is tricky. If all the specific shapes (square, circle, triangle, glu-teapot, whatever) then you can put them in a single array of type Shape and then you can just say something like
foreach Shape s in ArrayOfShapes{
s.draw(); // They all implement draw so it makes our life easy.
}
回答10:
The benefit is that you are able to take advantage of all of the functions / attributes of the parent class in addition to the child class. It's a way of making your code more flexible and as you learn more about the need to create families of objects you'll begin to appreciate the added flexibility provided. For instance, suppose I have a parent class with 5 methods in it, I could create a sub-class or child and add more functionality to the class giving you access to say another 3 more specialized methods. The basic idea is that the child classes should extend the functionality of the parent class enabling you to reuse more code and keep each class shorter and more cohesive. If you want to gain an appreciation for the art of object oriented programming I recommend you take a peek at the GRASP Patterns wiki. It has sufficiently simple code examples that should help you see the value in having classes extend other classes.