为什么要使用接口,多重继承与接口,接口的好处?

问题描述 投票:58回答:12

我对这件事情仍然有些困惑。我到现在所发现的是

(这里已经提出了类似的问题,但我还有其他一些观点。)

  1. 接口是仅抽象方法和最终字段的集合。
  2. Java中没有多重继承。
  3. 接口可用于在Java中实现多重继承。
  4. 继承的一个优点是我们可以在派生类中使用基类代码而无需再次编写它。可能这是继承在那里最重要的事情。

现在..

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

那么为什么要制作接口呢?

注意:我找到了一个接口有用的案例。它的一个例子就像在Runnable接口中我们有public void run()方法,我们在其中定义线程的功能,并且内置编码,该方法将作为单独的线程运行。所以我们只需要编写线程中的代码,Rest是预定义的。但是这个东西也可以用抽象类和所有东西来实现。

那么使用接口的确切好处是什么?我们使用Interfaces实现了多重继承吗?

java oop inheritance interface multiple-inheritance
12个回答
35
投票

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

我们做不到。接口不用于实现多重继承。他们用更安全但更弱的构造来代替它。请注意关键字implements而不是extends

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

他们不是。使用接口,单个类可以具有多个“视图”,不同的API或功能。例如。一个类可以同时是RunnableCallable,而两种方法都有效地做同样的事情。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

接口是一种多重继承,没有后者引入的问题(如Diamond problem)。

接口的用例很少:

  1. 对象有效地具有两个身份:Tank既是Vehicle又是Weapon。您可以使用Tank的实例,其中前者或后者是预期的(多态)。这在现实生活中很少出现,实际上是多重继承更好(或特征)的有效例子。
  2. 简单的职责:游戏中的Tank对象的实例也是Runnable,让你在线程和ActionListener中执行它来响应鼠标事件。
  3. 回调接口:如果对象实现了给定的回调接口,则会通知它有关其生命周期或其他事件的信息。
  4. 标记接口:不添加任何方法,但可以通过instanceof轻松访问以发现对象功能或愿望。 SerializableCloneable就是这方面的例子。

你正在寻找的是特质(就像在Scala中一样),遗憾的是在Java中不可用。


0
投票

进行接口以使类在接口内实现功能并根据该接口进行操作。


0
投票

所以。这里有很多优秀的答案,详细解释了界面是什么。然而,这是其使用的一个例子,就像我最好的同事多年前曾向我解释过的那样,我在过去几年里在大学学到的东西混杂在一起。

界面是一种“契约”。它公开了一些可用的方法,字段等。它没有透露任何实现细节,只揭示它返回的内容,以及它需要的参数。在这里是问题三的答案,我觉得现代OOP的最大优势之一:

“添加代码,不修改” - Magnus Madsen,AAU

这至少就是他所说的,他可能会从其他地方获得它。下面的示例代码是用C#编写的,但是所有显示的内容都可以在Java中以相同的方式完成。

我们看到的是一个名为SampleApp的类,它有一个字段,即IOContext。 IOContext是一个接口。 SampleApp并不关心它如何保存它的数据,它只需要在其“doSomething()”方法中这样做。

我们可以想象,在开发过程开始时,保存数据可能比保存数据更重要,因此,开发人员选择简单地编写FileContext类。然而,稍后,无论出于何种原因,他都需要支持JSON。所以他编写了JSONFileContext类,它继承了FileContext。这意味着它实际上是一个IOContext,它具有FileContext的功能,保存FileContexts SaveData和LoadData的替换,它仍然使用它的'write / read'方法。

与编写类相比,实现JSON类只需要少量工作,并且只需继承IOContext即可。

SampleApp的领域可能只是'FileContext'类型,但是这样,它将被限制为只使用该类的子类。通过创建接口,我们甚至可以执行SQLiteContext实现,并写入数据库,SampleApp永远不会知道或关心,当我们编写sql lite类时,我们只需要对代码进行一次更改:new JSONFileContext();而不是变成new SQLiteContext();

我们仍然有旧的实现,如果需要,可以切换回那些。我们没有什么破坏,我们代码的所有更改都是半行,可以在眨眼之间改变。

所以:代码加法,不是修改。

namespace Sample
{
    class SampleApp
    {
        private IOContext context;

        public SampleApp()
        {
            this.context = new JSONFileContext(); //or any of the other implementations
        }

