Java中的接口是什么?

时间:2009-08-24 08:29:22

标签: java inheritance interface oop

正如this question的对立点:Java中的接口是什么?

13 个答案:

答案 0 :(得分:51)

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

interface Interface
{
    void interfaceMethod();
}

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

public interface Interface
{
    abstract public void interfaceMethod();
}

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

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");
    }
}

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

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"
}

但是,您可以从不执行以下操作:

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

    y.interfaceMethodB(); // ERROR!
    z.interfaceMethodA(); // ERROR!
}

您无法执行此操作的原因是y类型为interfaceAinterfaceMethodB()中没有interfaceA。同样,z的类型为interfaceBinterfaceMethodA()中没有interfaceB

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

interface Interface
{
    void abstractMethod();
}

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

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

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

public class InteritsFromAbstractClass
    extends AbstractClass
{
    public void abstractMethod() { System.out.println("abstractMethod()"); }
}

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

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()"); }
}

但是,接口和抽象类之间存在两个区别。

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

interface Interface
{
    public void implementedMethod()
    {
        System.out.println("implementedMethod()");
    }
}

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

abstract public class AbstractClass
{
    public void implementedMethod()
    {
        System.out.println("implementedMethod()");
    }
}

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

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

abstract public class AbstractClassA { }
abstract public class AbstractClassB { }
public class InheritsFromTwoAbstractClasses
    extends AbstractClassA, AbstractClassB
{ }

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

interface InterfaceA { }
interface InterfaceB { }
public class InheritsFromTwoInterfaces
    implements InterfaceA, InterfaceB
{ }    

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

interface InterfaceA
{
    void method();
}

interface InterfaceB
{
    void method();
}

public class InheritsFromTwoInterfaces
    implements InterfaceA, InterfaceB
{
    void method() { System.out.println("method()"); }
}

上面的代码没有问题,因为InterfaceAInterfaceB没有任何隐藏的内容。很容易判断对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
{ }

这与我们的其他示例完全相同,只是因为我们被允许在抽象类中实现方法,我们这样做,并且因为我们不必在继承类中实现已经实现的方法,所以我们没有“T。但你可能已经注意到了,这是一个问题。当我们致电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
{ }

AbstractClassAAbstractClassB是“mixins”或不打算实例化的类,但是通过继承将它们“混入”的类添加功能。如果你打电话给new InheritsFromTwoAbstractClasses().hi()new InheritsFromTwoAbstractClasses().bye(),显然没有问题,但你不能这样做,因为Java不允许这样做。

(我知道这是一篇很长的帖子,所以如果有任何错误请告诉我,我会更正。)

答案 1 :(得分:1)

接口是合同。一个简单的示例租户地主,它们是两方合同租赁协议。租金协议包含了租户必须遵循的各种条款。同样,接口是包含缔约方必须执行的各种方法(声明)的联系人(提供方法主体)。在此,一方是实现接口的类,第二方是客户,并且使用和接口的方式具有“参考”。接口”和“实现类的对象”:以下是3个组件:(在示例的帮助下解释)

组件1]界面:合同

interface myInterface{

 public void myMethod();

 }

组件2]实施类:参与者编号1

 class myClass implements myInterface {

 @Override

 public void myMethod() {

 System.out.println("in MyMethod");

 }

 }

组件3]客户代码:派对号码2

 Client.java

 public class Client {

 public static void main(String[] args) {

 myInterface mi = new myClass();

 // Reference of Interface = Object of Implementing Class

 mi.myMethod(); // this will print in MyMethod

 }

 }

答案 2 :(得分:1)

接口:系统需求服务。

描述:假设客户端需要一些功能“即JDBC API”接口和一些其他服务器 Apache,Jetty,WebServer ,它们都提供了此工具的实现。 因此,它限制了服务提供商向与这些服务器 Apache,Jetty,WebServer 进行数据连接的用户提供的需求文档。

答案 3 :(得分:0)

