2

这个问题已经提出来讨论与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
    }
}

有人可以解释一下子方法如何在这里隐藏父方法吗?(使用父引用调用父方法,那么隐藏是如何出现的)

4

4 回答 4

1

子方法是怎么把父方法隐藏在这里的?

正如您所说,通过定义具有相同签名的静态方法。

隐藏是如何进入画面的?

Cat.testClassMethod();

有些人可能期望在这里调用父方法(通过类比多态)。但是通过类方法隐藏的想法是不同的:

如果类 C 声明或继承静态方法 m,则称 m 隐藏任何方法 m',其中 m 的签名是 m' 签名的子签名(第 8.4.2 节),位于C 中的代码可以访问(第 6.6 节)的 C
。...
可以通过使用限定名称或使用包含关键字 super 或强制转换为 a 的方法调用表达式(第 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

现在我们要添加testClassMethodCat.

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();
    }
}
于 2018-04-28T08:24:47.707 回答
1

这确切地说明了为什么打算隐藏静态方法是一种不好的做法。该方法是在编译时静态选择的,不考虑实际的实例类型。

我想带回家的短语应该是“隐藏不是覆盖......并且不要这样做,这意味着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怎么办? 使用该Animal方法,所有这些调用仍然有效,这意味着:

  • 隐藏静态方法是一种非常糟糕的做法
  • 使用类实例调用静态方法同样不好,因为在隐藏方法的情况下,很容易被误导......

回答这个问题:隐藏用Cat.testClassMethod()or来说明,它根据声明的类型myCat.testClassMethod()调用静态方法。当没有testClassMethod()in 时Cat,Java 调用父级的。

于 2018-04-28T08:25:42.887 回答
0

所有最终的、静态的和私有的方法和变量都使用静态绑定并由编译器绑定。静态绑定使用类型信息进行绑定(在本例中为 Animal)。

因此,在您的情况下myAnimal.testClassMethod();将打印静态方法,Animal因为声明的类型是Animal.

于 2018-04-28T08:19:07.280 回答
0

静态方法不参与动态绑定(多态性)。

静态方法不会被覆盖,静态方法被子类隐藏。

打电话Cat.testClassMethod()的人可能会期待Animal.testClassMethod()

Cat.testClassMethod()隐藏也是如此Animal.testClassMethod()

于 2018-04-28T08:22:27.823 回答