当派生类扩展基类并同时实现接口时,该方法是否被覆盖?

时间:2018-04-11 16:02:50

标签: java inheritance interface method-overriding

案例1:

我有一个Interface Inter.java:

interface Inter
{
        void abcd();
}

基类:

class Base
{
        void abcd()
        {
                System.out.println("Base abcd");
        }
}

派生类:

class Use extends Base implements Inter
{
        void abcd()  //intentionally not using public 
        {
                System.out.println("Use abcd");
        }
        public static void main(String[] args)
        {
                Use u = new Use();
                u.abcd();
        }
}

现在我编译它:

gyan@#ns:~/Desktop$ javac Inter.java Base.java Use.java 
Use.java:3: error: abcd() in Use cannot implement abcd() in Inter
    void abcd()
         ^
  attempting to assign weaker access privileges; was public
1 error
gyan@#ns:~/Desktop$ 

这意味着类Use中的重写方法abcd()来自已实现的接口“Inter”,而不是来自基类“Base”。

案例2:

我们有一个包含以下代码的文件Test.java:

interface Ab
{
        void run();
}

class A extends Thread implements Ab
{
        public void run()
        {
                System.out.println("class A");
        }
        public static void main(String[] args)
        {
                A a = new A();
                Thread t = new Thread(a);
                t.start();
                System.out.println("main method");
        }
}

当我们执行它时,我们得到了:

gyan@#ns:~/Desktop$ java A
main method
class A
gyan@#ns:~/Desktop$

由于t.start()执行了方法run(),这意味着类的Thread的run()被覆盖了。但是在这种情况下,接口“Inter”的方法abcd()被覆盖了。

在案例1中:在类Use中覆盖了谁的方法abcd()? Class Base或接口Inter?错误说我们正在覆盖接口Inter的abcd()。但在案例2中:似乎我们没有覆盖接口Ab的方法运行。因为我们可以通过调用t.start()来执行run()方法。只有在我们覆盖Thread类的run()时才有可能。

3 个答案:

答案 0 :(得分:1)

您的类中的方法会覆盖基类方法并同时实现接口。

覆盖方法与实现接口并不完全相同:

  • 从超类覆盖方法意味着您要替换其实现。如果您没有提供重写方法,则将使用超类(可以为空)的实现。
  • 实现接口方法时,您将提供简单声明的代码(无需任何实现)。如果将非抽象类声明为实现接口,但不为接口的每个方法提供实现,则编译将失败。在Java 8中不太常见,您可以在接口中选择性地提供默认实现,但在这种情况下,超类中的任何实现都将获胜。

方法的实现和覆盖总是可以扩展其可见性,但不能减少它。这意味着:

  • 超类中的package-private(默认可见性)或受保护的方法可以在子类中公开
  • 但是超类中的公共方法不能在子类中成为包私有或受保护。

接口中的方法始终是公共的,即使接口中未指定“public”修饰符也是如此。因此,他们的实现也必须是public =>这就是你在案件中得到的错误1

作为旁注,在你的情况2中,你使用错误的线程。不要子类Thread。相反,创建一个实现Runnable或Callable接口的类,并将其提交给线程池(请参阅java.util.concurrent中的类,或者使用java 8的ForkJoinPool.commonPool().submit(myTask)进行快速测试。

答案 1 :(得分:0)

两者。方法覆盖取决于方法的名称和签名,而不是它的定义位置。如果在多个祖先上定义,它将覆盖两者。 注意:如果在一个中定义为public,在另一个中定义,则它将变为公共。

答案 2 :(得分:0)

Inter接口中,void abcd();是抽象方法的定义。所有抽象方法本质上都是公开的。

来自{Defining an Interface},

  

界面中的所有抽象,默认和静态方法都是隐式公共的,因此您可以省略public修饰符。

所以,虽然Interabcd()public,但Use中的实际实施却表示abcd()的实施是package-private },这是一个较弱的访问权限。这应该符合您的评论"//intentionally not using public" 传统上,abcd()也应该使用注释@Override(尽管这不是一项严格的要求)。

在第二个示例中,Thread类提供了run()的具体实现。鉴于A#run()是公共的,您已满足接口Ab对访问说明符所强加的要求。然后,A#run()继续覆盖Thread#run() - 这正是我们期望继承行为的方式。

总而言之,我们刚刚看到了extends(扩展或重写类方法)和implements之间的区别(给定类为接口中的所有方法状态提供实现的契约)。 {This answer}对此有更深入的了解,并且是一本很好的读物。

让我知道这个答案的任何部分是否需要更清晰。