java中的接口 是一个类的蓝图。它只有静态常量和抽象方法.java中的接口是一种实现完全抽象的机制。 java接口中只能有抽象方法而不是方法体。它用于在Java中实现完全抽象和多继承。接口是抽象方法的集合。类实现接口,从而继承接口的抽象方法。 接口不是类。编写接口类似于编写类,但它们是两个不同的概念。类描述对象的属性和行为。接口包含类实现的行为(抽象方法)。 除非实现接口的类是抽象的,否则接口的所有方法都需要在类中定义。因为java中不允许多重继承,所以接口只能实现多重继承。 以下是理解界面

的示例
interface Printable{  
void print();  
}  

interface Showable{  
void print();  
}  

class testinterface1 implements Printable,Showable{  

public void print(){System.out.println("Hello");}  

public static void main(String args[]){  
testinterface1 obj = new testinterface1();  
obj.print();  
 }  
}

答案 4 :(得分:0)

界面是班级的蓝图。

有一个名为数据抽象的oop概念,其中有两个类别,一个是抽象类,另一个是接口

抽象类只实现部分抽象,但接口实现完全抽象。

在接口中只有抽象方法和最终变量。你可以扩展任意数量的接口,你可以实现任意数量的类。

如果任何类正在实现该接口,那么该类也必须实现抽象方法

无法实例化接口。

interface A() {
    void print()
}

答案 5 :(得分:0)

这个问题已经有6年了,很多事情多年来改变了界面的定义。

来自oracle documentation页面(发布Java 8后):

  

在Java编程语言中,接口是一种类似于类的引用类型,它只能包含常量,方法签名,默认方法,静态方法和嵌套类型。方法体仅适用于默认方法和静态方法。接口无法实例化 - 它们只能由类实现或由其他接口扩展。

查看相关的SE问题以获得更好的解释:

Is there more to an interface than having the correct methods

What is the difference between an interface and abstract class?

答案 6 :(得分:0)

它是什么
接口是一种引用类型,就像一样。这些是Java中的两个主要引用类型。

包含的内容
接口可以包含普通可以包含的子集。这包括static,方法和变量以及非static方法声明的所有内容。不允许使用非static个变量。
方法的声明在几个方面不同于常规方法;这里有一个例子:

[public] [abstract] ReturnType methodName();

这些声明可以标记为publicabstract,用[optional braces]表示。没有必要这样做,因为它是默认值。 privateprotectedpackage-private(aka。nothing)和final修饰符不被允许并标记为编译器错误。它们没有实现,所以有一个分号而不是花括号。

从Java 8开始,他们可以使用实现 。但是,适用与其他修饰符相同的限制(添加static现在有效且default不再有效。)

有用的内容
它的一个用途是将其用作服务的面孔。当双方共同努力形成服务请求者时,服务提供者类型的关系,服务提供者以接口的形式提供服务的面貌(关于服务的外观)。
其中一个OOP概念是"抽象"这意味着隐藏系统的复杂工作并仅显示理解系统所需的内容。这有助于可视化复杂系统的工作。 这可以通过 interface 来实现,其中每个模块都可视化(并且也实现)以通过另一个模块的接口工作

答案 7 :(得分:0)

一般情况下,当我们有两个更多的实现时,我们更喜欢接口。其中接口充当协议。

编码到接口,而不是实现编码到接口会松散地耦合。

接口是Java中的引用类型。它类似于类。它是抽象方法的集合。类实现接口,从而继承接口的抽象方法。除抽象方法外,接口还可以包含常量,默认方法,静态方法和嵌套类型。更多details

答案 8 :(得分:0)

接口是一个类似于类的结构,它只包含常量和抽象方法(java编程简介,n.d。)。而且,它可以扩展多个接口,例如Superclass。 Java只允许单继承用于类扩展,但允许多个扩展 接口(Java编程简介,n.d。)例如,

public class NewClass extends BaseClass
implements Interface1, ..., InterfaceN {
    ...
}

其次,接口可用于指定类中对象的行为。但是,它们不能包含抽象方法。此外,接口可以使用extends关键字继承其他接口。

public interface NewInterface extends Interface1, ... , InterfaceN {

}

参考

Java编程简介。接口和抽象类(n.d)。 2017年3月10日从https://viewer.gcu.edu/7NNUKW

