ホームページ  >  記事  >  Java  >  インターフェースとは何ですか?抽象クラスとは何ですか?

インターフェースとは何ですか?抽象クラスとは何ですか?

零下一度
零下一度オリジナル
2017-06-30 11:20:011526ブラウズ

インターフェイスとは何か、抽象クラスとは何ですか? 抽象クラスでもなぜインターフェイスが必要なのでしょうか?

抽象クラスの概念:

抽象クラスは通常のものに対して相対的ですクラスに関して言えば、通常のクラスは、インスタンス化されたオブジェクトを直接生成できる完全な関数クラスであり、通常のクラスには、コンストラクター、通常のメソッド、静的メソッド、定数、変数などを含めることができます。抽象クラスとは、通常のクラスの構造に抽象メソッドのコンポーネントを追加すること、またはクラスを抽象型として直接宣言することを指します。また、抽象メソッドは通常のメソッドに対して相対的であり、すべての通常のメソッドで使用されます。 「{}」はメソッド本体を表します。メソッド本体を持つメソッドは、オブジェクトによって直接使用される必要があります。抽象メソッドはメソッド本体のないメソッドを指し、抽象メソッドもキーワード abstract で変更する必要があります。抽象メソッドを持つクラスは抽象クラスであり、抽象クラスは、abstract キーワードを使用して宣言する必要があります。

以下は単純な抽象クラスです:

package abstractdemo;  
  
//抽象类  public abstract class AbstractDemo {  //抽象方法,没有方法体  public abstract void test();  
      public void test1(){  
        System.out.println("普通方法");  
    }  
  public static void main(String[] args) {  
        Class18f2cef21ebec83e6009fc1ed61f2bdf c = AbstractDemo.class;  
        System.out.println(c.getName());  
    }  
}
抽象クラスのインスタンス:

package abstractdemo;  
  
public abstract class AbstractTest {  
  public static void main(String[] args) {  
        AbstractDemo ad = new AbstractDemo() {  
              
            @Override  public void test() {  
                System.out.println("实例抽象类要重写抽象类中所有的抽象方法!");  
            }  
        };  
        ad.test();  
        System.out.println(ad.getClass());  
    }  
  
}
上記から、抽象クラスを直接インスタンス化できないことがわかります。なぜ直接インスタンス化できないのでしょうか?クラスがインスタンス化されるということは、オブジェクトがクラス内の属性またはメソッドを呼び出すことができることを意味しますが、抽象クラスには抽象メソッドがあり、抽象メソッドにはメソッド本体がなく、メソッド本体なしでは呼び出すことができません。メソッド呼び出しはできないので、インスタンス化されたオブジェクトを生成するにはどうすればよいでしょうか?したがって、抽象クラスをインスタンス化するときは、まず抽象クラスの抽象メソッドをオーバーライドするように求められます。抽象クラスに抽象メソッドが存在しない場合、クラスはインスタンス化できず、インスタンス化中にコンパイル エラーが報告されます。 ;

抽象 クラスを使用する原則は次のとおりです:

(1) 抽象メソッドはパブリックまたは保護されている必要があります (プライベートの場合、サブクラスに継承できず、サブクラスはメソッドを実装できないため)。デフォルトは public です。

(2) 抽象クラスは直接インスタンス化できず、上方変換を通じてサブクラスによって処理される必要があります。

(3) 抽象クラスは継承を使用してサブクラスを持つ必要があり、サブクラスは 1 つだけ継承できます。抽象クラス;
(4) サブクラス (抽象クラスでない場合) は、抽象クラス内のすべての抽象メソッドをオーバーライドする必要があります (サブクラスが親クラスの抽象メソッドを実装していない場合、サブクラスも抽象クラス)

以下を参照 コードの一部:

package abstractdemo;  
  
//抽象类  public abstract class AbstractDemo {  //抽象方法,没有方法体  public abstract void test();  
      public void test1(){  
        System.out.println("普通方法");  
    }  
  public static void main(String[] args) {  
        Class18f2cef21ebec83e6009fc1ed61f2bdf c = AbstractDemo.class;  
        System.out.println(c.getName());  
    }  
  
}  

