Java中的静态和动态绑定

时间:2015-06-12 21:03:42

标签: java oop binding polymorphism dynamic-binding

请有人向我解释输出的最后6行是如何打印的。我知道由于静态绑定,前三行被正确打印。

我不知道为什么第5行给出了输出,因为它是Ipod类型,它没有任何歌曲方法,但它仍打印输出。 这是代码:

package myferrari;

import mycar.*;

class IPOD
{
    void PlayMusic(Music m)
    {
        System.out.println("Music from Ipod");
    }
}

class IpodPlayer extends IPOD
{
    void PlayMusic(Music m)
    {
        System.out.println("Music from IpodPlayer");
    }

    void PlayMusic(Song m)
    {
        System.out.println("Song from IpodPlayer");
    }
}

class Music{}
class Song extends Music{}

public class Main  {

    public static void main(String [] args)
    {
        IPOD ipod = new IPOD();
        IpodPlayer iplayer = new IpodPlayer();
        IPOD ipl = new IpodPlayer();

        Music m = new Music();
        Song s = new Song();
        Music sm = new Song();

        iplayer.PlayMusic(m);
        iplayer.PlayMusic(s);
        iplayer.PlayMusic(sm);  // static binding refers to the reference type

        ipod.PlayMusic(m);      
        ipod.PlayMusic(s);
        ipod.PlayMusic(sm);

        ipl.PlayMusic(m);
        ipl.PlayMusic(s);
        ipl.PlayMusic(sm);

    }
}

输出在这里:

Music from IpodPlayer
Song from IpodPlayer
Music from IpodPlayer
Music from Ipod
Music from Ipod
Music from Ipod
Music from IpodPlayer
Music from IpodPlayer
Music from IpodPlayer

4 个答案:

答案 0 :(得分:0)

执行打印的类有一个方法可以将对象作为Music类,而不是Song的子类。

为了做你想做的事,你必须做如下:

void PlayMusic(Music m){
  if(m instance of Song){
    System.out.println("Song from Ipod");
  } else
    System.out.println("Music from Ipod");
}

并且由于您将ipl声明为超类IPOD并将其实例化为IPodPlayer,因此除非您检查其类型并正确转换它,否则它将表现为IPOD。

IpodPlayer player2 = null;
if(ipl instance of IpodPlayer)
    player2 = (IpodPlayer)ipl;

但这样做没有意义,所以只需将它作为你希望它表现为的类。

这篇文章比我更好地解释了它。 Static Vs. Dynamic Binding in Java

答案 1 :(得分:0)

原因在于: 首先,java在从一组重载方法中进行选择时使用静态绑定。然后从一组覆盖方法中选择动态绑定。 http://beginnersbook.com/2013/04/java-static-dynamic-binding/

class IpodPlayer extends IPOD
{
    //that is overriding
    void PlayMusic(Music m)
    {
        System.out.println("Music from IpodPlayer");
    }

    //that is overloading    
    void PlayMusic(Song m)
    {
        System.out.println("Song from IpodPlayer");
    }
}

答案 2 :(得分:0)

我认为你理解为什么前三行被打印出来,所以我不能解释其背后的原因。

所以想想这样。每当你"延伸"对于一个类,你实际上是在创建该类的新副本并向其中添加内容。 如果你把一个类想象成一个拥有房间(方法)和设备(变量)的房子的蓝图,那么扩展另一个类的类是一个房子的蓝图,它基于另一个蓝图,带有一些可能的修改/添加。当您创建扩展另一个蓝图的蓝图时,您添加的任何房间或设备与原始蓝图中的内容具有相同的签名(名称/类型/参数相同),将覆盖原始蓝图中的内容

解释为什么每条线都像他们一样打印出来:

第4行:您创建了一个IPOD类,它只有一个方法并打印相同的内容,"来自Ipod的音乐"。

第5行:您创建了一个IPOD类,它只有一个方法并打印相同的内容,"来自Ipod"的音乐。是的,该方法仅接受音乐类型,但歌曲扩展了音乐。回到这个例子:这意味着音乐屋的房间和电器都在歌厅内。因此,由于该方法不是在寻找一个歌厅,它会删除所有不属于音乐屋的部分并将其丢弃。然后将音乐屋交给IPOD课程内的方法。

