Dynamic instantiation advantages in JAVA

冷暖自知 提交于 2019-12-25 05:31:59

问题


I have 2 classes. Animal and Horse. Animal is the super class, horse extends animal.

public class Animal 
{
    public void legs()
    {
        System.out.println(this + " Some animals can have 3 legs, some have 4");
    }
}

public class Horse extends Animal
{
    public void legs()
    {
        System.out.println(this + " Horses always have 4 legs");
    }

    public void tail()
    {
        System.out.println("A horse definitely has a tail");
    }
}

From another class, I am doing some functions on these classes.

public class SCJP_Practice
{
    public static void main (String args[])
    {
        Animal a = new Animal();
        Horse h = new Horse();

        a.legs();
        h.legs();

        Animal aa = new Horse();
        aa.legs(); // THIS PRINTS THE HORSE VERSION OF LEGS() AND RIGHTLY SO
        aa.tail(); // THIS IS THROWING A COMPILATION ERROR

    }
}

Theoretically, aa.tail(), while it compiles is still an Animal type, which is why it throws an error, since it can't see the method. But, during run time, it is instantiated as a horse, and it should have the ability to take advantage of the horse method.

If not, what is the point in declaring

Animal aa = new Horse();

What are the advantages of doing this?


回答1:


The declaration Animal aa = new Horse(); doesn't just exist for classes or subclasses; it also exists for interfaces, too:

List<Animal> animalPen = new LinkedList<>();

The advantages of using the syntax depend on what your left-hand class are.

If you're using pure inheritance, then so long as the method is defined in the parent class, and the parent class is treated as the reference (in this case, it'd be Animal), then you would benefit from virtual method invocation, and Java would use the right method for the right instance assigned to the reference.

If you had different types of animals, and the Animal class had a tail method, and all of those other classes override tail, then the subclasses' tail method would be used instead of the parent class.

If you've got an interface on the LHS, then you're conforming to the interface's compile-time contract. You're stating that, so long as whatever implementation is used conforms to the interface I care about, the implementation-specific portions aren't as crucial.

Formally, the rules are spelled out in the JLS, section 15.12.2.1:

The class or interface determined by compile-time step 1 (§15.12.1) is searched for all member methods that are potentially applicable to this method invocation; members inherited from superclasses and superinterfaces are included in this search.

In addition, if the method invocation has, before the left parenthesis, a MethodName of the form Identifier, then the search process also examines all member methods that are (a) imported by single-static-import declarations (§7.5.3) and static-import-on-demand declarations (§7.5.4) within the compilation unit (§7.3) within which the method invocation occurs, and (b) not shadowed (§6.4.1) at the place where the method invocation appears, to determine if they are potentially applicable.

A member method is potentially applicable to a method invocation if and only if all of the following are true:

  • The name of the member is identical to the name of the method in the method invocation.

  • The member is accessible (§6.6) to the class or interface in which the method invocation appears. Whether a member method is accessible at a method invocation depends on the access modifier (public, none, protected, or private) in the member's declaration and on where the method invocation appears.

  • If the member is a variable arity method with arity n, the arity of the method invocation is greater or equal to n-1.

  • If the member is a fixed arity method with arity n, the arity of the method invocation is equal to n.

  • If the method invocation includes explicit type arguments, and the member is a generic method, then the number of type arguments is equal to the number of type parameters of the method.

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs.




回答2:


But, during run time, it is instantiated as a horse, and it should have the ability to take advantage of the horse method.

If at runtime, your code feels like doing so, it can still typecast the instance as

Animal aa = new Horse(); // or, received as an argument

if (aa instanceof Horse) {
  // Let's do Horse things
  Horse hh = (Horse) aa;
  hh.tail();
}

Compiler can't assume that an Animal reference would point to Horse instance and hence flags aa.tail() as an error.

What are the advantages of doing this?

Polymorphism, as demonstrated by your own code

aa.legs(); // prints the Horse version



回答3:


The object is a Horse.

The reference type is Animal.

The compiler doesn't try to predict that later, at runtime, the Animal reference will be pointing to a Horse instance.

One advantage of using the superclass Animal type wherever possible, is that it makes code more re-usable with other kinds of animals.



来源:https://stackoverflow.com/questions/28549912/dynamic-instantiation-advantages-in-java

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