Using superclass type for subclass instance

丶灬走出姿态 提交于 2021-02-06 03:08:26

问题


I know this question has been asked a lot, but the usual answers are far from satisfying in my view.

given the following class hierarchy:

class SuperClass{}
class SubClass extends SuperClass{}

why does people use this pattern to instantiate SubClass:

SuperClass instance = new SubClass();

instead of this one:

SubClass instance = new SubClass();

Now, the usual answer I see is that this is in order to send instance as an argument to a method that requires an instance of SuperClass like here:

void aFunction(SuperClass param){}

//somewhere else in the code...
...
aFunction(instance);
...

But I can send an instance of SubClass to aFunction regardless of the type of variable that held it! meaning the following code will compile and run with no errors (assuming the previously provided definition of aFunction):

SubClass instance = new SubClass();
aFunction(instance);

In fact, AFAIK variable types are meaningless at runtime. They are used only by the compiler!

Another possible reason to define a variable as SuperClass would be if it had several different subclasses and the variable is supposed to switch it's reference to several of them at runtime, but I for example only saw this happen in class (not super, not sub. just class). Definitly not sufficient to require a general pattern...


回答1:


The main argument for this type of coding is because of the Liskov Substituion Principle, which states that if X is a subtype of type T, then any instance of T should be able to be swapped out with X.

The advantage of this is simple. Let's say we've got a program that has a properties file, that looks like this:

mode="Run"

And your program looks like this:

public void Program
{
    public Mode mode;

    public static void main(String[] args)
    {
        mode = Config.getMode();
        mode.run();
    }
}

So briefly, this program is going to use the config file to define the mode this program is going to boot up in. In the Config class, getMode() might look like this:

public Mode getMode()
{
    String type = getProperty("mode"); // Now equals "Run" in our example.

    switch(type)
    {
       case "Run": return new RunMode();
       case "Halt": return new HaltMode();  
    }
}

Why this wouldn't work otherwise

Now, because you have a reference of type Mode, you can completely change the functionality of your program with simply changing the value of the mode property. If you had public RunMode mode, you would not be able to use this type of functionality.

Why this is a good thing

This pattern has caught on so well because it opens programs up for extensibility. It means that this type of desirable functionality is possible with the smallest amount of changes, should the author desire to implement this kind of functionality. And I mean, come on. You change one word in a config file and completely alter the program flow, without editing a single line of code. That is desirable.




回答2:


In many cases it doesn't really matter but is considered good style. You limit the information provided to users of the reference to what is nessary, i.e. that it is an instance of type SuperClass. It doesn't (and shouldn't) matter whether the variable references an object of type SuperClass or SubClass.

Update:

This also is true for local variables that are never used as a parameter etc. As I said, it often doesn't matter but is considered good style because you might later change the variable to hold a parameter or another sub type of the super type. In that case, if you used the sub type first, your further code (in that single scope, e.g. method) might accidentially rely on the API of one specific sub type and changing the variable to hold another type might break your code.

I'll expand on Chris' example:

Consider you have the following:

RunMode mode = new RunMode();

...

You might now rely on the fact that mode is a RunMode.

However, later you might want to change that line to:

RunMode mode = Config.getMode(); //breaks

Oops, that doesn't compile. Ok, let's change that.

Mode mode = Config.getMode(); 

That line would compile now, but your further code might break, because you accidentially relied to mode being an instance of RunMode. Note that it might compile but could break at runtime or screw your logic.




回答3:


It is called polymorphis and it is superclass reference to a subclass object.

In fact, AFAIK variable types are meaningless at runtime. They are used 
only by the compiler!

Not sure where you read this from. At compile time compiler only know the class of the reference type(so super class in case of polymorphism as you have stated). At runtime java knows the actual type of Object(.getClass()). At compile time java compiler only checks if the invoked method definition is in the class of reference type. Which method to invoke(function overloading) is determined at runtime based on the actual type of the object.

Why polymorphism?

Well google to find more but here is an example. You have a common method draw(Shape s). Now shape can be a Rectangle, a Circle any CustomShape. If you dont use Shape reference in draw() method you will have to create different methods for each type of(subclasses) of shape.




回答4:


SuperClass instance = new SubClass1()

after some lines, you may do instance = new SubClass2();

But if you write, SubClass1 instance = new SubClass1();

after some lines, you can't do instance = new SubClass2()




回答5:


This is from a design point of view, you will have one super class and there can be multiple subclasses where in you want to extend the functionality.

An implementer who will have to write a subclass need only to focus on which methods to override



来源:https://stackoverflow.com/questions/19113285/using-superclass-type-for-subclass-instance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!