第6行:您创建了一个IPOD类,它只有一个方法并打印相同的内容,"来自Ipod"的音乐。 SM是一个音乐对象,因此很容易传递给该方法。

第8行:所以第8行是使用这些代码行制作的:

IPOD ipl = new IpodPlayer();
Song s = new Song();
ipl.PlayMusic(s);

ipl是IPOD类,而不是IpodPlayer类。 IPOD类中没有对象乐曲的方法。当你写" IPOD ipl = new IpodPlayer();"你没有创建一个IpodPlayer对象。您正在创建一个IPOD对象。 当你说"新的IpodPlayer"在这种情况下,您实际上是在使用IpodPlayer蓝图来构建IPOD对象。 IPOD对象是一个具有一种方法的类," void PlayMusic(Music m)"。所以ipl只有一种方法(音乐方法)。 它之所以说是来自IpodPlayer"的音乐,而不是来自Ipod"的音乐。是因为当您使用IpodPlayer蓝图构建IPOD对象时,使用具有相同签名的IpodPlayer方法(void PlayMusic(Music m))覆盖了IPOD方法。这只能起作用,因为IpodPlayer正在扩展IPOD类。

第7行和第9行:IPL是一个IPOD类,但是您会覆盖名为" PlayMusic"的方法。在声明期间使用与IpodPlayer类相同的命名方法。这就是为什么m,s和sm都打印出来的原因"来自IpodPlayer的音乐"

答案 3 :(得分:0)

Nut shell:整个概念是关于方法重载和覆盖以及它们如何与动态和静态绑定相关联。

现在,首先看下面的代码片段,它简化了你的案例@运行时并理解了运行时图片。使用您选择的任何IDE调试代码,您将看到完全相同的结果。

主要外卖:在运行时,您的引用将解析为实际对象,称为动态绑定或多态。 运行时意味着对象。 因此,无论IpodPlayer iplayer = new IpodPlayer(); OR IPOD ipl = new IpodPlayer();,在运行时,您将获得IpodPlayer的实例,并且将调用其方法。

动态绑定与方法重写 相关联。因此,在运行时,将通过检查对象类型来确定将调用重写方法。因此,您可以看到无论什么是引用类型,都会在运行时调用实际对象的PlayMusic方法。

这总结了您的动态绑定和方法覆盖。

    new IpodPlayer().PlayMusic(new Music());        //Music from IpodPlayer 
    new IpodPlayer().PlayMusic(new Song());         //Song from IpodPlayer 
    new IpodPlayer().PlayMusic(new Song());         //Music from IpodPlayer 

    new IPOD().PlayMusic(new Music());              //Music from Ipod     
    new IPOD().PlayMusic(new Song());               //Music from Ipod 
    new IPOD().PlayMusic(new Song());               //Music from Ipod 

    new IpodPlayer().PlayMusic(new Music());        //Music from IpodPlayer 
    new IpodPlayer().PlayMusic(new Song());         //Music from IpodPlayer 
    new IpodPlayer().PlayMusic(new Song());         //Music from IpodPlayer

进行静态绑定和方法重载。

使用类型信息在编译时将静态绑定清楚地表明java中的重载方法是如何绑定的。

现在,您IPOD ipod = new IPOD();的情况非常明确,因为您只有方法而没有重载方法,所以结果没有。 4,5和6是不言自明的。

真正的混淆是IpodPlayer iplayer = new IpodPlayer();IPOD ipl = new IpodPlayer();

在编译时,决定根据对象类型调用哪个重载方法,无论是PlayMusic(Music m)还是PlayMusic(Song m)请注意,我只谈论方法而不是哪个类或对象。

现在,在你的情况下没有。 1,2和3,因为对象是new IpodPlayer()并且你有两个重载方法,所以基于PlayMusic对象类型调用适当的PlayMusic方法

最后一个案例 - 你的案例没有。 7,8和9是主要的头部抓挠案例和最重要的理解因为它结合了动态绑定和静态绑定的概念。
再次在编译时,根据对象类型确定要调用的重载方法但是在编译时它是基于IPOD ipl而不是= new IpodPlayer();决定的,因此编译器决定并生成字节代码PlayMusic(Music m)将在运行时被调用(这是对象的方法,但是PlayMusic(Music m)方法),因为IPOD没有任何其他方法。最后在运行时由于IpodPlayer

,将调用时间动态绑定并调用= new IpodPlayer();的方法