运行时引用类型

Reference types in runtime

我包含的代码的输出非常丑陋,但它只是用于理解不同事物在 Java 中如何工作的代码。被质疑的行在代码的下半部分标有注释。

class CsTorta extends Torta{

public CsTorta retegez(CsTorta a){
   ....
}
public CsTorta retegez(Torta a){
    System.out.println("This method");               //<-----it calls this one and not the one above
    ....
}

}

public class NewClass {
public static void main(String[] args) {
    Torta tt=new Torta(5);
    Torta tcs=new CsTorta(3);
    CsTorta cs=new CsTorta(4);
    System.out.println("");
    System.out.println(tcs.retegez(tcs)); //The line in question uses the cstorta retegez method (marked with "This method") 

}

}

虽然 tcs 在编码时的类型是引用类型,但在运行时,当我调用 tcs.retegez 方法时,它识别出它是一个 cstorta 类型,但与 tcs 相同的参数仍然是引用类型(这就是它使用 cstorta 标记方法的原因)。

我的问题是:我的结论是否正确:如果程序调用方法,程序只检查对象的"real"类型,并使用引用类型如果没有?

非常正确。这里需要的是理解 overloadingoverriding.

之间的区别

当你有一个声明实例方法的 class 和一个声明相同方法的子 class 时发生重写(相同的名称,相同的参数——结果类型通常是相同的但可能是子 class)。有多种方法可供选择,但具体方法在运行时确定。

public class A {
    public void method1(String s1, int s2) { ... }
}

public class B extends A {
    @Override
    public void method1(String s1, int s2) { ... }
}

A object = new B();
object.method1("xxx",2);

关于 method1 是 运行 的决定直到 运行 时间才做出。 object的真实类型是B,所以调用B中声明的method1

重载是指同时存在两个名称相同但参数不同的方法。参数不同是指参数个数不同,或者参数个数相同但类型不同。也就是说,他们有不同的签名。在那种情况下,在 编译时 决定调用哪个方法。 (你可能会遇到覆盖和重载都发生的情况。关于选择哪个参数签名的决定是在编译时做出的;但是如果有多个具有相同签名的覆盖方法,则在这些方法之间进行选择 运行 时间。)

要记住的关键是,如果在编译时做出决定,编译器将不会知道对象的"real"类型是什么。它只知道你是如何声明它的。因此:

public CsTorta retegez(CsTorta a){   // Number 1
   ....
}
public CsTorta retegez(Torta a){     // Number 2
    System.out.println("This method");               //<-----it calls this one and not the one above
    ....
}

这些是重载方法。

您的代码如下所示:

Torta tcs = // the compiler doesn't care

System.out.println(tcs.retegez(tcs)); 

编译器必须决定是调用 Number 1 还是 Number 2。编译器只知道参数是一个 Torta。实际值可以是 TortaCsTorta 或任何其他 class 的对象。或者它可以是 null(好吧,如果它为 null,则不能调用 tcs.retegez,但如果你说 tcs.retegez(tcs2),则 tcs2 可能为 null。)编译器不知道,也不关心。它所知道的是它被声明为 Torta,因此它选择带有 Torta 参数的重载方法。

(进一步说明:编译器将尽可能选择最深的子class。示例:)

class AnotherTorta extends Torta { ... }
class YetAnotherTorta extends CsTorta { ... }

AnotherTorta t3 = // whatever
YetAnotherTorta t4 = // whatever

tcs.retegez(t3);  
    // since AnotherTorta can't be cast to CsTorta, it chooses the Torta parameter
tcs.retegez(t4);
    // here, t4 can be cast to either a Torta or CsTorta parameter, so it chooses the subclass, CsTorta