运行时引用类型
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"类型,并使用引用类型如果没有?
非常正确。这里需要的是理解 overloading 和 overriding.
之间的区别
当你有一个声明实例方法的 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
。实际值可以是 Torta
、CsTorta
或任何其他 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
我包含的代码的输出非常丑陋,但它只是用于理解不同事物在 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"类型,并使用引用类型如果没有?
非常正确。这里需要的是理解 overloading 和 overriding.
之间的区别当你有一个声明实例方法的 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
。实际值可以是 Torta
、CsTorta
或任何其他 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