代码之家  ›  专栏  ›  技术社区  ›  totoro

Java-调用方法时的继承和变量类型

  •  2
  • totoro  · 技术社区  · 8 年前

    我对理解某些代码的结果有很大的疑问。

    public class ClassA {
        public void stampa(ClassA p) {
            System.out.println("AAA");
        }
    }
    public class ClassB extends ClassA {
        public void stampa(ClassB p) {
            System.out.println("BBB");
        }
        public void stampa(ClassA p) {
            System.out.println("AAA/BBB");
        }
    }
    public class ClassC extends ClassA {
        public void stampa(ClassC p) {
            System.out.println("CCC");
        }
        public void stampa(ClassA p) {
            System.out.println("AAA/CCC");
        }
    }
    

    主要是这样的

    public static void main(String[] args) {
        ClassA a1, a2;
        ClassB b1;
        ClassC c1;
        a1 = new ClassB();
        b1 = new ClassB();
        c1 = new ClassC();
        a2 = new ClassC();
        b1.stampa(b1);//BBB
        a1.stampa(b1);//AAA/BBB
        b1.stampa(c1);//AAA/BBB
        c1.stampa(c1);//CCC
        c1.stampa(a1);//AAA/CCC
        a2.stampa(c1);//AAA/CCC
    }
    

    我很难理解为什么a1.stampa(b1)的结果;是“AAA/BBB”而不是“BBB”。

    当我试图理解a2.stampa(c1)的结果时,同样的事情也会发生;它是“AAA/CCC”而不是“CCC”。

    有人能帮我理解我做错了什么吗?

    5 回复  |  直到 8 年前
        1
  •  1
  •   Adam    8 年前

    问题是以下几点

    public class ClassB extends ClassA {
        public void stampa(ClassB p) {
    

    不是 最重要的

    public class ClassA {
        public void stampa(ClassA p) {
    

    它是 过载 而是。。。

    这意味着它是一个额外的方法,而不是覆盖,并且只能通过 b1.stampa(b1); .

    仅覆盖 发生 如果你有相同的方法签名,除了所谓的“协变返回”,基本上是相同的概念,但返回类型是一个子类。

        2
  •  0
  •   yun xu    8 年前

    这是一个与过载和多态性相关的问题。

    ClassA a1;
    ClassB b1;
    ...
    a1.stampa(b1);
    

    编译器只能确定编译时调用的两个参数类型和函数名(因为多态性)。

    所以“a1.邮票(b1);”使编译查找stampa的参数类型为ClassA中的ClassB,但ClassA没有此功能,因此参数被降级,编译查找stamp的参数类型在ClassA中为ClassA。这个函数是存在的,所以编译器在这一行中记录了一个名为stampa、参数类型为ClassA的函数应该在这里调用。

    当程序运行时,a1实际上是一个ClassB对象,这个对象用名称stampa和参数类型ClassA覆盖函数。因此,最终输出为“AAA/BBB”。

    请记住,重载发生在编译时,多态发生在执行时。

    请不要理我蹩脚的英语。

        3
  •  0
  •   Andreas LppEdd    8 年前

    这是关于 最重要的 过载 方法的。

    方法具有 signature ,由方法名和参数类型定义,而不是参数名或返回类型。

    只要签名不同,就可以在一个类上定义同名的多个方法。这就是所谓的 过载 .

    如果子类使用 相同的 签名作为超类,子类是 最重要的

    Java编译器确定 哪一个 方法,即要使用的方法签名。要调用的具有该签名的实际方法是在 ,具体取决于引用对象的实际类。

    所以,在 编译时间 对于 a1.stampa(b1) 编译器查看所有 stampa 上课时 ClassA (因为 a1 ),只找到一个这样的方法,带有签名 stampa(ClassA) .

    运行时间 ,引用的对象 a1级 实际上是一个 ClassB ,所以 ClassB.stampa(ClassA) 被调用,因为 B级 已重写中的方法 A级 .

    B级印花(A级) 然后打印 AAA/BBB .

        4
  •  0
  •   Shailesh    8 年前

    据我所知,a1。stampa(b1)的结果;是“AAA/BBB”而不是“BBB”,因为当您将b1传递给stampa()时,它将被类型强制转换为超类引用,并且因为您有超类的重载方法,而重载方法的执行总是优先于子类方法,所以执行子类方法而不是超类。

        5
  •  0
  •   Pushpinder Singh Grewal    8 年前

    这是 运行时多态 这是通过 重写的方法 . 首先,你甚至不能期望 a1.stampa(b1); 调用不重写父类方法的方法 public void stampa(ClassB) )。此方法永远不会从您的调用中调用,因为它不会重写父类方法。

    现在,为什么 public void stampa(ClassA p) gets被调用是因为在运行时父类引用变量 a1 ClassB

    你的另一个问题也是如此。

    要更好地理解Runtime多态性,您可以参考 https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html