package abstractdemo;  
  
public class Test extends AbstractDemo{  
  
    @Override  public void test() {  
        System.out.println("继承抽象类,一定要重写抽象类中的抽象方法,如果不重写,那么该类也是抽象类!");  
    }  
  
}  

package abstractdemo;  
  
public class Demo {  
  public static void main(String[] args) {  
        AbstractDemo ad = new Test();  
        ad.test();  
    }  
  
}

现在就可以清楚的发现: 
(1)抽象类继承子类里面有明确的方法覆写要求,而普通类可以有选择性的来决定是否需要覆写; 
(2)抽象类实际上就比普通类多了一些抽象方法而已,其他组成部分和普通类完全一样; 
(3)普通类对象可以直接实例化,但抽象类的对象必须经过向上转型之后才可以得到。

虽然一个类的子类可以去继承任意的一个普通类,可是从开发的实际要求来讲,普通类尽量不要去继承另外一个普通类,而是去继承抽象类。

抽象类的使用限制:

1.由于抽象类里会存在一些属性,那么抽象类中一定存在构造方法,其存在目的是为了属性的初始化。抽象类中是有构造函数的,所以子类继承抽象类,构造方法的调用顺序仍然是先父类构造函数,然后子类构造函数

2.抽象类不可以修饰为final,因为抽象类有子类,而final修饰的类不能被继承;

3.外部抽象类不能被修饰为static,外部抽象类不允许使用static声明,而内部的抽象类运行使用static声明。使用static声明的内部抽象类相当于一个外部抽象类的成员,继承的时候使用“外部类.内部类”的形式表示类名称。

package com.wz.abstractdemo;static abstract class A{//定义一个抽象类public abstract void print();

}class B extends A{public void print(){
        System.out.println("**********");
    }
}public class TestDemo {public static void main(String[] args) {
        A a = new B();//向上转型        a.print();
    }

}

执行结果

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Illegal modifier for the class A; only public, abstract & final are permitted
    at com.wz.abstractdemo.A.<init>(TestDemo.java:3)
    at com.wz.abstractdemo.B.<init>(TestDemo.java:9)
    at com.wz.abstractdemo.TestDemo.main(TestDemo.java:18)

再看一个关于内部抽象类:

package com.wz.abstractdemo;abstract class A{//定义一个抽象类static abstract class B{//static定义的内部类属于外部类public abstract void print();
    }

}class C extends A.B{public void print(){
        System.out.println("**********");
    }
}public class TestDemo {public static void main(String[] args) {
        A.B ab = new C();//向上转型        ab.print();
    }

}

执行结果:

**********

4.任何时候,如果要执行类中的static方法的时候,都可以在没有对象的情况下直接调用,对于抽象类也一样。但是修饰为abstract的抽象方法,不能修饰为static,没有意义; 

5.有时候由于抽象类中只需要一个特定的系统子类操作,所以可以忽略掉外部子类。这样的设计在系统类库中会比较常见,目的是对用户隐藏不需要知道的子类。

范例如下:

package com.wz.abstractdemo;abstract class A{//定义一个抽象类public abstract void print();private static class B extends A{//内部抽象类子类public void print(){//覆写抽象类的方法System.out.println("Hello World !");
        }
    }//这个方法不受实例化对象的控制public static A getInstance(){return new B();
    }

}public class TestDemo {public static void main(String[] args) {//此时取得抽象类对象的时候完全不需要知道B类这个子类的存在A a = A.getInstance();
        a.print();
    }
}

运行结果:

Hello World !

抽象类的应用——模板设计模式

例如,现在有三类事物: 
(1)机器人:充电,工作; 
(2)人:吃饭,工作,睡觉; 
(3)猪:进食,睡觉。 
现要求实现一个程序,可以实现三种不同事物的行为。

先定义一个抽象行为类:

