我有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();
这样做有什么好处?
答案 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。
如果方法调用包含显式类型参数,并且该成员是泛型方法,则类型参数的数量相等 到方法的类型参数的数量。
如果搜索没有产生至少一个可能适用的方法,则会发生编译时错误。