Java 对象赋值是什么意思?

What does Java object assignment mean?

我有以下 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: static -- 4”? 我的理解是这样的:

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

但好像不是这样,为什么?

原因是 Java 根据引用变量本身的类型解析静态方法,而不是像实例方法那样在 运行 时以多态方式解析。

稍微扩展一下,当您执行 Animal myAnimal = myCat 时,您正在将 Cat 引用分配给 Animal 引用。这是可以接受的,因为 Cat 也是 Animal,所以 Animal 可以做的任何事情,Cat 也可以做。

此外,如果您通过myAnimal引用调用实例(即非静态)方法,并且该方法在Cat中被覆盖,那么Cat版本的该方法被调用,因为这就是该方法首先被覆盖的原因。另一方面,静态方法永远不会被覆盖。这就是为什么它们是 "static",如 "non-dynamic"。这意味着静态方法可以由编译器解析,而不必依赖 运行time 环境。

您将 myAnimal 声明为 Animal。因此,也从 class 调用了一个静态方法。

切勿从实例调用静态方法(或访问静态字段)以防止此类混淆。

来自Oracle docs

8.4.8.2. Hiding (by Class Methods)

If a class C declares or inherits a static method m, then m is said to hide any method m', where the signature of m is a subsignature (§8.4.2) of the signature of m', in the superclasses and superinterfaces of C that would otherwise be accessible to code in C.

Example 8.4.8.2-1. Invocation of Hidden Class Methods

A class (static) method that is hidden can be invoked by using a reference whose type is the class that actually contains the declaration of the method. In this respect, hiding of static methods is different from overriding of instance methods. The example:

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

produces the output:

Goodnight, Dick

because the invocation of greeting uses the type of s, namely Super, to figure out, at compile time, which class method to invoke, whereas the invocation of name uses the class of s, namely Sub, to figure out, at run time, which instance method to invoke.

Static 的确切含义是:调用是静态解析的(在您的情况下,它是根据 variable[=18= 的声明类型解析的) ], 变量是一个编译时实体).

您预期的结果需要动态解析调用(多态,基于引用实例的实际类型,并且该实例是运行时实体)。

当您设置 myAnimal = myCat 时,指针 myAnimal 指向一个 cat 对象,但是当您尝试通过 myAnimal 指针访问静态方法时,它访问来自声明 myAnimal 的 class 的静态方法作为.