我有以下2个课程:

class Animal {
    public static void staticMethod(int i) {
        System.out.println("Animal : static -- " + i);
    }

    public void instanceMethod(int i) {
        System.out.println("Animal : instance -- " + i);
    }
}

class Cat extends Animal {
    public static void staticMethod(int i) {
        System.out.println("Cat : static -- " + i);
    }

    public void instanceMethod(int i) {
        System.out.println("Cat : instance -- " + i);
    }

    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.staticMethod(1);                       // Cat : static -- 1
        myCat.instanceMethod(2);                     // Cat : instance -- 2
        System.out.println("");

        Animal myAnimal = myCat;
        Animal.staticMethod(3);                      // Animal : static -- 3
        myAnimal.staticMethod(4);                    // Animal : static -- 4 [ ? ]
        System.out.println("");

        myAnimal.instanceMethod(5);                  // Cat : instance -- 5
    }
}

当我运行Cat时,得到以下结果:
Cat : static -- 1
Cat : instance -- 2

Animal : static -- 3
Animal : static -- 4

Cat : instance -- 5

我可以理解1,2,3和5,但是为什么#4不是:“Cat:静态-4”?
我的理解是这样的:

myAnimal = myCat表示“myAnimal”现在与“myCat”完全相同,因此在任何“myAnimal”豌豆中,您都可以将其替换为“myCat”,并获得相同的结果,因为myAnimal中的所有内容都与myCat中的所有内容相同,因此,“myAnimal.staticMethod(4)”应与“myCat.staticMethod(4)”相同,输出应为:“Cat:static-4”,与上述“myCat.staticMethod(1)”类似。

但是,事实并非如此,为什么?

最佳答案

Oracle docs:

8.4.8.2。隐藏(按类方法)

如果类C声明或继承了静态方法m,则称m为
隐藏任何方法m',其中m的签名是子签名
的超类中m'的签名(第8.4.2节)
C的超级接口,否则C中的代码将可以访问它们。

示例8.4.8.2-1。调用隐藏类方法

隐藏的类(静态)方法可以使用
类型为实际上包含以下内容的类的引用
方法的声明。在这方面,隐藏静态方法
与重写实例方法不同。这个例子:

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());
            }
        }

产生输出:

晚安,迪克

因为Greeting的调用使用s的类型,即Super,
在编译时找出要调用的类方法,而
名称的调用使用s的类(即Sub)来确定,
在运行时,调用哪个实例方法。

07-24 14:09