Java 为什么这两个代码示例产生不同的输出?
样本1:Java 为什么这两个代码示例产生不同的输出?,java,static,Java,Static,样本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
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调用的是奶牛版本而不是动物版本。我的理解是,
gurr!哞!呜呜无论哪种情况,代码>都将是输出。在动物上调用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();
}
}
哪个打印:
蒙纳多克山
此处favorite返回null,但未引发NullPointerException
资源:
关于同一主题:
您不能覆盖子类中具有相同签名的静态方法,只需隐藏它们即可
对于类方法,运行时系统调用调用该方法的引用的编译时类型中定义的方法。例如方法,运行时系统调用调用方法的引用的运行时类型中定义的方法
一些已知的压倒一切的“陷阱”
- 不能重写静态方法
- 无法重写私有方法
这解释了输出。静态方法绑定到对象的“类”,而不是“实例”。
因为您指的是“动物”并调用静态方法saySomething()。除非您指的是Cow,否则它将始终调用“Animal”。静态方法在编译时绑定到它们的类,不能以多态方式使用。当您在Animal上声明一个“静态”方法时,它将永远绑定到Animal类,并且不能被重写。静态方法绑定到类对象,而不是类的实例
常规方法在运行时绑定,因此JVM可以查看您对“saySomething”的调用,并尝试确定您是否正在传递Animal的子类,如果是,它是否覆盖了saySomething()
方法。常规方法绑定到对象的实例,而不是类本身
这也是为什么你永远无法做到这一点:
class Animal
{
public abstract static void saySomething();
}
因为“static”意味着“在编译时绑定”,所以静态和抽象的东西是没有意义的。我一直不明白为什么Java允许通过对象引用调用静态方法。这是没有必要的,它会导致像这样的混乱。同意。C++也让你做了。我猜这只会让编译器编写者更容易允许这种访问。我在这里试图为这一点辩护:“Java语言规范这么说”就是它的全部内容。首先,为什么允许您从这样的实例引用调用静态方法,这才是真正的奇怪之处。但至少已经有一个庞大的社区维基帖子在上面:)