在 Java 中,“this”在继承该方法的子类上调用的超类方法中表示什么? 多态性重载

问题描述

代码是这样的:

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

作为输出

解决方法

多态与重载

多态性

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

重载

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

当前示例中发生了什么?

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