简体   繁体   English

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

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

Why does the following Java code produces: 为什么以下Java代码会产生:

10
superclass

The code in question is: 有问题的代码是:

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

There is no instance of SuperClass ever created, isn't there? 没有创建SuperClass实例,不是吗? Not only that Java starts looking for the method to invoke from the SuperClass , it even somehow knows that a = 10 ! 不仅Java开始寻找从SuperClass调用的方法,它甚至以某种方式知道a = 10

Let's consider a similar Python code: 让我们考虑类似的Python代码:

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

It works as I expect: 它按预期工作:

20
subclass

The only explanation that my colleagues (Python disliking Java folks) came up with is: "Python is not a true OOP language". 我的同事(Python不喜欢Java人员)提出的唯一解释是:“Python不是真正的OOP语言”。 Not very convincing at all. 根本不是很有说服力。

Update: private void another_print() is my blunder, I should have used protected . 更新: private void another_print()是我的错误,我应该使用protected

In the sub-class's print you just call super-class's print method. 在子类的打印中,您只需调用超类的打印方法。 So it prints the a from the super class of course. 所以它当然从超级类打印出来的。

You have two separate a fields here. 这里有两个单独字段。 Fields are not subject to overriding, only methods are. 字段不受覆盖,只有方法。 The super-class has an a field and you have another a field in the sub-class. 超类有一个字段 ,你有另一个在子类中的字段。

If another language produces another result, that's not a big surprise. 如果另一种语言产生另一种结果,那不是一个大惊喜。 Also, I am not sure your Python code is logically equivalent/analogous to your Java code. 此外,我不确定您的Python代码在逻辑上是否等同于/类似于您的Java代码。

It is the order of constructor calling in Java. 它是用Java调用的构造函数的顺序。
In the SubClass , when you instantiate c , the constructor implicitly calls the default constructor of the SuperClass ( public SuperClass() ) (it must do so). SubClass ,当您实例化c ,构造函数隐式调用SuperClass的默认构造SuperClasspublic SuperClass() )(它必须这样做)。 Then a is set to be 10 in the SuperClass . 然后在SuperClass a设置为10。

Now that we're done with the SuperClass constructor, we get back to the constructor of SubClass , which assigns a = 20 . 现在我们已经完成了SuperClass构造函数,我们回到SubClass的构造函数,它指定a = 20 But fields are not subject to overriding in java, so a in SuperClass is still 10. 但字段不受制于Java的重写,所以aSuperClass仍是10。

After that it's pretty obvious, we call c.print() which calls the print of SubClass , which calls the print of SuperClass (by super.print() ), which prints a which is as you remember 10. Then another_print (which is not overridden since it is private ) just prints superclass and we're done. 之后很明显,我们调用c.print()来调用SubClassprint ,它调用SuperClassprint (通过super.print() ),打印a你记得的10。然后是another_print (这是没有被覆盖,因为它是private )只是打印superclass ,我们已经完成。

My comment explained the reason your code probably doesn't work as expected. 我的评论解释了您的代码可能无法按预期工作的原因。 Below is code written how you most likely expected it to work. 下面是代码,写下你最有可能期望它如何工作。 Note the comments in the code. 请注意代码中的注释。

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

This will print 这将打印

20
subclass

I've debugged my slightly corrected code and found out that: 我调试了稍微纠正过的代码并发现:

  1. this is an instance of SubClass thisSubClass一个实例
  2. Unlike Python, Java is ok with more than one variable of the same name (as peter.petrov mentioned in his answer , but I didn't got it right away) 与Python不同,Java可以使用多个同名变量(如他的答案中提到的peter.petrov,但我没有马上得到它)
  3. One of the a s is from the SubClass and the second is from the SuperClass (as implicit superclass constructor call, again unlike Python) 其中a来自SubClass ,第二个来自SuperClass (作为隐式超类构造函数调用,再次与Python不同)
  4. this.a has a different value in test_super() and test_sub() and that is the magic, given that this is a SubClass and Java documentation reads: this.a有不同的值test_super()test_sub()这是神奇的,因为this是一个SubClass和Java文件内容如下:

this is a reference to the current object — the object whose method or constructor is being called this是对当前对象的引用 - 正在调用其方法或构造函数的对象

I think I can live with the fact that this will have all the variables from the whole dependency tree and Java will select which one to use depending on the context. 我认为我可以忍受这样一个事实: this将包含整个依赖树的所有变量,Java将根据上下文选择使用哪一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM