样本1:
class Animal {
public static void saySomething() { System.out.print(" Gurrr!");
}
}
class Cow extends Animal {
public static void saySomething() {
System.out.print(" Moo!");
}
public static void main(String [] args) {
Animal [] animals = {new Animal(), new Cow()};
for( Animal a : animals) {
a.saySomething();
}
new Cow().saySomething();
}
}
输出是:
Gurrr! Gurrr! Moo!
样本2:
class Animal {
public void saySomething() { System.out.print(" Gurrr!");
}
}
class Cow extends Animal {
public void saySomething() {
System.out.print(" Moo!");
}
public static void main(String [] args) {
Animal [] animals = {new Animal(), new Cow()};
for( Animal a : animals) {
a.saySomething();
}
new Cow().saySomething();
}
}
输出:
Gurrr! Moo! Moo!
我只是不明白为什么使saySomething非静态导致第二次调用saySomething调用Cow版本而不是Animal版本。我的理解是Gurrr! Moo! Moo!
在任何一种情况下都是输出。
答案 0 :(得分:7)
当您在动物身上调用saySomething()
时,动物的实际类型不计算在内,因为saySomething()
是静态的。
Animal cow = new Cow();
cow.saySomething();
与
相同Animal.saySomething();
JLS示例:
当计算目标引用然后因为调用模式是静态而被丢弃时,不会检查引用以查看它是否为null:
class Test { static void mountain() { System.out.println("Monadnock"); } static Test favorite(){ System.out.print("Mount "); return null; } public static void main(String[] args) { favorite().mountain(); }
}
打印:
Mount Monadnock
这里的收藏返回null,但没有抛出NullPointerException。
资源:
关于同一主题:
答案 1 :(得分:3)
你不能在子类中使用相同的签名覆盖静态方法,只需隐藏它们。
对于类方法,运行时系统调用在其上调用方法的编译时类型的引用中定义的方法。对于实例方法,运行时系统调用在调用该方法的运行时类型的引用中定义的方法。
答案 2 :(得分:3)
一些已知的重写“PITFALLS”
这解释了输出。
答案 3 :(得分:1)
静态方法与“类”绑定,而不是对象的“实例”。 因为你指的是“Animal”并且调用静态方法saySomething()。除非你指的是牛,否则它总是会调用“动物”。
答案 4 :(得分:1)
静态方法在编译时绑定到它们的类,不能以多态方式使用。当您在Animal上声明一个“静态”方法时,它将永远绑定到Animal类,并且无法覆盖。静态方法绑定到Class对象,而不是Class的实例。
常规方法在运行时绑定,因此JVM可以查看对“saySomething”的调用,并尝试确定是否传递了Animal的子类,如果是,则覆盖saySomething()
方法。常规方法绑定到对象的实例,而不是绑定到Class本身。
这也是你永远不能这样做的原因:
class Animal
{
public abstract static void saySomething();
}
由于“静态”意味着“在编译时绑定”,因此静态和抽象的东西永远不会有意义。