这个问题是围绕与java中的静态方法相关联的术语隐藏提出来讨论的。每当在父类和子类中定义了具有相同签名的静态方法时,就说子类方法在父类中隐藏了该方法。我的问题是关于隐藏的用法,因为我们知道静态方法将被类名访问,或者如果我们试图创建一个引用(这是一个坏习惯),方法将基于引用类型被调用。那么隐藏是如何进入画面的呢,以下面的代码为例:
public class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
public class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod(); // prints The static method in Animal
}
}
有人可以解释一下子方法如何在此处隐藏父方法吗?(父方法使用父引用调用,那么隐藏是如何出现的)
这正好说明了为什么隐藏静态方法是一种不好的做法。该方法是在编译时静态选择的,不考虑实际实例类型。
我想带回家的短语应该是“隐藏不是覆盖......并且不要这样做“,这意味着Java甚至不查看对象/实例(只查看声明的类型):
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testClassMethod(); //bad to do, but you can see it uses the declared "Animal" class
Cat.testClassMethod(); //Uses method in Cat
myCat.testClassMethod(); //Uses method in Cat
((Animal) null).testClassMethod(); //Uses Animal method, doesn't look at instance
((Cat) null).testClassMethod(); //Uses Cat method, doesn't look at instance
现在有趣的部分:如果您从Cat
中删除该方法怎么办?所有这些调用仍然有效,使用动物
方法,这意味着:
要回答这个问题:隐藏用< code > cat . testclassmethod()或< code > mycat . testclassmethod()来说明,它们根据声明的类型调用静态方法。当< code>Cat中没有< code>testClassMethod()时,Java调用父类的。
这里子方法是如何隐藏父方法的?
正如您所说,通过定义具有相同签名的静态方法。
隐藏是如何出现的?
Cat.testClassMethod();
有些人可能希望在这里调用父方法(类似于多态性)。但按类方法隐藏的想法不同:
如果类 C 声明或继承了静态方法 m,则称 m 隐藏了任何方法 m',其中 m 的签名是 m' 签名的子签名 (§8.4.2),在 C 的超类和超接口中,否则 C 中的代码可以访问 (§6.6
)。
可以使用限定名或使用包含关键字 super 或转换为超类类型的方法调用表达式 (§15.12) 来访问隐藏方法。
。
class Super {
static String greeting() { return "Goodnight"; }
String name() { return "Richard"; }
}
class Sub extends Super {
static String greeting() { return "Hello"; }
String name() { return "Dick"; }
}
class Test {
public static void main(String[] args) {
Super s = new Sub();
System.out.println(s.greeting() + ", " + s.name()); // Goodnight, Dick
}
}
JLS 10-8.4.8.2。隐藏(按类方法)
这个例子完美地展示了覆盖和隐藏之间的区别。同时,它是一个糟糕的实践演示——在实例上调用静态方法。
我将试图通过提供另一个例子来说明这一点。
由于公共静态方法是继承的
class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
class Cat extends Animal {
public static void main(String[] args) {
// Cat: I don't have own method, probably I inherited it from the parent.
// O, yes. I can call it.
Cat.testClassMethod();
}
}
指纹
The static method in Animal
现在我们要将testClassWay
添加到Cat
。
class Animal {
public static void testClassMethod() {
System.out.println("The static method in Animal");
}
}
class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The static method in Cat");
}
public static void main(String[] args) {
// Cat: I have two version of the method: mine and the inherited one.
// The caller specified my class name, so he wanted my version.
// I will call my method hiding the parent method.
Cat.testClassMethod();
// If he wanted Animal's version, he would write
Animal.testClassMethod();
// or (DON'T DO THIS)
((Animal)new Cat()).testClassMethod();
}
}
所有final、static和private方法和变量都使用静态绑定,并由编译器绑定。静态绑定使用类型信息进行绑定(在本例中为Animal)。
因此,在您的案例中,myAnimal.testClassMethod()
将在Animal
中打印静态方法,因为声明的类型是Animal
。