检索

答案 9 :(得分:0)

根据Oracle的最新定义,界面为:

  

在软件工程中有很多情况   对于不同的程序员群体来说,同意“合同”很重要   说明了他们的软件如何交互。每个小组应   能够编写自己的代码而无需其他知识   编写小组代码。一般来说,接口是这样的   合同。

     

例如,想象一个未来的社会,其中计算机控制   机器人汽车将乘客运送到没有人的城市街道上   操作员。汽车制造商编写软件(当然是Java)   操纵汽车-停止,启动,加速,向左转和   等等。另一个工业集团,电子制导仪   制造商,制造可接收GPS的计算机系统(全球   定位系统)定位数据和交通无线传输   条件并使用这些信息来开车。

     

汽车制造商必须发布行业标准界面   详细说明了可以调用哪些方法来制造汽车   移动(任何制造商的任何汽车)。指导厂家可以   然后编写软件,以调用   指挥车的界面。两家工业集团都不需知道   另一小组的软件如何实施。实际上,每个组   认为其软件是高度专有的,并保留以下权利:   只要它继续遵守   已发布的界面。

     

[...]接口是类似于类的引用类型,可以   仅包含常量,方法签名,默认方法,静态   方法和嵌套类型。方法主体仅默认存在   方法和静态方法。接口无法实例化-它们   只能由类实现或由其他接口扩展。

接口的最流行用法是作为API(应用程序编程接口),在商业软件产品中很常见。通常,一家公司出售的软件包包含另一家公司要在其自己的软件产品中使用的复杂方法。

一个例子可能是一整套数字图像处理方法,这些方法被出售给制作最终用户图形程序的公司。

图像处理公司编写其类来实现一个接口,该接口向客户公开。然后,图形公司使用接口中定义的签名和返回类型来调用图像处理方法。在图像处理公司的API(向其客户)公开的同时,其API的实现仍被严格保密,实际上,只要它继续实现原始接口,它就可能在以后修改实现。它的客户所依赖的。

退回到learn more about interfaces

答案 10 :(得分:0)

除了其他人提到的内容之外,通过不合逻辑的比较 这是包装方法的框架,因此可以将它们存储在变量。

因此,从这个意义上讲,您可以随时将接口变量等同于任何方法或方法集合,通常要这样做的一个好理由是逃避肯定会出现的重复逻辑在代码半衰期内以任何衰减速度成为进度敌人的情况下,请谨慎考虑以下用户自行决定的情况。

场景

您在drawSillyThings()类中有一个带有SoulAvenger方法的游戏,该游戏必须绘制一些框架或精灵。现在drawSillyThings()有了其他方法的列表,在用户杀死 goulified-soul-ranger > 5k级别的> grim-reaper ,即drawSillyThings()需要调用inviteTheGrimReaper()drawUpperCut()drawTotalKO()drawVictoryAndGlorifiedRanger()中的任何一个,drawDefeatAndMockery()drawFightRecap()drawGameOver(),只要在游戏体验期间出现正确的情况,但所有这些都会导致drawSillyThings()中出现不需要的逻辑,这可能会减慢游戏速度,即

public static class SoulAvenger{

        public SoulAvenger(){
             //constructor logic
        }

        private void loadLevel5k(){...}

        private void dontAllowUserWinOnTime(){...}

        private void loadGrimReaperFight(){...}

        private void drawSillyThings(){
            ... //unaccounted game logic
            while(fighting_in_level_5k){
                while(soul_ranger_has_enough_lives){
                    if(game_state=fight)inviteTheGrimReaper();
                    else if(game_state=medium_blows)drawUpperCut();
                    else if(game_state=heavy_blows)drawTotalKO();
                    else if(game_state=lost)drawDefeatAndMockery();
                    else if(game_state=won)drawVictoryAndGlorifiedRanger();
                    else if(game_state=end)drawFightRecap();
                }else drawGameOver();
            }
        }
}

