2017-07-01 70 views
1

我包括代码的输出是很丑陋,但它只是一个代码,了解不同的事情怎么可以在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在编码时类型是参考的类型,在运行时,当我把它识别出其一个cstorta类型tcs.retegez方法,但是这是相同的TCS参数保持引用类型(那就是为什么它使用cstorta标记的方法)。

我的问题是:我的结论是否正确:如果程序调用方法,程序只检查“真实”类型的对象,如果不是,则使用引用类型?

+0

好吧,我做到了。 –

+0

正确的扩展对象在Java中有点棘手,并可能导致延迟的运行时异常。 –

+2

是的,Java雇佣了[Single-dispatch](https://www.wikiwand.com/en/Dynamic_dispatch#/Single_and_multiple_dispatch) –

回答

1

这是非常正确的。这里需要的是理解超载覆盖之间的差异。

当您有一个声明实例方法的类和一个声明相同方法(相同名称,相同参数 - 结果类型通常相同但可能是子类)的子类时,会覆盖覆盖率。有多种方法可供选择,但确切的方法是在运行时确定的。

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被调用。

重载是当两个方法具有相同的名称,但不同的参数,都存在。通过不同的参数,我的意思是参数的数量是不同的,或者参数的数量是相同的,但是类型是不同的。也就是说,他们有不同的签名。在这种情况下,决定在哪个方法调用编译时间。 (你可以有一个情况,即重载和重载两者都发生,关于选择哪个参数签名的决定是在编译时做出的;但是如果有多个具有相同签名的重写方法,那么这些方法在运行时就作出选择。 )

要记住的关键是,如果决定是在编译时做出的,编译器将而不是知道对象的“真实”类型是什么。它只知道你是如何宣布它的。因此:

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)); 

编译器必须决定是否要呼叫号码1或2号。所有的编译器知道是该参数是一个Torta。实际值可能是TortaCsTorta或任何其他类的对象。或者它可能是null(没事,你不能称之为tcs.retegez如果它是空的,但如果你说tcs.retegez(tcs2),然后tcs2可能是空的。)编译器不知道,也不关心。它只知道它被声明为Torta,所以它选择了参数为Torta的重载方法。

(为了进一步澄清:编译器会选择最深的子类,它可以举例:)

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