【问题标题】:In Java, what does 'this' indicate in a superclass method called on a subclass that inherits that method?在Java中,“this”在继承该方法的子类上调用的超类方法中表示什么?
【发布时间】:2021-02-11 16:56:57
【问题描述】:

代码是这样的:

class Main {  
  public static void main(String args[]) { 
        Person p1 = new Student();
        Person p3 = new Teacher();
        Student p4 = new Student();
        OnlineLecture lec3 = new OnlineLecture();
        
        lec3.addAttendant(p1);
        lec3.addAttendant(p3);
        lec3.addAttendant(p4);
  }
}


abstract class Person {
    public void join(Lecture lec) { 
        System.out.println("Joining "+lec);
    }
    public void join(OnlineLecture lec) {
        System.out.println("Joining "+lec);
    }
}

class Student extends Person {
    public void join(Lecture lec) {
        System.out.println("Student joining "+lec);
    }
}

class Teacher extends Person {
    public void join(OnlineLecture lec) {
        System.out.println("Teacher joining "+lec);
    }
}
    
class Lecture {
    public void addAttendant(Person p) {
        p.join(this);
    }
    public String toString() {
        return "a lecture";
    }
}

class OnlineLecture extends Lecture {
    public String toString() {
        return "an online lecture";
    }
}

我不明白为什么我得到的输出是这样的:

Student joining an online lecture
Joining an online lecture
Student joining an online lecture

不应该在 lec3 上调用的 'addAttendant' 方法中的 'join(this)' 导致 'join(OnlineLecture lec3)',因此给出这个

Joining an online lecture
Teacher joining an online lecture
Joining an online lecture

作为输出?

【问题讨论】:

标签: java this subclass superclass


【解决方案1】:

多态性和重载

多态性

  1. 在调用 reference.method() 时会表现出多态性
  2. 这本质上是一种基于reference 引用的实际object 类型的动态行为
  3. 这就是查找表(如 c++ 中的 vmt)发挥作用的地方
  4. 根据引用指向的对象,运行时将决定要调用的实际方法

重载

  1. 编译时决策中的方法重载
  2. 方法的签名在编译时固定
  3. 对于基于方法的参数类型表现出的任何多态性,都不需要运行时查找
  4. 参数只是上下文中方法的参数,它不关心类型表现出的多态性

当前示例中发生了什么?

    static class Lecture {
        public void addAttendant(Person p) {
            p.join(this);
        }
    }
  1. 假设有一个 Lecture 的子类覆盖 addAttendant,那么当有人在 Lecture 或其 @ 之一的引用类型上调用方法时,多态性可以根据 object 类型控制将调用哪个方法987654328@.
  2. 但是,对于任何最终将到达Lecture.addAttendant 的调用,匹配p.join(this) 的方法签名是join(Lecture)(即使p 可以被动态引用)。即使this 引用的对象可能是多态类型,这里也没有多态性。

【讨论】:

  • 那么您的意思是,如果该方法是继承方法(未覆盖),那么this 是否被视为超类的实例?因为这就是我认为在 lec3.addAttendant 中调用 p.join(this) 时正在发生的事情,作为 lec3 一个 OnlineLecture。
  • this 作为参数的解析完全依赖于方法的参考框架,在这种情况下,运行时解析的方法在 Lecture 类内部,因此它与实现的方法匹配由p(或其任何子类 - 在p 上使用多态性)匹配具有Lecture 签名的方法。
  • 非常感谢。这是否意味着PersonTeacher 类的join(OnlineLecture) 永远不会被调用,因为OnlineLectureLecture 继承addAttendant,而this 将永远是Lecture
  • 是的。如果您需要调用join(OnlineLecture),则覆盖OnlineLecture 上的addAttendant 方法。
  • 你是绝对正确的。 (可能文字略有变化,this at that point would be referring to OnlineLecture - this will be statically linked to OnlineLecture when used as the parameter inside the OnlineLecture instance)。同样,您的理解是正确的,英语不是我的第一语言。所以我假设,我们在这里的意思是一样的。
【解决方案2】:
  • addAttendant方法内部,thisp.join(this)内部是持有Lecture类,因为在子类中没有addAttendant的实现。因此,它调用join(Lecture lec) 方法。它会忽略 OnlineLecture 行为。
class Lecture {
    public void addAttendant(Person p) {
        p.join(this);
    }
}

解决这种模棱两可行为的一种方法,在 OnlineLecture 子类中实现 @Override 方法 addAttendant(Person p)

public class InheritanceProblem {

    public static void main(String args[]) {
        Person p1 = new Student();
        Person p3 = new Teacher();
        Student p4 = new Student();
        OnlineLecture lec3 = new OnlineLecture();

        lec3.addAttendant(p1);
        lec3.addAttendant(p3);
        lec3.addAttendant(p4);
    }
}

abstract class Person {
    public void join(Lecture lec) {
        System.out.println("Joining " + lec);
    }

    public void join(OnlineLecture lec) {
        System.out.println("Joining " + lec);
    }
}

class Student extends Person {
    public void join(Lecture lec) {
        System.out.println("Student joining " + lec);
    }
}

class Teacher extends Person {
    public void join(OnlineLecture lec) {
        System.out.println("Teacher joining " + lec);
    }
}

class Lecture {
    public void addAttendant(Person p) {
        p.join(this);
    }

    public String toString() {
        return "a lecture";
    }
}

class OnlineLecture extends Lecture {
    @Override
    public void addAttendant(Person p) {
        p.join(this);
    }

    public String toString() {
        return "an online lecture";
    }
}

输出:

Joining an online lecture
Teacher joining an online lecture
Joining an online lecture

【讨论】:

  • 我发布的代码实际上不是我写的,我被要求考虑一下并告诉输出会是什么。我仍然不明白为什么p.join(this)this 是 OnlineLecture 时仍然采用带有 Lecture 参数的join 方法。
  • 我更新了我的答案,尝试解释这种情况。感谢您的精彩询问。
猜你喜欢
  • 1970-01-01
  • 2011-10-17
  • 2021-05-04
  • 1970-01-01
  • 2018-01-05
  • 2014-05-27
  • 1970-01-01
  • 2012-05-11
  • 2015-01-14
相关资源
最近更新 更多