实现 vs 继承:何时使用?有什么区别?

813

请用易于理解的语言进行解释,或提供某篇文章的链接。


9
这个例子很容易让人理解Java中接口和抽象类,即通过实现(implements)和继承(extends)的方式。 - User Learning
extends 是扩展空间的一个元素。 - JobHunter69
19个回答

848

extends是用于扩展一个类。

implements是用于实现一个接口。

接口和普通类的区别在于,在接口中你不能实现任何声明的方法。只有“实现”该接口的类可以实现这些方法。与接口相当的C++语言中的概念是抽象类(不完全相同但非常相似)。

另外,Java不支持类的多重继承。通过使用多个接口来解决这个问题。

 public interface ExampleInterface {
    public void doAction();
    public String doThis(int number);
 }

 public class sub implements ExampleInterface {
     public void doAction() {
       //specify what must happen
     }

     public String doThis(int number) {
       //specfiy what must happen
     }
 }

现在扩展一个类

 public class SuperClass {
    public int getNb() {
         //specify what must happen
        return 1;
     }

     public int getNb2() {
         //specify what must happen
        return 2;
     }
 }

 public class SubClass extends SuperClass {
      //you can override the implementation
      @Override
      public int getNb2() {
        return 3;
     }
 }

在这种情况下

  Subclass s = new SubClass();
  s.getNb(); //returns 1
  s.getNb2(); //returns 3

  SuperClass sup = new SuperClass();
  sup.getNb(); //returns 1
  sup.getNb2(); //returns 2

请注意,实现一个接口不需要使用 @Override 标记,因为原始接口方法中没有可被覆盖的内容

我建议你在面向对象编程中动态绑定、多态和继承进行更多研究。


55
一个接口可以包含远不止方法声明:常量字段、注解、接口甚至类。 - Philipp Reichart
它们是否类似于 Ruby 中的模块和混入? - user2492854
@user2492854 有点区别,但是接口中不会有任何实现方法。它只是接口的描述而已,没有具体实现。 - Rob Grant
43
Java 8的一个新特性允许在接口中实现default方法行为,使这些方法的自定义实现变成可选项。因此,关于“你只能指定方法但不能实现它们”的说法仅在Java 7及以下版本才完全正确。 - ADTC
10
"extends is for extending a class"这句话有点令人困惑。它还可以用于扩展接口。例如:public interface ListIterator<E> extends Iterator<E> - weiheng
显示剩余4条评论

83

我注意到您的个人资料中有一些关于C++的问题。 如果您了解C++中的多继承概念(指从多个其他类继承特征的类),Java不允许这样,但它确实有关键字interface,有点像C++中的纯虚拟类。正如许多人所提到的,您可以extend一个类(您只能从一个类扩展),并且您可以implement一个接口 - 但是您的类可以实现任意数量的接口。

也就是说,这些关键字及其使用规则界定了Java中多重继承的可能性(您只能有一个超类,但您可以实现多个接口)。


67
通常,implements 用于实现接口,而 extends 用于扩展基类行为或抽象类。 extends:派生类可以扩展基类。您可以重新定义已建立关系的行为。派生类“是一个”基类类型。 implements:您正在实现合同。实现接口的类“具有”能力。
在 Java 8 发布中,接口可以在接口本身中提供默认方法的实现。
请参考此问题以了解何时使用它们: Interface vs Abstract Class (general OO) 示例以理解事物。
public class ExtendsAndImplementsDemo{
    public static void main(String args[]){
        
        Dog dog = new Dog("Tiger",16);
        Cat cat = new Cat("July",20);
            
        System.out.println("Dog:"+dog);
        System.out.println("Cat:"+cat);
        
        dog.remember();
        dog.protectOwner();
        Learn dl = dog;
        dl.learn();
                
        cat.remember();
        cat.protectOwner();
        
        Climb c = cat;
        c.climb();
        
        Man man = new Man("Ravindra",40);
        System.out.println(man);
        
        Climb cm = man;
        cm.climb();
        Think t = man;
        t.think();
        Learn l = man;
        l.learn();
        Apply a = man;
        a.apply();
        
    }
}

abstract class Animal{
    String name;
    int lifeExpentency;
    public Animal(String name,int lifeExpentency ){
        this.name = name;
        this.lifeExpentency=lifeExpentency;
    }
    abstract public void remember();
    abstract public void protectOwner();
   
    public String toString(){
        return this.getClass().getSimpleName()+":"+name+":"+lifeExpentency;
    }
}
class Dog extends Animal implements Learn{
    
    public Dog(String name,int age){
        super(name,age);
    }
    public void remember(){
        System.out.println(this.getClass().getSimpleName()+" can remember for 5 minutes");
    }
    public void protectOwner(){
        System.out.println(this.getClass().getSimpleName()+ " will protect owner");
    }
    public void learn(){
        System.out.println(this.getClass().getSimpleName()+ " can learn:");
    }
}
class Cat extends Animal implements Climb {
    public Cat(String name,int age){
        super(name,age);
    }
    public void remember(){
        System.out.println(this.getClass().getSimpleName() + " can remember for 16 hours");
    }
    public void protectOwner(){
        System.out.println(this.getClass().getSimpleName()+ " won't protect owner");
    }
    public void climb(){
        System.out.println(this.getClass().getSimpleName()+ " can climb");
    }
}
interface Climb{
    public void climb();
}
interface Think {
    public void think();
}