package com.wz.abstractdemo;public abstract class Action{public static final int EAT = 1 ;public static final int SLEEP = 3 ;public static final int WORK = 5 ;public abstract void eat();public abstract void sleep();public abstract void work();public void commond(int flags){      switch(flags){case EAT:this.eat();break;case SLEEP:this.sleep();break;case WORK:this.work();break;case EAT + SLEEP:this.eat();this.sleep();break;case SLEEP + WORK:this.sleep();this.work();break;default:break;
        }
    }
}

定义一个机器人的类:

package com.wz.abstractdemo;public class Robot extends Action{

    @Overridepublic void eat() {
        System.out.println("机器人充电");

    }

    @Overridepublic void sleep() {

    }

    @Overridepublic void work() {
        System.out.println("机器人工作");

    }

}

定义一个人的类:

package com.wz.abstractdemo;public class Human extends Action{

    @Overridepublic void eat() {
        System.out.println("人吃饭");

    }

    @Overridepublic void sleep() {
        System.out.println("人睡觉");

    }

    @Overridepublic void work() {
        System.out.println("人工作");

    }

}

定义一个猪的类:

package com.wz.abstractdemo;public class Pig extends Action{

    @Overridepublic void eat() {
        System.out.println("猪进食");

    }

    @Overridepublic void sleep() {
        System.out.println("猪睡觉");

    }

    @Overridepublic void work() {


    }

}

测试主类:

package com.wz.abstractdemo;public class AbstractDemo {public static void main(String[] args) {

        fun(new Robot());

        fun(new Human());

        fun(new Pig());

    }public static void fun(Action act){
        act.commond(Action.EAT);
        act.commond(Action.SLEEP);
        act.commond(Action.WORK);
    }

}

运行结果:

机器人充电
机器人工作
人吃饭
人睡觉
人工作
猪进食
猪睡觉
 

すべてのサブクラスが操作を正常に完了したい場合は、指定されたメソッドに従ってオーバーライドする必要があります。このとき、抽象クラスの関数はクラス定義テンプレートの関数です。

---------------------------------------------- --- --------------------------------------------------- --- --------------------------------------------------- --- --------------------------------------------------- --- --------------------------------------------------- --- ------------------------------------------------

Interface

Interfaceはa 抽象クラスよりも抽象的な「クラス」。これより適切に表現できる言葉が見つからないため、ここでは「クラス」を引用符で囲みましたが、インターフェイス自体はクラスではないことを明確にする必要があります。これは、インターフェイスをインスタンス化できないという事実からもわかります。たとえば、 new Runnable(); は明らかに間違っており、実装クラスを new することしかできません。

インターフェイスは、クラス間のプロトコルを確立するために使用されます。提供されるのは、特定の実装のない形式だけです。同時に、インターフェイスを実装する実装クラスはインターフェイスのすべてのメソッドを実装する必要があります。implements キーワードを使用すると、クラスが特定のインターフェイスまたは特定のインターフェイスのグループに従っていることが示され、また「インターフェイスは次のとおりです」ということも示されます。見た目だけですが、どのように動作するかを説明する必要があります。」

データのセキュリティを確保するために、Java は多重継承を許可できません。つまり、継承は 1 つの親クラスからのみ存在できますが、クラスは異なります。インターフェイスに関係なく、複数のインターフェイスを同時に実装します。インターフェイス間には関係がないため、抽象クラスが多重継承を持てないという欠点はインターフェイスによって補われますが、継承とインターフェイスを併用することをお勧めします。データのセキュリティを確保するだけでなく、多重継承も実現します。

インターフェイスを使用するときは、次の問題に注意する必要があります:

1. インターフェイスのすべてのメソッド アクセス権は、自動的に public として宣言されます。もちろん、明示的に protected または private として宣言することもできますが、コンパイル エラーが発生します。

2. インターフェース内の「メンバー変数」は自動的に public static Final になるため、インターフェース内の「メンバー変数」、または不変の定数を定義できます。クラス名 ImplementClass.name を使用して直接アクセスできます。

3. インターフェースには実装されたメソッドがありません。

