Java 运行时多态性提供错误的输出
据我所知,根据我对运行时多态性的了解,以下代码应该打印Java 运行时多态性提供错误的输出,java,Java,据我所知,根据我对运行时多态性的了解,以下代码应该打印a 但是,当我运行以下代码时,它正在打印b: 根据JLS 8.4.8.1,B1.m1不覆盖A1.m1,因此当A1.m1为 调用时,不应选择B1.m1 有人能帮我理解这种行为吗。预期的输出确实是b 当您将对象a声明为A1类型时,该类仅定义方法的接口。它定义m1返回一个字符串,但该方法的实现由用于构建对象的类定义,即Test1。而Test1扩展了B1,它覆盖了方法m1,因此这就是用于对象的m1的实现 该调用的输出m1()必须确实是B1 编辑:此答
a
但是,当我运行以下代码时,它正在打印b
:
根据JLS 8.4.8.1,B1.m1不覆盖A1.m1,因此当A1.m1为
调用时,不应选择B1.m1
有人能帮我理解这种行为吗。预期的输出确实是
b
当您将对象a
声明为A1
类型时,该类仅定义方法的接口。它定义m1
返回一个字符串,但该方法的实现由用于构建对象的类定义,即Test1
。而Test1
扩展了B1
,它覆盖了方法m1
,因此这就是用于对象的m1
的实现
该调用的输出m1()
必须确实是B1
编辑:此答案是针对问题的第一个版本编写的。OP改变了很多代码,但解释的根源仍然是一样的。下面一行
a1a=newtest1()
只是指构建一个Test1
实例并将其存储在A1
框中
因此,该实例将是一个Test1
,但您将只能访问A1
的方法/变量,但将访问Test1
中所有重写的方法
这是波里莫皮什
通过阅读有关accesor的
在类C中声明或由类C继承的实例方法mC重写了在类A中声明的另一个方法mA,如果以下所有条件均为真:
- A是C的一个超类
- mC的签名是mA签名的子签名()
- 马是公众人物
- 如果重写或隐藏的方法是public,那么重写或隐藏的方法必须是public;否则,将发生编译时错误
- 如果重写或隐藏方法受保护,则重写或隐藏方法必须受保护或公开;否则,将发生编译时错误
- 如果重写或隐藏方法具有包访问权限,则重写或隐藏方法不能是私有的;否则,将发生编译时错误
C1
实现m1
(由于接口),您在B1
中找到的实现中隐藏了A1
的方法,该方法确实是接口合同的有效定义
您可以看到您没有覆盖该方法(您不能调用
super.m1
,甚至不能在B1.m1
上添加@Override
。但是调用a.m1()
是有效的,因为它是在类本身中定义的。您正在重写。包括@Override
注释,您可以看到这一点。只要您的类扩展可以重写父类方法,您就可以增加访问权限,但不能减少访问权限
如果您试图将B#m1
设置为私有,那么某人可以将其转换为A
并使用该方法
相反,如果将A#m1
设为私有,则B
无法覆盖它,最终可能会导致对象具有两个具有相同签名的方法
static class A{
private String get(){
return "a";
}
}
static class B extends A{
public String get(){
return "b";
}
}
public static void main (String[] args) throws java.lang.Exception
{
A b = new B();
System.out.println(b.get());
System.out.println(((B)b).get());
// your code goes here
}
这将输出:
- a
- b
public class C1 extends b.B1 implements I1 {
public static void main(String[] args) {
a.A1 a = new a.C1();
System.out.println(a.m1());
a.A1 b = new b.B1();
System.out.println(b.m1());
}
}
(实际上,我使用了不同的包名以避免与变量名冲突。因此,我的代码与上面的代码看起来有些不同。)
我已经确认它打印“b”和“a”。也就是说,如果我创建一个新的B1
,它的m1
方法不会覆盖A1
中的方法。因此,如果我打印b.m1()
,因为b
属于A1
类型,多态性不起作用,调用了A1
中声明的方法。那么C1
发生了什么
C1
继承了B1
中的m1
方法。但是,尽管B1
中的m1
方法没有覆盖A1
中的方法,但是C1
中的m1
方法继承自B1
,实际上覆盖了A1
中的方法。我认为这与此有关第8.4.8.1条:
mA与C在同一个包中使用包访问权声明,C声明mC或mA是C的直接超类的成员
这里
C
是你的C1
类。mC
是继承自B1
的m1
。在这种情况下,“C声明mC”是假的,因为C1
没有声明m1
,它继承了它。然而,我相信“mA是C的直接超类的一员”是的。据我所知,B1
拥有A1
拥有的所有成员。B1
声明它自己的m1
,并且由于它没有重写,它是一个新的m1
,导致它从A1
继承的m1
被隐藏。但即使它是隐藏的,它仍然是一个成员。因此在此基础上,mA
是C
的直接超类的成员(即B1
)满足,因此满足8.4.8.1的所有条件,因此C1
中继承的m1
覆盖A1
您有一个接口I1
,该接口由A1
实现
B1级扩展A1
类C1扩展B1
(因此隐式扩展
public class C1 extends b.B1 implements I1 {
public static void main(String[] args) {
a.A1 a = new a.C1();
System.out.println(a.m1());
a.A1 b = new b.B1();
System.out.println(b.m1());
}
}
I1 instance = new C1();
String value = instance.m1();
public interface IAnimal {
public Object saySome();
}
public class Animal {
Object saySome() {
return "I am an animal";
}
}
public class Feline extends Animal {
public String saySome() {
return "I am a feline";
}
public class Cat extends Feline implements IAnimal {
Object saySome() {
return "meow";
}
}
public class Lion extends Feline implements IAnimal {
Object saySome() {
return "roar";
}
}
class Aplication {
public static void main(String[] args) {
Animal anAnimal = new Cat();
Animal anotherAnimal = new Lion();
System.out.println(anAnimal.saySome());
System.out.println(anotherAnimal.saySome());
}
}