我有以下代码:
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分。基于静态绑定的概念和通过静态绑定完成重载的整个概念,静态绑定查看声明的类型而不是实际类型,为什么结果会以这种方式出现?我非常感谢你的帮助。
答案 0 :(得分:2)
int
可以扩展为double
,但不能相反。这意味着10
可以调用B.p(double)
或A.p(int)
,但10.0
是double
,不会被隐式转换为int
,即仅{ {1}}将被调用。
答案 1 :(得分:2)
因为你的方法p
不是一个被重写的方法,所以当你使用
Super sup = new Sub();
sup.p(int);
sup.p(double);
在这种情况下,因为你的超级类有一个方法,它需要双倍作为参数,而 int 可以适合 a double
你的超级类方法被调用接受double的方法。
Sub sup = new Sub();
sup.p(int);
sup.p(double);
但是,在这种情况下,由于您的子类没有采用double的方法,因此对于sup.p(double) call
,如果将double作为参数传递,它将使用超类中的继承方法。
答案 2 :(得分:1)
当你编写A a = new A()
时,你创建了一个A
类型的新对象,它将有2个方法。 A.p(int)
和B.p(double)
,当您致电A.p(10.0)
时,由于缺乏转化,它会致电B.p(double)
。
答案 3 :(得分: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)B.p(10)可以接受一个int作为浮点参数
3)因此,这就是你得到的
这实际上是一个问题类型可以隐式转换的问题,而不是重载或覆盖的方法。
答案 4 :(得分:1)
当对象声明了类型B
时,调用double
版本,因为它与int
参数兼容,因为在Java int
中是double
的子类型1}}。
当对象声明为A
时,方法p()
重载了两个版本:
p(int arg);
p(double arg);
因此,当您传递int
时,会选择第一个版本,因为它更准确,当您传递double
第二个版本时,因为它是最具体的签名。
供参考,请参阅相关的JLS at §15.12.2和this post by Gilad Bracha。顺便说一句,不要试图根据你认为最符合逻辑的方式来弄清楚语言应该如何表现,因为每种编程语言都是一种工程努力,这意味着你付出了代价无论你拿什么。 Java的主要信息来源是JLS,如果你仔细阅读,你会(令人惊讶地发现?)发现有些情况下源代码中的行不明确且无法编译。
答案 5 :(得分:1)
在你的情况下,你正在进行重载,它将在编译时被绑定(静态绑定。)。静态绑定发生在引用类型而不是引用所指向的对象类型。 在你的第一种情况下,你正在使用B的引用变量并为它分配一个A的对象。因为你的引用是B,即使你使用int,来自B的方法p(double)也会静态绑定(因为int可以是扩大到一倍)。
在第二种情况下,你使用引用作为A本身。在这种情况下,你有两个p()方法可用。一个是来自B的p(双精度)和来自A.So p(10)的其他p(int)将调用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。
答案 6 :(得分:0)
为了使int的加宽效果更加生动,我创造了另一个值得一看的例子。在这里,我创建了一个名为double
的类而不是Parent
而不是int
,而是创建了一个Child
类。
因此,
double~Barent
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
打印像20
test.Parent