提问者:小点点

java中方法隐藏概念中术语“隐藏”的意义是什么?[副本]


这个问题是围绕与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
    }
}

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


共3个答案

匿名用户

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

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

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

要回答这个问题:隐藏用< 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