        public void doSomething()
        {
            //This app can now use the context, completely agnostic of the actual implementation details.
            object data = context.LoadData();
            //manipulate data
            context.SaveData(data);
        }
    }

    interface IOContext
    {
        void SaveData(object data);
        object LoadData();
    }

    class FileContext : IOContext
    {
        public object LoadData()
        {

            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            writeFileContents(string.Empty);
        }

        protected void writeFileContents(string fileContents)
        {
            //writes the fileContents to disk
        }

        protected string loadFileContents()
        {
            string fileContents = string.Empty;
            //loads the fileContents and returns it as a string
            return fileContents;
        }
    }

    class JSONFileContext : FileContext
    {
        public new void SaveData(object data)
        {
            //logic to create filecontents from 'data'
            base.writeFileContents(string.Empty);
        }

        public new object LoadData()
        {
            object data = null;
            var fileContents = loadFileContents();
            //Logic to turn fileContents into a data object
            return data;
        }
    }

    class SQLiteContext : IOContext
    {
        public object LoadData()
        {
            object data = null;
            //logic to read data into the data object
            return data;
        }

        public void SaveData(object data)
        {
            //logic to save the data object in the database
        }
    }
}

-1
投票

Interfaces

接口是定义如何与对象交互的契约。它们可用于表达内部构件如何与对象进行交互。在依赖性反转之后,您的公共API将使用接口表示所有参数。你不关心它是如何完成你需要它做的,只是它完全按照你的需要去做。

示例:您可能只需要一个Vehicle来运输货物,您不关心特定的运输方式。

Inheritance

继承是特定实现的扩展。该实现可能满足也可能不满足特定接口。只有在关心方法时,才应该期待特定实现的祖先。

示例:您可能需要使用Plane实现车辆以实现快速运输。

Composition

组合可以用作继承的替代方法。它不是扩展基类的类,而是使用实现主类责任的较小部分的对象创建的。组成用于facade patterndecorator pattern

示例:您可以创建一个DuckBoatDUKW)类来实现LandVehicleWaterVehicle,它们都实现了由VehicleTruck实现组成的Boat

Answers

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

接口不是继承。实现接口表示您希望类以接口定义的方式运行。继承是指您拥有共同的祖先,并且您获得与祖先相同的行为(inherit),因此您无需定义它。

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

接口不实现多重继承。他们表示一个班级可能适合多个角色。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

接口的主要好处之一是提供关注点分离:

  • 您可以编写一个与另一个类执行某些操作的类,而无需关心该类的实现方式。
  • 任何未来的开发都可以与您的实现兼容,而无需扩展特定的基类。

根据DRY的精神,如果你利用组合,你可以编写一个满足界面并改变它的实现,同时仍然尊重open/closed principal


20
投票

接口是最终静态字段和抽象方法的集合(Newly Java 8增加了对在接口中使用静态方法的支持)。

接口是在我们知道必须完成某项任务的情况下进行的,但是如何完成它可能会有所不同。换句话说,我们可以说我们实现了接口,以便我们的类开始以特定的方式运行。

让我用一个例子来解释,我们都知道动物是什么。像狮子是动物,猴子是动物,大象是动物,牛是动物,等等。现在我们知道所有动物都吃东西睡觉了。但每只动物吃东西或睡觉的方式可能不同。像狮子一样,通过狩猎其他动物来吃东西,就像母牛吃草一样。但两人都吃。所以我们可以有这样的伪代码,

interface Animal {
    public void eat();
    public void sleep();   
}

class Lion implements Animal {
    public void eat() {
        // Lion's way to eat
    }

    public void sleep(){
         // Lion's way to sleep
    }
}

class Monkey implements Animal {
    public void eat() {
        // Monkey's way to eat
    }

    public void sleep() {
        // Monkey's way to sleep
    }
}

根据上面提到的伪代码,任何能够进食或睡觉的东西都会被称为动物,或者我们可以说所有动物都必须吃饭和睡觉,但吃饭和睡觉的方式取决于动物。

在接口的情况下,我们只继承行为,而不是类继承的实际代码。

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

实现接口是另一种继承。它与类的继承类似,因为继承子类获取了从基类重用的实际代码。

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

据说是因为一个类可以实现多个接口。但我们需要了解这种继承与类的继承不同。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