4. インターフェースを実装する非抽象クラスは、インターフェースのすべてのメソッドを実装する必要があります。抽象クラスを実装する必要はありません。

5. new 演算子を使用してインターフェイスをインスタンス化することはできませんが、インターフェイス変数を宣言することはできます。インターフェイス変数は、インターフェイスを実装するクラスのオブジェクトを参照する必要があります。 Instanceof を使用すると、オブジェクトが特定のインターフェイスを実装しているかどうかを確認できます。例: if(Comparable のオブジェクト インスタンス){}。

6. 複数のインターフェースを実装する場合、メソッド名の重複を避ける必要があります。

抽象クラスとインターフェイスの違い

Java言語では、抽象クラスとインターフェイスは、抽象クラスの定義をサポートする2つのメカニズムです。これら 2 つのメカニズムが存在するからこそ、Java には強力なオブジェクト指向機能が与えられます。抽象クラス定義のサポートという点では、抽象クラスとインターフェイスには大きな類似点があり、相互に置き換えることもできるため、多くの開発者は抽象クラスを定義する際に、抽象クラスとインターフェイスの選択についてよりカジュアルになっているようです。実際、この 2 つの間には大きな違いがあり、その選択は、問題領域の性質の理解と設計意図の理解が正しく合理的であるかどうかさえ反映します。

抽象クラス

インターフェース

インスタンス化

はできません

はできません

クラス

継承関係。クラスは継承関係を 1 回だけ使用できます。多重継承は、複数のインターフェイスを継承することで実現できます

クラスは複数のインターフェイスを実装できます

データメンバー

独自のインターフェイスを持つことができます

静的 それはできませんつまり、静的なfinalである必要があります

メソッド

は、プライベートな非抽象メソッドにすることができ、抽象メソッドを実装する必要があります

プライベートにすることはできません、デフォルトはパブリック、抽象型です

変数

プライベートにすることができます、デフォルトはフレンドリ型、その値はサブクラスで再定義または再割り当てできます

デフォルトは public static Final 型であり、その初期値は実装クラスで再定義できず、その値は変更できません。

デザインコンセプト

は「ある」関係を表します

は「似ている」関係を表します

達成

継承する必要があり、extendsを使用する必要があります

implementsを使用する必要があります