interface Learn {
    public void learn();
}
interface Apply{
    public void apply();
}

class Man implements Think,Learn,Apply,Climb{
    String name;
    int age;

    public Man(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void think(){
        System.out.println("I can think:"+this.getClass().getSimpleName());
    }
    public void learn(){
        System.out.println("I can learn:"+this.getClass().getSimpleName());
    }
    public void apply(){
        System.out.println("I can apply:"+this.getClass().getSimpleName());
    }
    public void climb(){
        System.out.println("I can climb:"+this.getClass().getSimpleName());
    }
    public String toString(){
        return "Man :"+name+":Age:"+age;
    }
}

输出:

Dog:Dog:Tiger:16
Cat:Cat:July:20
Dog can remember for 5 minutes
Dog will protect owner
Dog can learn:
Cat can remember for 16 hours
Cat won't protect owner
Cat can climb
Man :Ravindra:Age:40
I can climb:Man
I can think:Man
I can learn:Man
I can apply:Man

理解的重点:

  1. 是动物,它们通过共享Animal中的name,lifeExpentency来扩展remember()和protectOwner()。
  2. 猫可以爬()但狗不行。狗可以思考()但猫不行。这些特定的能力是通过实现该能力来添加到CatDog中的。
  3. 人不是动物,但他可以Think,Learn,Apply,Climb

通过这些例子,您可以了解到:

无关的类可以通过接口具有能力,但相关的类通过扩展基类覆盖行为。


真的吗?我一直认为“有”指的是拥有某物,占有它。你可以说猫“有”攀爬能力,但我建议重新措辞你的例子。猫“是一个”攀登者,人“是一个”思考者、学习者、攀登者。既然人“是一个”思考者,他就能做一个思考者能做的事情。在使用某些协议时,这一点甚至更加清晰——如果你有一座房子,它有一扇门,但它没有实现推门把手。它也“是一个”物质对象,意味着它实现了服从重力的接口;它没有“服从重力技能”或类似的东西。 - MatthewRock
如果人是一个思考者,我将与extends建立关系而不是implements。思考者可能具有某些状态和其他角色/功能,但我只会通过接口实现思考能力。IS A是继承中使用的标准术语。 - Ravindra babu

52
如下图所示,一个类可以继承另一个类,一个接口可以继承另一个接口,但一个类实现一个接口。 enter image description here 要获取更多细节

2
如果这些数字使用了正确的UML符号(空心三角形),那么这个答案就完美了。 - Géry Ogam

44

extends是用于从基类继承功能的情况。

implements是用于实现接口的情况。

这里是一个很好的起点:接口和继承


25
"extends" 也用于当你要扩展一个接口时 :-). - Mark Peters

36

一个类只能"实现"一个接口。一个类只能"继承"一个类。同样,接口可以扩展另一个接口。

一个类只能继承一个其他的类。一个类可以实现多个接口。

如果你更关心何时使用抽象类和接口,请参考这个帖子:Interface vs Abstract Class (general OO)


33
一个接口是描述对象能做的操作的方式,例如当你翻转开关时,灯亮了,你不关心它是如何工作的,只关心它能否正常使用。在面向对象编程中,接口是描述对象必须具备的所有函数的方式,以便成为“X”。举个例子,任何“ACTS LIKE”灯的东西都应该有一个turn_on()方法和一个turn_off()方法。接口的目的是允许计算机强制执行这些属性,并知道类型T的对象(无论接口是什么)必须拥有称为X、Y、Z等函数。
一个接口是一种编程结构/语法,可以让计算机对对象(类)强制执行某些属性。例如,我们有一个汽车类、一个摩托车类和一个卡车类。这三个类中的每一个都应该有一个start_engine()动作。每个车辆启动引擎的方式由每个特定的类自己决定,但它们必须具备一个start_engine的动作,这是接口的领域。

27

这两个关键字都用于在Java语言中创建自己的新类。

区别: implements 表示您在类中使用了Java接口的元素。 extends 表示您正在创建一个基类的子类,您只能在子类中扩展一个类,但可以实现任意多个接口。

请参考oracle文档页面上有关接口的更多详细信息。

这有助于澄清接口是什么以及使用它们的约定。


26

Extends :该关键字用于将父类的属性引入到子类中,并且可以包含在子类中重写的已定义方法。

Implements :该关键字用于通过在子类中定义函数来实现接口(父类仅具有函数签名但没有定义)。

有一个特殊情况:“如果我想让一个新接口成为现有接口的子接口怎么办?” 在上述条件中,子接口extends父接口。


18
  • A extends B:

    A和B都是类或接口

  • A implements B:

    A是一个类,B是一个接口

  • 在Java中不合法的情况是A是一个接口,B是一个类。


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