关于oop:Java` this`在继承情况下实际指的是什么?

What does Java `this` actually refer to in an inheritance situation?

为什么下面的Java代码产生:

1
2
10
superclass

问题代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class SuperClass {
    int a;

    public SuperClass() {
        this.a = 10;
    }

    private void another_print() {
        System.out.println("superclass");
    }

    public void print() {
        System.out.println(this.a);
        this.another_print();
    }
}

class SubClass extends SuperClass {
    int a;

    public SubClass() {
        this.a = 20;
    }

    private void another_print() {
        System.out.println("subclass");
    }

    public void print() {
        super.print();
    }
}

public class Main {
    public static void main (String[] args) {
        SubClass c = new SubClass();
        c.print();
    }
}

没有创建过SuperClass的实例,不是吗?不仅Java开始寻找从EDCOX1的0调用中调用的方法,它甚至知道EDCOX1是2的!

让我们考虑一个类似的python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SuperClass:
    def __init__(self):
        self.a = 10

    def another_prn(self):
        print('superclass')

    def prn(self):
        print(self.a)
        self.another_prn()

class SubClass(SuperClass):
    def __init__(self):
        self.a = 20

    def another_prn(self):
        print('subclass')

    def prn(self):
        super().prn()

c = SubClass()
c.prn()

它按我的预期工作:

1
2
20
subclass

我的同事(Python不喜欢Java人)提出的唯一解释是:"Python不是真正的OOP语言"。一点也不令人信服。

更新:private void another_print()是我的错误,我应该使用protected


它是Java中构造函数调用的顺序。在SubClass中,当实例化c时,构造函数隐式调用SuperClass的默认构造函数(public SuperClass()(必须这样做)。然后在SuperClass中,a设为10。

现在我们已经完成了SuperClass构造函数的使用,我们回到SubClass的构造函数,它分配a = 20。但是,在Java中,字段不受重写,所以EDOCX1×4在EDCOX1×2中仍然是10。

很明显,我们称之为c.print(),它称为SubClassprint,它称为SuperClassprint(由super.print()),它打印a,如你所记得的10。然后,another_print(因为它是private)只打印SuperClass,我们就完成了。


在子类的print中,您只需调用super类的print方法。当然,它是从超级班打印A的。

这里有两个独立的A字段。字段不受重写的约束,只有方法受重写。超级类有一个A字段,子类中有另一个A字段。

如果另一种语言产生了另一种结果,那不是什么大惊喜。此外,我不确定您的Python代码在逻辑上等同于/类似于Java代码。


我的评论解释了您的代码可能无法按预期工作的原因。下面是您最有可能期望它工作的代码。注意代码中的注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
static class SuperClass {
    int a; // only declare field in superclass to avoid hiding

    public SuperClass() {
        this.a = 10;
    }

    // make method protected, public, or package private to allow children to override it
    protected void another_print() {
        System.out.println("superclass");
    }

    public void print() {
        System.out.println(this.a);
        this.another_print();
    }
}

static class SubClass extends SuperClass {
    public SubClass() {
        this.a = 20;
    }

    @Override
    protected void another_print() {
        System.out.println("subclass");
    }

    public void print() {
        super.print();
    }
}


public static void main (String[] args) {
    SubClass c = new SubClass();
    c.print();
}

这将打印

1
2
20
subclass


我调试了稍微更正的代码,发现:

  • thisSubClass的实例。
  • 与Python不同的是,Java有一个以上的同名变量(就像彼得.彼得罗夫在他的回答中提到的那样,但是我没有马上得到它)。
  • 其中一个as来自SubClass,另一个来自SuperClass(作为隐式超类构造函数调用,与python不同)
  • EDOCX1·26的EDCX1,27,EDCX1,28的值不同,这是神奇的,因为EDCOX1,21,21是EDCOX1,0,Java文档读到:
  • this is a reference to the current object — the object whose method or constructor is being called

    我想我可以接受这样一个事实:EDCOX1×21将拥有整个依赖树的所有变量,而Java将根据上下文选择使用哪一个。