Java对象赋值是什么意思?

时间:2015-04-28 20:59:17

标签: java object variable-assignment

我有以下两个班级:

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)”上方。

但情况似乎并非如此,为什么?

5 个答案:

答案 0 :(得分:3)

您将myAnimal声明为Animal。因此,也可以从该类调用静态方法。

您永远不应该从实例调用静态方法(或访问静态字段)以防止这种混淆。

答案 1 :(得分:2)

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

要进行扩展,当您执行Animal myAnimal = myCat时,您将为动物参考分配Cat引用。这是可以接受的,因为Cat也是Animal,因此Animal可以做的任何事情,Cat都可以做。

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

答案 2 :(得分:2)

来自Oracle docs

  

<强> 8.4.8.2。隐藏(按类方法)

     

如果一个C类声明或继承静态方法m,那么就说m   隐藏任何方法m',其中m的签名是子签名   (§8.4.2)m'的签名,在超类和   C的超级接口,否则C中的代码可以访问。

     

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

     

可以使用a调用隐藏的类(静态)方法   引用的类型是实际包含的类   声明方法。在这方面,隐藏了静态方法   与覆盖实例方法不同。例子:

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

产生输出:

     晚安,迪克

     

因为问候语的调用使用了s的类型,即Super,   在编译时弄清楚要调用哪个类方法,而   名称的调用使用s的类,即Sub,来弄清楚,   在运行时,调用哪个实例方法。

答案 3 :(得分:1)

静态意味着:静态解析调用(在您的情况下,它是根据变量的声明类型解析的,并且变量是编译的-time实体)。

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

答案 4 :(得分:1)

当你设置myAnimal = myCat时,指针myAnimal指向一个cat对象,但是当你尝试通过myAnimal指针访问静态方法时,它会从myAnimal被声明为的类中访问静态方法。