JAVA中的动态实例化优势

时间:2015-02-16 20:38:32

标签: java polymorphism

我有2节课。动物和马。动物是超级类,马延伸动物。

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");
    }
}

从另一个班级,我正在对这些班级做一些功能。

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

    }
}

理论上,aa.tail(),虽然它编译仍然是一个Animal类型,这就是它抛出错误的原因,因为它无法看到该方法。但是,在运行期间,它被实例化为一匹马,它应该有能力利用马法。

如果没有,宣布

的重点是什么
Animal aa = new Horse();

这样做有什么好处?

3 个答案:

答案 0 :(得分:0)

  

但是,在运行期间,它被实例化为一匹马,它应该有能力利用马法。

如果在运行时,您的代码感觉就像这样,它仍然可以将实例强制转换为

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

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

编译器不能假定Animal引用指向Horse实例,因此将aa.tail()标记为错误。

  

这样做有什么好处?

多态性,如您自己的代码所示

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

答案 1 :(得分:0)

对象Horse

参考类型为Animal

编译器不会尝试预测稍后,在运行时,Animal引用将指向Horse实例。

尽可能使用超类动物类型的一个优点是,它使代码与其他种类的动物更加可重复使用

答案 2 :(得分:0)

声明Animal aa = new Horse();不仅存在于类或子类中;它也存在于接口中:

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

使用语法的优点取决于你的左手课程。

如果你正在使用纯继承,那么只要在父类中定义了方法,并且父类被视为引用(在这种情况下,它是Animal),那么您将从virtual method invocation中受益,Java将使用正确的方法为分配给引用的正确实例。

如果你有不同类型的动物,并且Animal类有tail方法,而所有其他类都覆盖tail,那么子类'tail将使用方法而不是父类。

如果你在LHS上有一个接口,那么你就符合接口的编译时合同。您只是声明,只要使用的任何实现符合我关注的接口,特定于实现的部分就不那么重要了。

正式地,规则在JLS section 15.12.2.1中详细说明:

  

由编译时步骤1(第15.12.1节)确定的类或接口是   搜索了可能适用的所有成员方法   这个方法调用;成员继承自超类和   超级接口包含在此搜索中。

     

另外,如果方法调用在左边之前   括号,形式为Identifier的MethodName,然后是搜索   进程还检查(a)导入的所有成员方法   单静态导入声明(第7.5.3节)和静态导入按需   声明(第7.5.4节)在编制单位(第7.3节)内   发生方法调用,并且(b)没有阴影(§6.4.1)   出现方法调用的位置,以确定它们是否存在   可能适用。

     

如果成员方法可能适用进行方法调用   并且只有满足以下所有条件:

     
      
  • 该成员的名称与方法调用中方法的名称相同。

  •   
  • 成员可以访问(§6.6)类方法调用所在的类或接口。    是否可以在方法调用中访问成员方法取决于访问修饰符(public,none,protected或private)   在成员的声明和方法调用的位置   出现。

  •   
  • 如果成员是arity n的变量arity方法,则方法调用的arity大于或等于n-1。

  •   
  • 如果成员是具有arity n的固定arity方法,则方法调用的arity等于n。

  •   
  • 如果方法调用包含显式类型参数,并且该成员是泛型方法,则类型参数的数量相等   到方法的类型参数的数量。

  •   
     

如果搜索没有产生至少一个可能适用的方法,则会发生编译时错误。