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签名的子签名()
  • 马是公众人物
您可以在中找到有关访问修饰符的更多信息

重写或隐藏方法的访问修饰符(§6.6)必须提供至少与重写或隐藏方法相同的访问,如下所示:


  • 如果重写或隐藏的方法是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());
    }
}