抽象クラスとインターフェースは両方ともJava言語で抽象クラスを定義するために使用されます(この記事の抽象クラスは抽象クラスから翻訳されたものではなく、抽象本体を表し、抽象クラスはJava言語で定義するために使用されます(抽象クラスのメソッド) では、抽象クラスとは何ですか?また、抽象クラスを使用するとどのような利点があるのでしょうか?

メソッドの存在を実装せずに宣言するクラスは抽象クラスと呼ばれ、いくつかの基本的な動作を具現化したクラスを作成し、そのクラスのメソッドを宣言するために使用されますが、の実装では使用できません。このクラスのこのクラス。抽象クラスのインスタンスは作成できません。ただし、型が抽象クラスである変数を作成し、それが具象サブクラスのインスタンスを指すようにすることはできます。抽象コンストラクターや抽象静的メソッドは使用できません。 Abstract クラスのサブクラスは、親クラス内のすべての抽象メソッドの実装を提供します。それ以外の場合は、それらも抽象クラスです。代わりに、メソッドをサブクラスに実装します。その動作を認識している他のクラスは、これらのメソッドをクラスに実装できます。

インターフェースは抽象クラスの一種です。インターフェイスでは、すべてのメソッドは抽象です。このようなインターフェースを実装することにより、多重継承を取得できます。インターフェイス内のすべてのメソッドは抽象メソッドであり、プログラム本体を持たないメソッドはありません。インターフェイスは静的な最終メンバー変数のみを定義できます。インターフェイスの実装はサブクラス化と似ていますが、実装クラスがインターフェイス定義から動作を継承できない点が異なります。クラスが特定のインターフェイスを実装する場合、このインターフェイスのすべてのメソッドを定義します (つまり、プログラム本体を与えます)。 その後、インターフェイスを実装するクラスの任意のオブジェクトでインターフェイスのメソッドを呼び出すことができます。抽象クラスがあるため、インターフェイス名を参照変数の型として使用できます。通常の動的リンクが有効になります。参照はインターフェイス型との間で変換でき、instanceof 演算子を使用してオブジェクトのクラスがインターフェイスを実装しているかどうかを判断できます。

インターフェースはインターフェースを継承できます。抽象クラスはインターフェイスを実装でき、抽象クラスはエンティティ クラスを継承できますが、エンティティ クラスには明確なコンストラクタが必要であることが前提となります。

インターフェースは、「実装方法」に関係なく、「どのような機能を実現できるか」に重点を置いています

1. 類似点A. どちらも抽象クラスであり、どちらもインスタンス化できません。
B. インターフェイス実装クラスと抽象クラスのサブクラスの両方が、宣言された抽象メソッドを実装する必要があります。

2. 違い
A. インターフェースは、implements を使用して実装する必要がありますが、抽象クラスは extends を使用して継承する必要があります。
B. クラスは複数のインターフェースを実装できますが、継承できる抽象クラスは 1 つだけです。
C. インターフェイスは特定の関数の実装を重視し、抽象クラスは所有権関係を重視します。
D. インターフェース実装クラスと抽象クラスのサブクラスは両方とも対応する抽象メソッドを実装する必要がありますが、実装形式は異なります。インターフェイス内のすべてのメソッドは抽象メソッドであり、宣言されるだけです。 (宣言、メソッド本体なし)、実装クラスはそれを実装する必要があります。抽象クラスのサブクラスは選択的に実装できます。
この選択には 2 つの意味があります:
まず、Abstract クラスのすべてのメソッドが抽象であるわけではなく、abstract を持つメソッドだけが抽象であり、サブクラスはそれらを実装する必要があります。抽象のないメソッドの場合、メソッド本体は Abstract クラスで定義する必要があります。
次に、抽象クラスのサブクラスがそれを継承する場合、非抽象メソッドを直接継承またはオーバーライドできます。抽象メソッドの場合は、それらを実装することを選択することも、実装せずにそのメソッドを再度抽象として宣言することもできます。をサブクラスに追加して実装しますが、このクラスも抽象として宣言する必要があります。抽象クラスなので当然インスタンス化できません。

E. 抽象クラスはインターフェイスとクラスの間の仲介者です。
インターフェイスは完全に抽象的であり、メソッドのみを宣言でき、プライベート メソッドとプロテクト メソッドを宣言できず、メソッド本体を定義できず、インスタンス変数も宣言できません。ただし、インターフェイスでは定数変数を宣言でき、JDK でそのような例を見つけるのは難しくありません。ただし、インターフェイスに定数変数を配置すると、インターフェイスとして存在する目的に違反し、インターフェイスとクラスの異なる値が混乱します。本当に必要な場合は、対応する抽象クラスまたはクラスに配置できます。
抽象クラスはインターフェースとクラスを繋ぐ役割を果たします。一方では、抽象クラスは抽象的であり、サブクラスが実装する必要がある関数を標準化するために抽象メソッドを宣言できます。他方では、サブクラスによって直接使用またはオーバーライドされるデフォルトのメソッド本体を定義できます。さらに、継承を通じてサブクラスで使用する独自のインスタンス変数を定義できます。

インターフェースの適用場面
A. クラスは、実装方法に関係なく、事前に調整するために特定のインターフェースを必要とします。
B. 特定の機能を実現できるロゴとして存在することも、インターフェイス メソッドを持たない純粋なロゴであることもできます。
C. クラスのグループは単一のクラスとして扱われる必要があり、呼び出し元はインターフェイスを通じてのみこのクラスのグループにアクセスします。
D. 特定の複数の機能を実装する必要があり、これらの機能はまったく関連していない可能性があります。

抽象クラスの応用シナリオ
一言で言えば、統一されたインターフェースとインスタンス変数またはデフォルトメソッドの両方が必要な場合に使用できます。最も一般的なものは次のとおりです:
A. 一連のインターフェイスを定義しますが、各実装クラスにすべてのインターフェイスの実装を強制したくありません。抽象クラスを使用してメソッド本体のセット、または空のメソッド本体を定義し、サブクラスが対象とするメソッドを選択できるようにすることができます。
B. 場合によっては、純粋なインターフェイスだけでは、クラス内の状態を表す変数も異なる関係を区別する必要があります。抽象の仲介的な役割は、これをうまく満たすことができます。
C. 相互に調整されたメソッドのセットを標準化します。その一部は共通で状態に依存せず、サブクラスが個別に実装する必要がなく共有できますが、他のメソッドは各サブクラスがそれぞれのメソッドに従って実装する必要があります。特定の機能を実装するための独自の状態。

インターフェースと抽象クラスの利点:

    好像定义接口是提前做了个多余的工作。下面我给大家总结了4点关于JAVA中接口存在的意义:

  1、重要性:在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。

  2、简单、规范性:如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口不仅告诉开发人员你需要实现那些业务,而且也将命名规范限制住了(防止一些开发人员随便命名导致别的程序员无法看明白)。

  3、维护、拓展性:比如你要做一个画板程序,其中里面有一个面板类,主要负责绘画功能,然后你就这样定义了这个类。

    可是在不久将来,你突然发现这个类满足不了你了,然后你又要重新设计这个类,更糟糕是你可能要放弃这个类,那么其他地方可能有引用他,这样修改起来很麻烦。

    如果你一开始定义一个接口,把绘制功能放在接口里,然后定义类时实现这个接口,然后你只要用这个接口去引用实现它的类就行了,以后要换的话只不过是引用另一个类而已,这样就达到维护、拓展的方便性。

  4、安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些(一般软件服务商考虑的比较多)。

    尽管抽象类和接口之间存在较大的相同点,甚至有时候还可以互换,但这样并不能弥补他们之间的差异之处。下面将从语法层次和设计层次两个方面对抽象类和接口进行阐述。

语法层次

在语法层次,java语言对于抽象类和接口分别给出了不同的定义。下面已Demo类来说明他们之间的不同之处。

使用抽象类来实现:

public abstract class Demo {  abstract void method1();  
      
      void method2(){  //实现      }  
}

 

使用接口来实现

interface Demo {  void method1();  void method2();  
}

 

    抽象类方式中,抽象类可以拥有任意范围的成员数据,同时也可以拥有自己的非抽象方法,但是接口方式中,它仅能够有静态、不能修改的成员数据(但是我们一般是不会在接口中使用成员数据),同时它所有的方法都必须是抽象的。在某种程度上来说,接口是抽象类的特殊化。

    对子类而言,它只能继承一个抽象类(这是java为了数据安全而考虑的),但是却可以实现多个接口。

设计层次

      上面只是从语法层次和编程角度来区分它们之间的关系,这些都是低层次的,要真正使用好抽象类和接口,我们就必须要从较高层次来区分了。只有从设计理念的角度才能看出它们的本质所在。一般来说他们存在如下三个不同点:

    1、 抽象层次不同。抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

    2、 跨域不同。抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。我们知道抽象类是从子类中发现公共部分,然后泛化成抽象类,子类继承该父类即可,但是接口不同。实现它的子类可以不存在任何关系,共同之处。例如猫、狗可以抽象成一个动物类抽象类,具备叫的方法。鸟、飞机可以实现飞Fly接口,具备飞的行为,这里我们总不能将鸟、飞机共用一个父类吧!所以说抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a" 关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的, 仅仅是实现了接口定义的契约而已。

    3、 设计层次不同。对于抽象类而言,它是自下而上来设计的,我们要先知道子类才能抽象出父类,而接口则不同,它根本就不需要知道子类的存在,只需要定义一个规则即可,至于什么子类、什么时候怎么实现它一概不知。比如我们只有一个猫类在这里,如果你这是就抽象成一个动物类,是不是设计有点儿过度?我们起码要有两个动物类,猫、狗在这里,我们在抽象他们的共同点形成动物抽象类吧!所以说抽象类往往都是通过重构而来的!但是接口就不同,比如说飞,我们根本就不知道会有什么东西来实现这个飞接口,怎么实现也不得而知,我们要做的就是事前定义好飞的行为接口。所以说抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。

      我们有一个Door的抽象概念,它具备两个行为open()和close(),此时我们可以定义通过抽象类和接口来定义这个抽象概念:

   抽象类:

abstract class Door{  abstract void open();  abstract void close();  
}

 

   接口

interface Door{  void open();  void close();  
}

 

       至于其他的具体类可以通过使用extends使用抽象类方式定义Door或者Implements使用接口方式定义Door,这里发现两者并没有什么很大的差异。

   但是现在如果我们需要门具有报警的功能,那么该如何实现呢?

   解决方案一:给Door增加一个报警方法:clarm();

abstract class Door{  abstract void open();  abstract void close();  abstract void alarm();  
}

 

    或者

interface Door{  void open();  void close();  void alarm();  
}

 

 

       这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle)(参见:),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方 法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变而改变,反之依然。

   解决方案二

   既然open()、close()和alarm()属于两个不同的概念,那么我们依据ISP原则将它们分开定义在两个代表两个不同概念的抽象类里面,定义的方式有三种:

   1、两个都使用抽象类来定义。

   2、两个都使用接口来定义。

   3、一个使用抽象类定义,一个是用接口定义。

   由于java不支持多继承所以第一种是不可行的。后面两种都是可行的,但是选择何种就反映了你对问题域本质的理解。

   如果选择第二种都是接口来定义,那么就反映了两个问题:1、我们可能没有理解清楚问题域,AlarmDoor在概念本质上到底是门还报警器。2、如果我们对问题域的理解没有问题,比如我们在分析时确定了AlarmDoor在本质上概念是一致的,那么我们在设计时就没有正确的反映出我们的设计意图。因为你使用了两个接口来进行定义,他们概念的定义并不能够反映上述含义。

   第三种,如果我们对问题域的理解是这样的:AlarmDoor本质上Door,但同时它也拥有报警的行为功能,这个时候我们使用第三种方案恰好可以阐述我们的设计意图。AlarmDoor本质是们,所以对于这个概念我们使用抽象类来定义,同时AlarmDoor具备报警功能,说明它能够完成报警概念中定义的行为功能,所以alarm可以使用接口来进行定义。如下:

abstract class Door{  abstract void open();  abstract void close();  
}  
  
interface Alarm{  void alarm();  
}  
  
class AlarmDoor extends Door implements Alarm{  void open(){}  void close(){}  void alarm(){}  
}

 

       这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。

      批注:

   ISP(Interface Segregation Principle):面向对象的一个核心原则。它表明使用多个专门的接口比使用单一的总接口要好。

   一个类对另外一个类的依赖性应当是建立在最小的接口上的。

   一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。

概要

1. 抽象クラスは Java 言語の継承関係を表します。サブクラスは親クラスを 1 つだけ持つことができますが、複数のインターフェイスを持つことができます。

2. 抽象クラスは独自のメンバー変数と非抽象クラス メソッドを持つことができますが、インターフェイス内に存在できるのは静的かつ不変のメンバー データのみです (ただし、メンバー データは通常インターフェイス内で定義されません)。メソッドは抽象的です。

3. 抽象クラスとインターフェイスによって反映される設計概念は異なります。抽象クラスは「である」関係を表し、インターフェイスは「似た」関係を表します。

抽象クラスとインターフェースは Java 言語の 2 つの異なる抽象概念ですが、それらの間には大きな類似点がありますが、その存在によりポリモーフィズムが非常によくサポートされます。しかし、彼らの選択は多くの場合、問題領域に対するあなたの理解を反映しています。問題領域の性質をよく理解して初めて、正しく合理的な設計を行うことができます。

以上がインターフェースとは何ですか?抽象クラスとは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。