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

多态实例如何选择其方法?

  •  1
  • Tchae  · 技术社区  · 6 年前

    我无法理解这段代码的行为。 a被定义为a,c被定义为c。 然后,在公共类的末尾,a=c。 当a调用display()方法时,它将达到它的C版本。 但是当a调用f()时,它只到达a版本,尽管第一个参数(byte和long)比float更符合long。

    这是一本书的练习,但解释很少或不存在。

    class A{
        public void display(){
            System.out.println("I am an A ");
        }
    
        public void f(double x){
            System.out.println("A.f(double = " + x + ") ");
        }
    }
    
    class C extends A{
        public void display(){
            System.out.println("I am a C ");}
    
        public void f(long q){
            System.out.println("C.f(long = " + q + ") ");}
        }
    
    
    public class PolySurStack{
        public static void main(String Args[]){
            byte bb =1; long q = 4; float x = 5.f;
    
            System.out.println(" ** A **");
            A a = new A(); a.display();
            a.f(bb); a.f(x);
    
            System.out.println();
            System.out.println(" ** C **");
            C c = new C(); c.display();
            c.f(bb); c.f(q); c.f(x);
            System.out.println();
            a = c; a.display();
            a.f(bb); a.f(q); a.f(x);
        }
    } 
    
    4 回复  |  直到 6 年前
        1
  •  1
  •   Eran    6 年前

    当你打电话 a.f(bb) a.f(q) a.f(x) ,编译器只能从类中定义的方法签名中进行选择。 A (或任何超类 ),因为 a 是类型的引用变量 .

    因此,只有 public void f(double x) 被认为是。为了 public void f(long q) 要成为过载解决方案的候选人,你必须 键入 C 打电话之前 f() ,因为只有类 C 定义具有该签名的方法。

    要理解的重要一点是,方法重载解析发生在编译时。只有调用该方法的引用变量的编译时类型才能确定哪些方法签名是方法重载解析的候选者,以及将选择哪些候选者。

        2
  •  1
  •   Tchae    6 年前

    我刚在另一个论坛上找到这个:

    重载:(相同的函数名但不同的签名)

    1. 两个或多个方法在同一类中具有相同的名称和不同的路径,称为重载。

    2. 当要扩展功能时,将使用重载。

    3. 重载被称为编译时多态性

    重写:(相同的函数名但相同的签名)

    1. 父类和子类中具有相同方法名和相同路径的两个或多个方法称为重写。

    2. 当要重用现有功能时,将使用覆盖。

    3. 覆盖被称为运行时多态性

    因此,我的问题的答案似乎是,重写解决方案(比如display())发生在运行时(这里在a=c之后),而重载解决方案(比如f())发生在编译时,而a仍然是a。

    我想。

    我还找到了这个页面: https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/

    明确并与本主题高度相关。

        3
  •  0
  •   davidxxx    6 年前

    编译器选择的方法取决于声明的类型,而不是运行时类型。
    声明为变量的第一个系列 A 只能调用方法(实例化为 仅导出 Object ):

    A a = new A(); 
    a.f(bb); a.f(x);
    

    对于第二个系列,编译器使用与调用匹配的最特定参数绑定方法,因为 C 是一个 因此编译器可以在这里绑定这些公共方法:

    C c = new C(); 
    c.f(bb); c.f(q); c.f(x);   
    

    但在最后一段可能会质疑你自己的代码中, a C 作为运行时对象 声明类型:

    A a = new A(); 
    // ...
    a = c; 
    a.f(bb); a.f(q); a.f(x);
    

    所以只有在 可以调用。

        4
  •  0
  •   RaminS    6 年前

    我会尽量澄清一下@eran的答案,以便你能理解。

    一个子类拥有它的超类的所有方法,然后可能还有更多的方法。您有一个类型的变量 A ,其中存储类型为的对象 C . C 具有类中定义的所有方法 以及另一种方法,即 f(long q) . 不知道这个新方法,所以因为您将对象存储在 ,你不能打电话 F(长Q) .

    可以 然而呼叫 display() 因为它是在 但是它仍然是 C 执行它的对象。