在Java中扩展类和实现接口

39
interface Bouncable{ } 
interface Colorable extends Bouncable{ } 
class Super implements Colorable{ } 
class Sub extends Super implements Colorable {} // Ok (case -1)

但是,

class Sub implements Colorable extends Super {} // error (case -2)

为什么第二种情况显示编译错误{ expected。为什么?尽管第一种情况没有出错执行。


可能是重复的问题https://dev59.com/62kv5IYBdhLWcg3wghIi - yegor256
@yegor256 可能是。但是,你可以说,它属于我问题的第二部分。 - Ravi
3
我不明白为什么有些人会在没有给出理由的情况下就点踩(downvote)。如果有人有疑问,他们会问,但另一方面,如果其他人知道答案,就应该发表他们的答案,而不是点踩。人们误用了 Stack Overflow 的点踩功能。 - Ravi
而且,我真的不这么认为,那是一个非常无关紧要的问题。作为一个初学者,很多人都不知道这个。 - Ravi
6个回答

69

extends 应该放在 implements 前面:

class Sub extends Super implements Colorable {}

1
为什么?有任何逻辑背后吗? - Ravi
19
只需要Java语法,不涉及逻辑。 - yegor256
1
必须有一些规则。为什么 { 和 [ 不能互换?为什么 ( 和 ) 不能互换?同样的原因。 - Osiris
1
如果您在JLS或其他地方发现了任何支持性的评论,请务必分享。 - Ravi
3
有一定的逻辑性。如果要实现更多的接口,那么在找到继承链末端的超类时会更加困难。考虑以下情况:class Sub implements Colorable, Shape, Component, SomeInterface, AnotherInterface extends Super {} - Nikolas Charalambidis
显示剩余3条评论

9

我有一个例子可以解释为什么在类声明中extends优先于implements。

接口:

public interface IParent {
    void getName();
    void getAddress();
    void getMobileNumber();
}

abstract class :

public abstract class Parent {
    public abstract void getAge();
    public void getName(){
        System.out.print("the parent name");
    }
}

子类:

public class Child extends Parent implements IParent {

    @Override
    public void getAddress() {
       System.out.print(" Child class overrides the Parent class getAddress()");
    }

    @Override
    public void getMobileNumber() {
        System.out.print(" Child class overrides the Parent class getMobileNumber()");
    }

    @Override
    public void getAge() {
        //To change body of implemented methods use File | Settings | File Templates.
    }
}

如果您观察,您会发现接口和抽象类中都有同名的方法getName(),而在抽象类中该方法具有实现。
当您尝试实现时,一个类必须覆盖接口的所有抽象方法,然后我们正在尝试扩展已经具有方法getName()实现的抽象类。
当您创建Child类的实例并调用方法getName()时,
Child child = new Child();
child.getName();

当一个方法getName()存在两个实现时,对于子类来说会产生冲突。

为了避免这种冲突,必须先继承再实现接口。

如果抽象类和接口中都有相同的方法,而且抽象类已经实现了该方法,那么子类不需要覆盖该方法。


4

在Java中,如果要实现一个接口并扩展一个类,我们必须先扩展一个类,然后再实现一个接口。

interface A{}
class super{}

class sub extends super implements A {}

当Java编译器将一个类转换为字节码时,它必须首先查找父类。这是因为类的底层实现是指向父类的字节码 - 它包含相关方法和字段。然后,它添加指针到子类函数的代码 - 其中一些是由'implements'关键字规定的。
由于父类必须可编译,如果编译器事先知道该类是什么,那么编译会更容易。此外,您只能扩展一个类,但可以实现任意数量的接口。如果extends关键字可以在任意数量的implements指令中穿插使用,则编译时间会增加。编译器希望尽快失败以减少开发时间,因此这个选择是合理的。此外,出于同样的原因,它还有助于您清晰地思考类的问题。

1
你能否添加任何参考资料来支持你的回答? - Ravi
你应该更新你的帖子,而不是把所有内容都写在评论里。现在,你的帖子比评论少了很多内容。 :D - Ravi
你的答案是从 https://dev59.com/62kv5IYBdhLWcg3wghIi 复制的。 - Akhilesh Dhar Dubey

2

JLS Syntax Page中,类定义的语法为:

NormalClassDeclaration: 
    class Identifier [TypeParameters] [extends Type] [implements TypeList] ClassBody

我认为,为了简化语法规则,他们没有使其可互换。

要使其可互换,您可能需要类似以下的内容:

NormalClassDeclaration: 
    class Identifier [TypeParameters] [ExtendsImplements] ClassBody

ExtendsImplements:
    [extends Type] [implements TypeList] | [implements TypeList] [extends Type]

甚至更糟的是,您可能需要声明ExtendsImplements才能使用OR

我想这并不那么重要,值得我们去混淆解析规则。


添加了对JLS语法页面的引用。 - Aviram Segal

1

这是由于JLS中的规范。在尝试声明Java类时,有一定的元素顺序:

  • 修饰符,如publicprivate等。
  • 类名,按惯例首字母大写。
  • 类的父类(超类)名称(如果有),前面加上关键字extends。一个类只能继承(子类化)一个父类。
  • 由逗号分隔的接口列表,如果有的话,前面加上关键字implements。一个类可以实现多个接口。
  • 类体,用大括号{ }括起来。

参考资料:

http://docs.oracle.com/javase/tutorial/java/javaOO/classdecl.html


你讲解了Java中的基本声明。但是,从你的解释和链接中,并不清楚为什么extend要先于implements。 - Ravi

0
你必须这样做。你只能通过逗号分隔来实现多个接口,但只能扩展一个类。如果在实现之前添加扩展,将更加易于阅读。
class Sub extends Super implements Colorable

我不这么认为,这个语法的原因是什么呢?请提供一些参考资料。 - Ravi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接