这里的问题是,每次 soul-ranger 仍然有效时,都必须执行循环嵌套的布尔检查。该类可确保drawSillyThings()不需要每次都检查game_state来调用正确的方法,但为此,您需要将正确的方法存储在变量中,以便随后,您可以variable = new method,也可以variable.invoke()。如果不是那样的话

public static class InterfaceTest{

    public interface Method{
        public void invoke();
    }

    public static void main(String[] args){
        //lets create and store a method in a variable shall we
        Method method_variable=new Method(){
            @Override
            public void invoke(){
                //do something        
            }
        };

        //lets call or invoke the method from the variable in order to do something
        method_variable.invoke();

        //lets change the method to do something else
        method_variable=new Method(){
            @Override
            public void invoke(){
                //do something else       
            }
        };

        //lets do something else
        method_variable.invoke();            

     }

}

这可能是 oracle 的人发现Java几年来所缺少的东西,之前有传言称一些开发人员计划进行大规模抗议,但后来回到SoulAvenger,因为游戏发生时,您肯定只是想让变量等同于提供正确的方法,以便在drawSillyThings()中进行调用,从而以一种愚蠢的方式运行事物

public static class SoulAvenger{

    private interface SillyRunner{
        public void run_things();
    }

    ...//soul avenging variables
    private SillyRunner silly_runner;

    public SoulAvenger(int game_state){
        //logic check is performed once instead of multiple times in a nested loop
        if(game_state=medium_blows){
            silly_runner=new SillyRunner(){
                @Override
                public void run_things(){
                    drawUpperCut();
                }
            };
        }else if(game_state=heavy_blows){
            silly_runner=new SillyRunner(){
                @Override
                public void run_things(){
                    drawTotalKO();
                }
            };
        }else if(game_state=lost){
            silly_runner=new SillyRunner(){
                @Override
                public void run_things(){
                    drawDefeatAndMockery();
                }
            };
        }else if(game_state=won){
            silly_runner=new SillyRunner(){
                @Override
                public void run_things(){
                    drawVictoryAndGlorifiedRanger();
                }
            };
        }else if(game_state=fight){
            silly_runner=new SillyRunner(){
                @Override
                public void run_things(){
                    drawFightRecap();
                }
            };

        }

    }

    private void loadLevel5k(){
        //an event triggered method to change how you run things to load level 5k
        silly_runner=new SillyRunner(){
            @Override
            public void run_things(){
                //level 5k logic
            }
        };
    }

    private void dontAllowUserWinOnTime(){
        //an event triggered method to help user get annoyed and addicted to the game
        silly_runner=new SillyRunner(){
            @Override
            public void run_things(){
                drawDefeatAndMockery();
            }
        };
    }

    private void loadGrimReaperFight(){
        //an event triggered method to send an invitation to the nearest grim-reaper
        silly_runner=new SillyRunner(){
            @Override
            public void run_things(){
                inviteTheGrimReaper();
            }
        };
    }

    private void drawSillyThings(){
        ...//unaccounted game logic
        while(fighting_in_level_5k){
            while(soul_ranger_has_enough_lives){
                silly_runner.run_things();
            }
        }
    }

}

现在drawSillyThings()不需要在绘制时执行任何 if 逻辑,因为当触发正确的事件时,silly_runner就等同于具有run_things()方法调用了一个不同的方法,因此使用了一个变量来存储和调用某种方法,尽管在实际的游戏世界中(我实际上是在控制台中),多个线程将异步工作以更改接口变量以运行不同的片段具有相同调用的代码。

答案 11 :(得分:0)

java中的接口是Abstract类的一种特殊类型,该Interface提供了100%抽象,但是由于java在java 8中引入了新功能,因此整个Interface的含义都在改变。接口用于指示应执行的操作。但是由于现在有了新功能,我们在Interface中提供了方法的实现,从而改变了Interface的含义。 在“界面”中,默认情况下该方法是公共抽象

interface Bird{
        void sound();
         void eat();
        }

Java不提供多重继承功能,这意味着一个类没有两个父级,但是我们在Java中扩展了多个接口。

答案 12 :(得分:0)

接口是系统与外部环境之间的契约。更具体地说,Java - 类(针对特定行为)的契约,以类似于纯抽象类的形式实现。