Java中的接口是什么?

Ima*_*ist 32 java oop inheritance interface

正如这个问题的对立点:Java中的接口是什么?

Ima*_*ist 53

接口是抽象类的一种特殊形式,它不实现任何方法.在Java中,您可以创建如下界面:

interface Interface
{
    void interfaceMethod();
}
Run Code Online (Sandbox Code Playgroud)

由于接口无法实现任何方法,因此暗示整个事物(包括所有方法)都是公共的和抽象的(Java术语中的抽象意味着"不是由此类实现的").所以上面的界面与下面的界面相同:

public interface Interface
{
    abstract public void interfaceMethod();
}
Run Code Online (Sandbox Code Playgroud)

要使用此界面,您只需实现该界面即可.许多类可以实现一个接口,一个类可以实现许多接口:

interface InterfaceA
{
     void interfaceMethodA();
}

interface InterfaceB
{
    void interfaceMethodB();
}

public class ImplementingClassA
    implements InterfaceA, InterfaceB
{
    public void interfaceMethodA()
    {
        System.out.println("interfaceA, interfaceMethodA, implementation A");
    }

    public void interfaceMethodB()
    {
        System.out.println("interfaceB, interfaceMethodB, implementation A");
    }
}

public class ImplementingClassB
    implements InterfaceA, InterfaceB
{
    public void interfaceMethodA()
    {
         System.out.println("interfaceA, interfaceMethodA, implementation B");
    }

    public void interfaceMethodB()
    {
        System.out.println("interfaceB, interfaceMethodB, implementation B");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果你想要,你可以写一个像这样的方法:

public void testInterfaces()
{
    ImplementingClassA u = new ImplementingClassA();
    ImplementingClassB v = new ImplementingClassB();
    InterfaceA w = new ImplementingClassA();
    InterfaceA x = new ImplementingClassB();
    InterfaceB y = new ImplementingClassA();
    InterfaceB z = new ImplementingClassB();

    u.interfaceMethodA();
    // prints "interfaceA, interfaceMethodA, implementation A"
    u.interfaceMethodB();
    // prints "interfaceB, interfaceMethodB, implementation A"
    v.interfaceMethodA();
    // prints "interfaceA, interfaceMethodA, implementation B"
    v.interfaceMethodB();
    // prints "interfaceB, interfaceMethodB, implementation B"
    w.interfaceMethodA();
    // prints "interfaceA, interfaceMethodA, implementation A"
    x.interfaceMethodA();
    // prints "interfaceA, interfaceMethodA, implementation B"
    y.interfaceMethodB();
    // prints "interfaceB, interfaceMethodB, implementation A"
    z.interfaceMethodB();
    // prints "interfaceB, interfaceMethodB, implementation B"
}
Run Code Online (Sandbox Code Playgroud)

但是,您永远不能执行以下操作:

public void testInterfaces()
{
    InterfaceA y = new ImplementingClassA();
    InterfaceB z = new ImplementingClassB();

    y.interfaceMethodB(); // ERROR!
    z.interfaceMethodA(); // ERROR!
}
Run Code Online (Sandbox Code Playgroud)

你不能这样做的原因是,y是类型的interfaceA,并没有interfaceMethodB()interfaceA.同样地,z是类型的interfaceB,也没有interfaceMethodA()interfaceB.

我之前提到过,接口只是抽象类的一种特殊形式.为了说明这一点,请查看以下代码.

interface Interface
{
    void abstractMethod();
}

abstract public class AbstractClass
{
    abstract public void abstractMethod();
}
Run Code Online (Sandbox Code Playgroud)

您将从这些类继承几乎完全相同的方式:

public class InheritsFromInterface
    implements Interface
{
    public void abstractMethod() { System.out.println("abstractMethod()"); }
}

public class InteritsFromAbstractClass
    extends AbstractClass
{
    public void abstractMethod() { System.out.println("abstractMethod()"); }
}
Run Code Online (Sandbox Code Playgroud)

实际上,您甚至可以像这样更改接口和抽象类:

interface Interface
{
    void abstractMethod();
}

abstract public class AbstractClass
    implements Interface
{
    abstract public void abstractMethod();
}

public class InheritsFromInterfaceAndAbstractClass
    extends AbstractClass implements Interface
{
    public void abstractMethod() { System.out.println("abstractMethod()"); }
}
Run Code Online (Sandbox Code Playgroud)

但是,接口和抽象类之间存在两个差异.

第一个区别是接口无法实现方法.

interface Interface
{
    public void implementedMethod()
    {
        System.out.println("implementedMethod()");
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的接口生成编译器错误,因为它有一个实现implementedMethod().如果你想实现该方法但不能实例化该类,你必须这样做:

abstract public class AbstractClass
{
    public void implementedMethod()
    {
        System.out.println("implementedMethod()");
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是一个抽象类,因为它的成员都不是抽象的,但它是合法的Java.

接口和抽象类之间的另一个区别是类可以从多个接口继承,但只能从一个抽象类继承.

abstract public class AbstractClassA { }
abstract public class AbstractClassB { }
public class InheritsFromTwoAbstractClasses
    extends AbstractClassA, AbstractClassB
{ }
Run Code Online (Sandbox Code Playgroud)

上面的代码生成了一个编译器错误,不是因为这些类都是空的,而是因为InheritsFromTwoAbstractClasses它试图从两个抽象类继承,这是非法的.以下是完全合法的.

interface InterfaceA { }
interface InterfaceB { }
public class InheritsFromTwoInterfaces
    implements InterfaceA, InterfaceB
{ }    
Run Code Online (Sandbox Code Playgroud)

接口和抽象类之间的第一个区别是第二个区别的原因.看看下面的代码.

interface InterfaceA
{
    void method();
}

interface InterfaceB
{
    void method();
}

public class InheritsFromTwoInterfaces
    implements InterfaceA, InterfaceB
{
    void method() { System.out.println("method()"); }
}
Run Code Online (Sandbox Code Playgroud)

有上面,因为代码没有问题InterfaceA,并InterfaceB没有什么要隐瞒.很容易判断调用method将打印"method()".

现在看下面的代码:

abstract public class AbstractClassA
{
    void method() { System.out.println("Hello"); }
}

abstract public class AbstractClassB
{
    void method() { System.out.println("Goodbye"); }
}

public class InheritsFromTwoAbstractClasses
    extends AbstractClassA, AbstractClassB
{ }
Run Code Online (Sandbox Code Playgroud)

这与我们的其他示例完全相同,只是因为我们允许在抽象类中实现方法,我们这样做,并且因为我们不必在继承类中实现已经实现的方法,所以我们没有.但你可能已经注意到了,这是一个问题.我们打电话会发生什么new InheritsFromTwoAbstractClasses().method()?它会打印"Hello"还是"Goodbye"?您可能不知道,Java编译器也不知道.另一种语言,C++允许这种继承,他们以通常非常复杂的方式解决了这些问题.为了避免这种麻烦,Java决定将这种"多重继承"定为非法.

Java解决方案的缺点是无法完成以下任务:

abstract public class AbstractClassA
{
    void hi() { System.out.println("Hello"); }
}

abstract public class AbstractClassB
{
    void bye() { System.out.println("Goodbye"); }
}

public class InheritsFromTwoAbstractClasses
    extends AbstractClassA, AbstractClassB
{ }
Run Code Online (Sandbox Code Playgroud)

AbstractClassA并且AbstractClassB是"mixins"或不打算实例化的类,但是通过继承将它们"混入"的类添加功能.显然没有问题,如果你打电话new InheritsFromTwoAbstractClasses().hi()或者发现会发生什么new InheritsFromTwoAbstractClasses().bye(),但你不能这样做,因为Java不允许这样做.

(我知道这是一个很长的帖子,所以如果有任何错误,请告诉我,我会纠正它们.)

  • 一句小话,你称你的类为"InheritsFromTwoInterfaces",但是当你使用接口时,你通常不会谈论继承,而是实现,这是因为接口不包含你可以继承的任何逻辑和/或实现.因此,最好谈谈实施(至少他们是学习我的). (5认同)
  • @Gertjan你是对的.但是,我认为"继承"和"实现"之间的区别并不重要,特别是考虑到在很多情况下,一个都继承并实现了一个抽象类.我选择保持命名方案不那么混乱. (2认同)