实现一个接口会强制它必须覆盖所有抽象方法的类。

在我的书herehere中阅读更多内容


9
投票

我已经搜索了几天,试图了解接口并且似乎阅读相同的通用帮助;我并不是要贬低这些贡献,但我认为灯泡只是点击了所以我很喜欢:))

我更喜欢保持简单愚蠢,因此将提供我新发现的界面视图。

我是一个随便的编码器,但我想发布我在VB.NET中编写的代码(其他语言的原理是相同的),以帮助其他人理解接口。

如果我错了,请在后续评论中告诉其他人。

说明

表单上的三个按钮,单击每个按钮可以保存对接口变量(_data)的不同类引用。不同类引用到接口变量的整点是我不理解的,因为它似乎是多余的,然后它的功能随着msgbox变得明显,我只需要调用SAME方法来执行我需要的任务,在此case'GetData()',它使用当前由接口引用变量(_data)保存的类中的方法。

因此,我想获取我的数据(来自数据库,网络或文本文件),它只使用相同的方法名称;该实现背后的代码......我不在乎。

然后使用接口更改每个类代码很容易,没有任何依赖性...这是OO和封装的关键目标。

何时使用

代码类,如果您注意到用于方法的相同动词,例如'GetData()',那么它是在该类上实现接口并将该方法名称用作抽象/接口的良好候选者。

我真诚地希望这可以帮助这个困难原则的老板。

Public Class Form1

Private _data As IData = Nothing

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    _data = New DataText()
    MsgBox(_data.GetData())
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    _data = New DataDB()
    MsgBox(_data.GetData())
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    _data = New DataWeb()
    MsgBox(_data.GetData())
End Sub

End Class

Public Interface IData
Function GetData() As String
End Interface

Friend Class DataText : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataText"
End Function

End Class

Friend Class DataDB : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataDB"
End Function

End Class

Friend Class DataWeb : Implements IData

Friend Function GetData() As String Implements IData.GetData
    Return "DataWeb"
End Function

End Class

6
投票

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

不幸的是,在口语用法中,当一个类实现一个接口时,仍然经常使用inheritance这个词,尽管interface implementation是一个更好的术语 - IMO,术语inheritance应该严格地用于具体或抽象类的继承。在像C ++和C#这样的语言中,相同的语法(即Subclass : SuperclassClass : Interface)用于类继承和接口实现,这可能导致使用接口滥用单词inheritance的传播。对于extending类而言,Java有不同的语法,而不是implementing接口,这是一件好事。

Q2如果实现接口不是继承,那么如何使用接口来实现多重继承?

您可以通过组合实现多重继承的“效果” - 通过在类上实现多个接口,然后为类中所有接口所需的所有方法,属性和事件提供实现。使用具体类执行此操作的一种常见技术是通过将实现“连接”到每个内部类实现来实现外部接口的类来实现“has-a”(组合)关系。 (像C ++这样的语言确实直接支持多个具体继承,但是会产生其他潜在问题,比如钻石问题)。

Q3无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

接口允许现有类(例如框架)与您的新类进行交互,而无需事先“看到”它们,因为它具有通过已知接口进行通信的能力。将接口视为合同。通过在类上实现此接口,您在合同中必须满足其所需的义务,并且一旦实现此合同,那么您的类应该能够与使用该接口的任何其他代码互换使用。

真实世界的例子

“现实世界”的例子是围绕特定国家的电壁式插座的立法和惯例(界面)。插入插座的每个电器需要满足当局为插座定义的规范(合同),例如,线路,中性线和地线的定位,开/关开关的位置和颜色,以及开启时通过interface提供的电压,频率和最大电流的一致性。

将接口(即标准壁式插座)分离而不仅仅是将电线焊接在一起的好处是,您可以插入(和拔下)风扇,水壶,双适配器或明年发明的一些新设备,即使设计界面时该设备不存在。为什么?因为它符合界面的要求。

为何使用接口?

接口非常适合松散耦合类,并且是Bob叔叔的SOLID范例的主要内容之一,尤其是Dependency Inversion PrincipleInterface Segregation Principles

简单地说,通过确保类之间的依赖关系仅在接口(抽象)上而不是在其他具体类上耦合,它允许依赖性替换为满足接口要求的任何其他类实现。

