3

我有以下代码:

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,但我不是。我得到 10a.p(10)和 20.0 a.p(10.0)。基于静态绑定的概念和由静态绑定完成的重载的整个概念,它着眼于声明的类型而不是实际的类型,为什么结果会这样?非常感谢您的帮助。

4

7 回答 7

2

Anint可以扩大到 a double,但不能反过来。这意味着10can call B.p(double)or A.p(int)but 10.0is adouble并且不会被隐式转换为intie 只会B.p(double)被调用。

于 2013-01-31T17:21:36.750 回答
2

这是因为您的方法p不是被覆盖的方法,它只是在您使用时继承在您的子类中

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

在这种情况下,因为您的 Super 类有一个方法,该方法将 double 作为参数,并且 aa 一个int可以适合您的doubleSuper-class 的方法被调用接受 double 的方法。

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

但是,在这种情况下,由于您的子类没有采用 double 的方法,因为sup.p(double) call如果您将 double 作为参数传递,它将使用从超类继承的方法。

于 2013-01-31T17:23:42.597 回答
1

当您编写时,A a = new A()您会创建一个新的 type 对象A,它将有 2 个方法。A.p(int)B.p(double),当你调用 时A.p(10.0),它会B.p(double)因为缺乏转换而调用。

于 2013-01-31T17:24:48.090 回答
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)因此,这就是你得到的

这实际上是一个可以隐式转换的参数类型的问题,而不是重载或覆盖哪些方法。

于 2013-01-31T17:25:54.187 回答
1

当对象声明了 typeB时,将double调用版本,因为它与int参数兼容,因为在 Javaint中是double.

当对象被声明为 aA时,它的方法p()重载了两个版本:

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

因此,当您通过 时int,会选择第一个版本,因为它更准确,而当您通过double第二个时,因为它是最具体的签名。

如需参考,请参阅第15.12.2 节中的相关 JLSGilad Bracha 的这篇文章顺便说一句,不要试图根据您认为最合乎逻辑的方式来弄清楚该语言的行为方式,因为每种编程语言都是一项工程工作,这意味着您要为所采取的任何方式付出代价。Java 的主要信息来源是 JLS,如果您仔细阅读它,您会(出乎意料地?)发现源代码中的行甚至存在歧义且无法编译的情况。

于 2013-01-31T17:29:48.227 回答
1

在您的情况下,您正在进行重载,这将在编译时绑定(静态绑定。)。静态绑定发生在引用类型而不是引用指向的对象类型上。在您的第一种情况下,您使用 B 的引用变量并将 A 的对象分配给它。由于您的引用是 B,即使您使用 int,来自 B 的方法 p(double) 也会静态绑定(因为 int 可以扩大到两倍)。

在第二种情况下,您将引用用作 A 本身。在这种情况下,您有两个可用的 p() 方法。一个是来自 B 的 p(double),另一个是来自 A 的 p(int)。所以 p(10) 将调用 p (int) 和 p(10.0) 将调用 p(double)

试试这个:

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 = new A(),您将看到编译器在这两种情况下都试图调用父 p。

于 2013-01-31T17:31:46.953 回答
0

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

因此,
double ~ Parent
int~Child

显然子对象可以扩大到父引用。

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
test.Parent

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

于 2014-11-26T13:38:29.183 回答