2013-01-31 119 views
3

我有以下代码:静态VS动态绑定逻辑

import java.lang.*; 

public class Program 
{ 
    public static void main(String [] args) 
    { 
     B a = new A(); 

     a.p(10); 
     a.p(10.0); 
    } 
} 
    class B { 
     public void p(double i) 
     { 
      System.out.println(i*2); 
     } 
    } 

    class A extends B{ 
     public void p(int i) 
     { 
      System.out.println(i); 
     } 
    } 

当我执行使用B a = new A()这个代码,我得到了这两种情况下这是有意义的,因为重载是在编译时编译器在哪里看手柄20.0声明的类型并适当调用一个函数。由于我们声明的类型是B类,所以在这两种情况下都调用B类的方法。现在如果我做A a = new A();,我应该在两个答案中得到10,但我不是。我得到a.p(10)为10,对于a.p(10.0)为20.0。基于静态绑定的概念和通过静态绑定完成重载的整体概念,该静态绑定将查看声明的类型而不是实际的类型,为什么结果会以这种方式出现?我非常感谢你的帮助。

回答

1

在你的情况下,你正在做的重载将在编译时绑定(静态绑定。)。静态绑定发生在引用类型而不是引用指向的对象类型。 在第一种情况下,您正在使用B的引用变量并将A的对象分配给它。由于引用是B,因此即使使用int,来自B的方法p(double)也会静态绑定(因为int can被扩大到双倍)。在这种情况下,你有两个p()方法可用。一个是来自B的p(双)和来自A.So的其他p(int)p(10) )将调用p(int)和p(10.0)将调用p(双)

试试这个:

class B { 
    public void p(String i) 
    { 
     System.out.println("parent:"+i); 
    } 
} 

class A extends B{ 
    public void p(int i) 
    { 
     System.out.println(i); 
    } 
} 
public class Test1 { 
    public static void main(String args[]) { 

     A a = new A(); //arg 
      a.p(10); 
      a.p("sample"); 
    } 
} 

如果你改变了行标ARG到B A =新的A(),你会看到编译器试图在这两种情况下调用父p。

+0

如果你说的是正确的,那么如果我改变我的子类方法public void p(double i){System.out(i * 3);},然后如果我调用B a = new A(),I在两种情况下都应该达到20.0,但为什么我要达到30.0?编译器为什么要查看子类方法?我会感谢你的帮助。 – Stranger

+1

在这种情况下,您重写了动态绑定函数。在动态绑定的情况下,它的对象类型不是引用,它决定了在运行时调用哪个方法。因此,在这种情况下,您的方法调用都会调用子类中的过度使用方法。现在很明显。 – Renjith

+0

啊!你是我的朋友。你说对了。非常感谢答案。你们好棒!! – Stranger

2

int可以扩大到double,但不是相反。这意味着10可以调用B.p(double)A.p(int),但10.0double,并且不会隐式转换为int,即只会调用B.p(double)

+0

感谢您的回答彼得 – Stranger

2

它,因为你的方法p不是一个重写的方法,它只是inhereted在当您使用

Super sup = new Sub(); 
sup.p(int); 
sup.p(double); 

在这种情况下,你的超类的子类有采用双作为参数的方法和一个int可以适合 a double您的超级类的方法被引用一个接受双。

Sub sup = new Sub(); 
sup.p(int); 
sup.p(double); 

然而,在这种情况下,你的子类不具有采用了一倍,为sup.p(double) call它使用了继承的方法从超类,如果您双击作为参数传递的方法。

1

当您编写A a = new A()时,将创建一个类型为A的新对象,该对象将有2个方法。 A.p(int)B.p(double),并且当您拨打A.p(10.0)时,由于缺乏转换,它将调用B.p(double)

+0

感谢阿什温在前面回答 – Stranger

+0

你欢迎,陌生人。我希望我很清楚。 – Achrome

1

这个反例可以帮助:

import java.lang.*; 

public class X 
{ 
    public static void main(String [] args) 
    { 
     B c = new A(); 

     c.p(10); 
     c.p(10.0); 
     c.p("AAA"); 
     ((A)c).p(10); 
    } 
} 
    class B { 
     public void p(String s) 
     { 
      System.out.println("B: my string is " + s); 
     } 

     public void p(double i) 
     { 
      System.out.println("B: twice my double is: " + i*2); 
     } 
    } 

    class A extends B{ 
     public void p(int i) 
     { 
      System.out.println("A: my number is " + i); 
     } 
    } 

输出:

C:\temp>java X 
B: twice my double is: 20.0 
B: twice my double is: 20.0 
B: my string is AAA 
A: my number is 10 

的问题是:

1)你声明类型为 “B”(而不是“ A“)

2)Bp(10)可以接受int作为浮点点参数

3)因此,这是你在说什么

这真的是参数类型的问题,可以隐式转换,比什么方法被重载或覆盖。

+0

感谢您的回答。感谢您的时间 – Stranger

1

当对象已声明的类型B,该double版本是用Java调用int,因为它是与int参数兼容的,因为是double一个亚型。

当对象被声明为A,它有两个版本重载的方法p()

p(int arg); 
p(double arg); 

所以,当你传递一个int,第一个版本被拾取,因为它更准确,而当你通过double第二个,因为它是最具体的签名。

仅供参考,请参阅相关JLS at §15.12.2this post by Gilad Bracha。顺便说一句,不要试图根据你认为最合乎逻辑的方式来理解语言应该如何表现,因为每一种编程语言都是一项工程努力,这意味着你付出的任何代价都会付出代价。 Java的主要信息来源是JLS,如果仔细阅读,您会(意外地发现)发现甚至有源代码行不明确且无法编译的情况。

+0

感谢您的回答。 – Stranger

0

为了让int的加宽效果更加生动,我创建了另一个值得一看的例子。在这里,而不是double我创建了一个名为Parent的类,而不是int a Child类已创建。

因此,
双〜父
INT〜儿童

显然子对象可以被加宽到父参考。

package test; 
public class OOPs { 
    public static void main(String[] args) { 
     Child ch = new Child(); // like int 10 
     Parent pa = new Parent();// like double 10.0 

     B a = new A(); // case 2 : A a = new A(); 

     a.p(ch);// 10 
     a.p(pa);// 10.0 
    } 
} 

class B { 
    public void p(Parent i) { 
     System.out.println("print like 20"); 
     System.out.println(i.getClass().getName()); 
    } 
} 

class A extends B { 
    public void p(Child i) { 
     System.out.println("print like 10"); 
     System.out.println(i.getClass().getName()); 
    } 
} 

class Parent { 
    String name; 

    Parent() { 
     name = "Parent"; 
    } 

    public String getName() { 
     return name; 
    } 
} 

class Child extends Parent { 
    String name; 

    Child() { 
     name = "Child"; 
    } 

    public String getName() { 
     return name; 
    } 
} 

案例1 - 输出(B a = new A();)
打印像20
test.Child
打印像20
测试。家长

案例2 - 输出(A a = new A();)
打印像10
test.Child
打印像20
test.Parent