在测试中,依赖项的存根和模拟可用于对每个类进行单元测试,并且类可以“依赖”该类与依赖项的交互。


5
投票

这是一个非常古老的问题,java-8版本为界面添加了更多功能和强大功能。

接口声明可以包含

  1. 方法签名
  2. 默认方法
  3. 静态方法
  4. 不变的定义。

在接口中具有实现的唯一方法是默认和静态方法。

使用界面:

  1. 定义合同
  2. 链接不相关的类具有一定的功能(例如,实现Serializable接口的类可能有也可能没有它们之间的任何关系,除了实现该接口
  3. 提供可互换的实施,例如Strategy_pattern
  4. 默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性
  5. 使用静态方法在库中组织辅助方法(可以在同一个接口中保留特定于接口的静态方法,而不是在单独的类中)

看看这个相关的SE问题代码示例,以便更好地理解概念:

How should I have explained the difference between an Interface and an Abstract class?

回到你的问题:

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

接口可以包含静态和默认方法的代码。这些默认方法提供向后兼容性,静态方法提供帮助/实用程序功能。

你不能在java中拥有真正的多重继承,并且接口不是获取它的方法。接口只能包含常量。所以你不能继承状态,但你可以实现行为。

您可以使用功能替换继承。接口提供了多种实现类的功能。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

请参阅我的答案中的“界面使用”部分。


3
投票

继承是指一个类派生自另一个类(可以是抽象的)或接口。面向对象(继承)的最强点不是代码的重用(有很多方法可以做到),而是多态性。

多态性是指您拥有使用接口的代码,它的实例对象可以是从该接口派生的任何类。例如,我可以有这样一个方法:public void Pet(IAnimal animal)和这个方法将得到一个对象,它是从IAnimal继承的Dog或Cat的实例。或者我可以有这样的代码:IAnimal animal然后我可以调用这个接口的方法:animal.Eat(),Dog或Cat可以用不同的方式实现。

接口的主要优点是你可以从其中一些继承,但是如果你只需要从一个继承,你也可以使用一个抽象类。这篇文章更详细地解释了抽象类和接口之间的区别:http://www.codeproject.com/KB/cs/abstractsvsinterfaces.aspx


2
投票

老问题。令我惊讶的是没有人引用规范来源:Java:James Gosling的概述,设计模式:四人帮的可重用面向对象软件的元素或Joshua Bloch的有效Java(以及其他来源)。

我将从一个引用开始:

接口只是对象响应的一组方法的规范。它不包含任何实例变量或实现。接口可以是多重继承的(与类不同),并且它们可以比通常的刚性类继承结构更灵活地使用。 (Gosling,第8页)

现在,让我们逐一考虑你的假设和问题(我会自愿忽略Java 8的功能)。

Assumptions

接口是仅抽象方法和最终字段的集合。

您是否在Java接口中看到关键字abstract?不。那么你不应该将接口视为抽象方法的集合。也许你被C ++所谓的接口所误导,这些接口只有纯虚方法。 C ++在设计上没有(也不需要)接口,因为它具有多重继承。

正如Gosling所解释的,您应该将接口视为“一组对象响应的方法”。我喜欢将界面和相关文档视为服务合同。它描述了您可以从实现该接口的对象中获得的内容。文档应指定前置和后置条件(例如,参数不应为空,输出始终为正,...)和不变量(不修改对象内部状态的方法)。我认为,这份合同是OOP的核心。

Java中没有多重继承。

确实。

JAVA省略了许多很少使用,知之甚少,令人困惑的C ++特性,这些特性在我们的经验中带来了更多的悲伤而不是利益。这主要包括运算符重载(尽管它确实有方法重载),多重继承和广泛的自动强制。 (Gosling,第2页)

没有什么可补充的。

接口可用于在Java中实现多重继承。

不,simlpy因为Java中没有多重继承。往上看。

继承的一个优点是我们可以在派生类中使用基类代码而无需再次编写它。可能这是继承在那里最重要的事情。

这就是所谓的“实现继承”。正如您所写,这是重用代码的便捷方式。

但它有一个重要的对应物:

父类通常至少定义其子类的物理表示的一部分。因为继承将子类暴露给其父实现的细节,所以通常会说“继承会破坏封装”[Sny86]。子类的实现与其父类的实现紧密相关,父类实现中的任何更改都将强制子类发生更改。 (GOF,1.6)

(Bloch,第16项也有类似的引用。)

实际上,继承还有另一个目的:

类继承结合了接口继承和实现继承。接口继承根据一个或多个现有接口定义新接口。实现继承根据一个或多个现有实现定义新实现。 (GOF,附录A)

两者都在Java中使用关键字extends。您可能具有类和接口层次结构的层次结构。第一个分享实施,第二个分担义务。

Questions

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现任何接口那么它是继承?我们没有使用它的代码。**

接口的实现不是继承。这是实施。因此关键字implements

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?**

Java中没有多重继承。往上看。

Q3。无论如何使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中一次又一次地编写代码。那么为什么要创建接口?/使用接口的确切好处是什么?我们使用Interfaces实现了多重继承吗?

最重要的问题是:为什么你想要多重继承?我可以想到两个答案:1。给一个对象提供多种类型; 2.重用代码。

Give mutliple types to an object

在OOP中,一个对象可能具有不同的类型。例如在Java中,ArrayList<E>有以下类型:SerializableCloneableIterable<E>Collection<E>List<E>RandomAccessAbstractList<E>AbstractCollection<E>Object(我希望我没有忘记任何人)。如果对象具有不同类型,则各种消费者将能够使用它而不了解其特性。我需要一个Iterable<E>,你给我一个ArrayList<E>?没关系。但是,如果我现在需要一个List<E>,你给我一个ArrayList<E>,它也没关系。等等。

如何在OOP中键入对象?你以Runnable界面为例,这个例子很适合说明这个问题的答案。我引用官方Java文档:

此外,Runnable提供了一个类活动而不是继承Thread的方法。

重点是:继承是一种输入对象的便捷方式。你想创建一个线程?让我们继承Thread类。你想要一个对象有不同的类型,让我们使用mutliple-inheritance。哎呀。它在Java中不存在。 (在C ++中,如果您希望对象具有不同的类型,则可以采用多重继承。)

如何将mutliple类型赋予对象呢?在Java中,您可以直接键入对象。当你的班级implements Runnable界面时,你就是这么做的。如果你是继承的粉丝,为什么要使用Runnable?也许是因为你的类已经是另一个类的子类,让我们说A。现在你的班级有两种类型:ARunnable

使用多个接口,您可以为对象提供多种类型。你只需要创建一个implements多个接口的类。只要你遵守合同,就没问题。

Reuse code

这是一个难题;我已经引用了GIF来打破封装。其他答案提到钻石问题。您还可以考虑单一责任原则:

一堂课应该只有一个改变的理由。 (Robert C. Martin,敏捷软件开发,原理,模式和实践)

除了自己的职责之外,拥有父类可能会让班级有改变的理由:

超类的实现可能会在不同版本之间发生变化,如果确实如此,子类可能会中断,即使其代码未被触及。因此,子类必须与其超类(Bloch,第16项)一起发展。

我会添加一个更平淡的问题:当我试图在类中找到方法的源代码时我总是有一种奇怪的感觉而我找不到它。然后我记得:它必须在父类的某个地方定义。或者在祖父母班上。或者甚至更高。在这种情况下,一个好的IDE是一个有价值的资产,但在我看来,它仍然是一些神奇的东西。没有类似于接口的层次结构,因为javadoc是我唯一需要的东西:IDE中的一个键盘快捷键,我得到它。

继承howewer有优势:

在包中使用继承是安全的,其中子类和超类实现在同一程序员的控制之下。在扩展专门为扩展而设计和记录的类时,使用继承也是安全的(第17项:继承的设计和文档,否则禁止它)。 (布洛赫,第16项)

在Java中“为扩展而专门设计和记录”的类的一个例子是AbstractList

但布洛赫和GOF坚持这样做:“赞成作品而非继承”:

委托是一种使组合像继承一样重用的方法[Lie86,JZ91]。在委托中,处理请求涉及两个对象:接收对象将操作委托给其委托。这类似于将子请求延迟到父类的子类。 (GOF第32页)

如果使用合成,则不必一次又一次地编写相同的代码。您只需创建一个处理重复的类,然后将此类的实例传递给实现该接口的类。这是重用代码的一种非常简单的方法。这有助于您遵循单一责任原则并使代码更易于测试。 Rust和Go没有继承(它们也没有类),但我不认为代码比其他OOP语言更冗余。

此外,如果您使用组合,您会发现自然使用接口为您的代码提供所需的结构和灵活性(请参阅有关接口用例的其他答案)。

注意:您可以与Java 8接口共享代码

最后,最后一句话:

在令人难忘的问答环节中,有人问他[James Gosling]:“如果你能再次做Java,你会改变什么?” “我会遗漏课程”(网上任何地方,不知道这是否属实)


2
投票

两种方法都有效(接口和多重继承)。

快速实用简答

如果您有多年使用具有超级类且仅具有方法定义且根本没有代码的多重继承的经验,那么接口会更好。

一个互补的问题可能是:“如何以及为什么要将代码从抽象类迁移到接口”。

如果您没有在应用程序中使用许多抽象类,或者您没有多少经验,那么您可能更喜欢跳过接口。

不要急于使用接口。

长期无聊的答案

接口非常相似,甚至等同于抽象类。

如果你的代码有很多抽象类,那么你就开始考虑接口了。

以下代码与抽象类:


my streams classes.Java

/* File name : MyStreamsClasses.java */
import java.lang.*;
// Any number of import statements

public abstract class InputStream {
  public void ReadObject(Object MyObject);
}

public abstract class OutputStream {
  public void WriteObject(Object MyObject);
}

public abstract class InputOutputStream 
    imnplements InputStream, OutputStream {
  public void DoSomethingElse();
}

可以替换为:


my streams interfaces.Java

/* File name : MyStreamsInterfaces.java */
import java.lang.*;
// Any number of import statements

public interface InputStream {
  public void ReadObject(Object MyObject);
}

public interface OutputStream {
  public void WriteObject(Object MyObject);
}

public interface InputOutputStream 
    extends InputStream, OutputStream {
  public void DoSomethingElse();
}

干杯。


0
投票

Q1。由于接口只有抽象方法(没有代码)所以我们怎么说如果我们实现一个接口那么它是继承?我们没有使用它的代码。

这不是平等的继承。它只是类似的。让我解释:

VolvoV3 extends VolvoV2, and VolvoV2 extends    Volvo (Class)
VolvoV3 extends VolvoV2, and VolvoV2 implements Volvo (Interface)

line1: Volvo v = new VolvoV2(); 
line2: Volvo v = new VolvoV3(); 

如果只看到line1和line2,则可以推断出VolvoV2和VolvoV3具有相同的类型。你不能推断沃尔沃是超级级还是沃尔沃是一个界面。

Q2。如果实现接口不是继承,那么如何使用接口来实现多重继承?

现在使用接口:

VolvoXC90 implements XCModel and Volvo (Interface)
VolvoXC95 implements XCModel and Volvo (Interface)

line1: Volvo   a = new VolvoXC90();
line2: Volvo   a = new VolvoXC95();
line3: XCModel a = new VolvoXC95();

如果只看到line1和line2,则可以推断出VolvoXC90和VolvoXC95具有相同的类型(Volvo)。你无法推断沃尔沃是一个超类或沃尔沃是一个界面。

如果你只看到第2行和第3行,你可以推断出Volvo95在Java中实现了两种类型,XCModel和Volvo,你知道至少有一种类型必须是一个接口。例如,如果这段代码是用C ++编写的,那么它们可能都是类。因此,多重遗传。

Q3。无论如何,使用Interfaces有什么好处?他们没有任何代码。我们需要在我们实现它的所有类中反复编写代码。

想象一下,在其他200个类中使用VolvoXC90类的系统。

VolvoXC90 v = new VolvoXC90();

如果您需要改进系统以启动VolvoXC95,则必须更改其他200个类。

现在,想象一下您在10,000,000个类中使用Volvo接口的系统。

// Create VolvoXC90 but now we need to create VolvoXC95
Volvo v = new VolvoFactory().newCurrentVolvoModel(); 

现在,如果您需要改进系统来创建VolvoXC95模型,则必须只更改一个类,即Factory。

这是一个常识问题。如果您的系统只由几个类组成并且几乎没有更新,则使用各处的接口会适得其反。对于大型系统,它可以为您节省很多痛苦并避免采用接口的风险。

我建议您阅读有关S.O.L.I.D原则的更多信息,并阅读有效Java一书。它有经验丰富的软件工程师的优秀经验。

© www.soinside.com 2019 - 2024. All rights reserved.