サーチ…


前書き

継承は、キーワードextendsを使用して、あるクラスが別のクラスのプロパティを取得し、拡張する基本的なオブジェクト指向機能です。インタフェースとキーワードのimplementsについては、 インタフェースを参照してください。

構文

  • クラスClassBはClassAを拡張する{...}
  • ClassBクラスはInterfaceA {...}を実装しています
  • interfaceBはInterfaceAを拡張します{...}
  • ClassBクラスがClassAを継承してInterfaceC、InterfaceD {...}を実装する
  • 抽象クラスAbstractClassBはClassAを拡張しています{...}
  • 抽象クラスAbstractClassB extends AbstractClassA {...}
  • 抽象クラスAbstractClassB extends ClassAは、InterfaceC、InterfaceD {...}を実装しています。

備考

継承は、基本クラスが1つ以上の型パラメータを持つように、ジェネリックと組み合わされることがよくあります。 ジェネリッククラスの作成を参照してください。

抽象クラス

抽象クラスは、 abstractキーワードでマークされたクラスです。非抽象クラスとは対照的に、抽象実装なしのメソッドを含むことができます。ただし、抽象メソッドを持たない抽象クラスを作成することは有効です。

抽象クラスはインスタンス化できません。サブクラスが抽象クラスであるか、スーパークラスで抽象クラスとしてマークされたすべてのメソッドを実装している限り、サブクラス化(拡張)することができます。

抽象クラスの例:

public abstract class Component {
    private int x, y;
    
    public setPosition(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public abstract void render();
}

少なくとも1つの抽象メソッドがある場合、クラスは抽象クラスとマークする必要があります。抽象メソッドは実装されていないメソッドです。任意のサブクラスに共通のコードを提供するために、実装を持つ抽象クラス内で他のメソッドを宣言することができます。

このクラスをインスタンス化しようとすると、コンパイルエラーが発生します。

//error: Component is abstract; cannot be instantiated   
Component myComponent = new Component();

しかし、 Componentを拡張し、その抽象メソッドのすべての実装を提供し、インスタンス化することができるクラス。

public class Button extends Component {

    @Override
    public void render() {
        //render a button
    }
}

public class TextBox extends Component {

    @Override
    public void render() {
        //render a textbox
    }
}

クラスを継承するインスタンスも親クラス(通常の継承)としてキャストでき、抽象メソッドが呼び出されるとポリモーフィックな効果を提供します。

Component myButton = new Button();
Component myTextBox = new TextBox();

myButton.render(); //renders a button
myTextBox.render(); //renders a text box

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

抽象クラスとインタフェースの両方は、実装を提供するために拡張/実装クラスを必要としながらメソッドシグネチャを定義する方法を提供します。

抽象クラスとインタフェースの間には2つの大きな違いがあります。

  • クラスは単一のクラスだけを拡張することができるが、多くのインターフェースを実装することができる。
  • 抽象クラスにはインスタンス(非static )フィールドを含めることができますが、インタフェースにはstaticフィールドしか含めることはできません。
Java SE 8

インタフェースで宣言されたメソッドには実装が含まれていない可能性があるため、抽象メソッドと呼ばれる実装の追加メソッドを提供するのに便利だった場合は、抽象クラスが使用されました。

Java SE 8

Java 8では、インタフェースにデフォルトのメソッドを含めることができます。これは、通常、インタフェースの他のメソッドを使用して実装され、この点でインタフェースと抽象クラスを同等に強力にします。

抽象クラスの匿名サブクラス

便利なJavaは、抽象クラスのサブクラスの匿名インスタンスのインスタンス化を可能にするため、新しいオブジェクトを作成する際に抽象メソッドの実装を提供します。上記の例を使用すると、次のようになります。

Component myAnonymousComponent = new Component() {
    @Override
    public void render() {
        // render a quick 1-time use component
    }
}

静的継承

静的メソッドは通常のメソッドと同様に継承できますが、通常のメソッドとは異なり、静的メソッドのオーバーライドを強制するためには「 抽象 」メソッドを作成することは不可能です。スーパークラス内の静的メソッドと同じシグネチャを持つメソッドを書き込むことは、オーバーライドの一種と思われますが、実際にはこれは単に新しい関数を作成して他のものを隠すだけです。

public class BaseClass {
    
    public static int num = 5;

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

    public static void main(String[] args) {
        BaseClass.sayHello();
        System.out.println("BaseClass's num: " + BaseClass.num);
            
        SubClass.sayHello();
        //This will be different than the above statement's output, since it runs
        //A different method
        SubClass.sayHello(true);
        
        StaticOverride.sayHello();
        System.out.println("StaticOverride's num: " + StaticOverride.num);
    }
}

public  class SubClass extends BaseClass {
    
    //Inherits the sayHello function, but does not override it   
    public static void sayHello(boolean test) {
        System.out.println("Hey");
    }
}

public static class StaticOverride extends BaseClass {

    //Hides the num field from BaseClass
    //You can even change the type, since this doesn't affect the signature
    public static String num = "test";
        
    //Cannot use @Override annotation, since this is static
    //This overrides the sayHello method from BaseClass
    public static void sayHello() {
        System.out.println("Static says Hi");
    }

}

これらのクラスのいずれかを実行すると、次の出力が生成されます。

Hello
BaseClass's num: 5
Hello
Hey
Static says Hi
StaticOverride's num: test

通常の継承とは異なり、静的継承メソッドは隠されていないことに注意してください。 BaseClass.sayHello()を使って、いつでもbase sayHelloメソッドを呼び出すことができます。しかし、サブクラスで同じシグネチャを持つメソッドが見つからない場合 、クラスは静的メソッドを継承します。 2つのメソッドのシグネチャが異なる場合、たとえ名前が同じであっても、両方のメソッドをサブクラスから実行できます。

静的フィールドは、同様の方法でお互いを隠します。

'final'を使用して継承とオーバーライドを制限する

最終クラス

class宣言で使用されるとき、 final修飾子は、クラスをextendする他のクラスの宣言を防ぎます。 finalクラスは、継承クラス階層の「リーフ」クラスです。

// This declares a final class
final class MyFinalClass {
    /* some code */
}

// Compilation error: cannot inherit from final MyFinalClass
class MySubClass extends MyFinalClass {
    /* more code */
}

最終クラスのユースケース

最終クラスをprivateコンストラクタと組み合わせて、クラスのインスタンス化を制御または防止することができます。静的メンバーのみを定義する、いわゆる "ユーティリティクラス"を作成するのに使用できます。すなわち定数と静的メソッド。

public final class UtilityClass {

    // Private constructor to replace the default visible constructor
    private UtilityClass() {}

    // Static members can still be used as usual
    public static int doSomethingCool() {
        return 123;
    }

}

変更不能なクラスもfinalとして宣言する必要があります。 (不変クラスとは、インスタンスが作成された後に変更できないものです.Immutableオブジェクトのトピックを参照してください。)これにより、不変クラスの可変サブクラスを作成することができなくなります。それは、サブタイプがそのスーパータイプの「行動的契約」に従うことを要求するLiskov Substitution Principleに違反します。

実用的な観点からは、不変のクラスをfinalに宣言することで、プログラムの振る舞いを簡単に推論することができます。また、セキュリティサンドボックスで信頼できないコードが実行されるシナリオでのセキュリティ上の問題も解決します。たとえば、 Stringfinalとして宣言されているため、信頼できるクラスは、信頼できない呼び出し元が秘密に変更できるように、変更可能なサブクラスを受け入れることに騙されることを心配する必要はありません。

finalクラスの1つの欠点は、Mockitoのような一部の模擬フレームワークでは機能しないことです。更新:Mockitoバージョン2は、最終クラスの模擬をサポートするようになりました。

最終的なメソッド

final変更子は、サブクラスでオーバーライドされないようにするメソッドにも適用できます。

public class MyClassWithFinalMethod {

    public final void someMethod() {
    }
}

public class MySubClass extends MyClassWithFinalMethod {

    @Override
    public void someMethod() { // Compiler error (overridden method is final)
    }
}

最終的なメソッドは、通常、サブクラスを完全に禁止することなくクラス内で変更できるものを制限する場合に使用されます。


final修飾子は変数にも適用できますが、変数のfinalの意味は継承とは無関係です。

リスコフ置換原理

Substitutabilityは、1987年の基調講演でBarbara Liskovによって導入されたオブジェクト指向プログラミングの原則であり、クラスBがクラスAサブクラスであり、 Aが期待される場所であればBを代わりに使用できると述べています。

class A {...}
class B extends A {...}

public void method(A obj) {...}

A a = new B(); // Assignment OK
method(new B()); // Passing as parameter OK

これは、タイプがインタフェースであり、オブジェクト間に階層関係が必要ない場合にも適用されます。

interface Foo {
    void bar();
}

class A implements Foo {
    void bar() {...}
}

class B implements Foo {
    void bar() {...}
}

List<Foo> foos = new ArrayList<>();
foos.add(new A()); // OK
foos.add(new B()); // OK

このリストには、同じクラス階層にないオブジェクトが含まれています。

継承

クラス間でextendsキーワードを使用すると、スーパークラス( 親クラスまたは基本クラス )のすべてのプロパティがサブクラス( 子クラスまたは派生クラスとも呼ばれます)に存在し、

public class BaseClass {

    public void baseMethod(){
        System.out.println("Doing base class stuff");
    }
}

public class SubClass extends BaseClass {

}

インスタンスSubClassメソッドの継承しているbaseMethod()

SubClass s = new SubClass();
s.baseMethod();  //Valid, prints "Doing base class stuff"

追加コンテンツをサブクラスに追加することができます。そのようにすると、基本クラスまたはその同じ基本クラスの他のサブクラスに変更を加えることなく、サブクラスに追加の機能が追加されます。

public class Subclass2 extends BaseClass {

    public void anotherMethod() {
        System.out.println("Doing subclass2 stuff");
    }
}

Subclass2 s2 = new Subclass2();
s2.baseMethod(); //Still valid , prints "Doing base class stuff"
s2.anotherMethod(); //Also valid, prints "Doing subclass2 stuff" 

フィールドも継承されます:

public class BaseClassWithField {

    public int x;

}

public class SubClassWithField extends BaseClassWithField {

    public SubClassWithField(int x) {
        this.x = x; //Can access fields
    }
}

privateフィールドとメソッドはサブクラス内にまだ存在しますが、アクセスできません:

public class BaseClassWithPrivateField {

    private int x = 5;

    public int getX() {
        return x;
    }
}

public class SubClassInheritsPrivateField extends BaseClassWithPrivateField {

    public void printX() {
        System.out.println(x); //Illegal, can't access private field x
        System.out.println(getX()); //Legal, prints 5
    }
}

SubClassInheritsPrivateField s = new SubClassInheritsPrivateField();
int x = s.getX(); //x will have a value of 5.

Javaでは、各クラスは最大でも1つの他のクラスに拡張できます。

public class A{}
public class B{}
public class ExtendsTwoClasses extends A, B {} //Illegal

これは多重継承と呼ばれ、一部の言語では合法ですが、Javaではクラスでそれを許可しません。

この結果、すべてのクラスには、すべてのクラスが下降するObjectに至るクラスの非分岐先祖チェーンがあります。

継承と静的メソッド

Javaでは、親クラスと子クラスの両方が同じ名前の静的メソッドを持つことができます。しかし、そのような場合、子クラスの静的メソッドの実装は親クラスの実装を隠しているので、メソッドオーバーライドではありません。例えば:

class StaticMethodTest {

  // static method and inheritance
  public static void main(String[] args) {
    Parent p = new Child();
    p.staticMethod(); // prints Inside Parent
    ((Child) p).staticMethod(); // prints Inside Child
  }

  static class Parent {
    public static void staticMethod() {
      System.out.println("Inside Parent");
    }
  }

  static class Child extends Parent {
    public static void staticMethod() {
      System.out.println("Inside Child");
    }
  }
}

静的メソッドはインスタンスにではなくクラスにバインドされ、このメソッドのバインドはコンパイル時に行われます。 staticMethod()への最初の呼び出しで親クラスのリファレンスpが使用されたため、 ParentのバージョンのstaticMethod()が呼び出されました。 2番目のケースでは、 pChildクラスにキャストし、 ChildstaticMethod()実行しました。

可変シャドーイング

変数はSHADOWEDで、メソッドはOVERRIDDENです。どの変数が使用されるかは、その変数が宣言されているクラスに依存します。どのメソッドが使用されるかは、変数によって参照されるオブジェクトの実際のクラスに依存します。

class Car {
    public int gearRatio = 8;

    public String accelerate() {
        return "Accelerate : Car";
    }
}

class SportsCar extends Car {
    public int gearRatio = 9;

    public String accelerate() {
        return "Accelerate : SportsCar";
    }

    public void test() {

    }


    public static void main(String[] args) {

        Car car = new SportsCar();
        System.out.println(car.gearRatio + "  " + car.accelerate());
        // will print out 8  Accelerate : SportsCar
    }
}

オブジェクト参照の絞り込みと拡大

基底クラスのインスタンスを次のようにサブクラスにキャストする: b = (B) a; (より具体的なクラスオブジェクトに基底クラスオブジェクトを絞り込もうとしているので)ナローイングと呼ばれ、明示的な型キャストが必要です。

サブクラスのインスタンスをベースクラスにキャスティングするには: A a = b; 拡張と呼ばれ、型キャストは必要ありません。

例として、次のクラス宣言とテストコードを考えてみましょう。

class Vehicle {
}

class Car extends Vehicle {
}

class Truck extends Vehicle {
}

class MotorCycle extends Vehicle {
}

class Test {

    public static void main(String[] args) {
    
        Vehicle vehicle = new Car();
        Car car = new Car();        
    
        vehicle = car; // is valid, no cast needed

        Car c = vehicle // not valid
        Car c = (Car) vehicle; //valid
    }
}

Vehicle vehicle = new Car();というステートメントがありVehicle vehicle = new Car();有効なJavaステートメントです。 CarすべてのインスタンスもVehicleです。したがって、明示的な型キャストを必要とせずに割り当てが合法です。

一方、 Car c = vehicle;有効じゃない。静的な型vehicle変数はVehicleそれはのインスタンスを参照することを意味Car 、トラック,オートバイ, or any other current or future subclass of車両. (Or indeed, an instance of itself, since we did not declare it as an抽象class.) The assignment cannot be allowed, since that might lead to itself, since we did not declare it as an . (Or indeed, an instance of Vehicle itself, since we did not declare it as an . (Or indeed, an instance of class.) The assignment cannot be allowed, since that might lead to referring to a Truckのインスタンスreferring to aです。

このような状況を防ぐために、明示的な型キャストを追加する必要があります。

Car c = (Car) vehicle;

型キャストは、我々はの価値を期待コンパイラ伝えvehicleあることをCarやサブクラスのCar 。必要に応じて、コンパイラは実行時の型チェックを実行するコードを挿入します。チェックが失敗すると、コード実行時にClassCastExceptionがスローされます。

すべての型キャストが有効であるわけではないことに注意してください。例えば:

String s = (String) vehicle;  // not valid

Javaコンパイラは、 Vehicleと型互換性のあるインスタンスはString 型互換性がないことを認識しています。型キャストは決して成功することはできませんでした.JLSはコンパイルエラーを引き起こすことを要求しています。

インタフェースへのプログラミング

インターフェイスへのプログラミングの背後にある考え方は、コードを主にインターフェイスに基づいており、インスタンス化時にはコンクリートクラスのみを使用することです。このコンテキストでは、Javaコレクションを扱う良いコードは、次のようになります(メソッド自体はまったく使用されているわけではありません)。

public <T> Set<T> toSet(Collection<T> collection) {
  return Sets.newHashSet(collection);
}

悪いコードはこのように見えるかもしれません:

public <T> HashSet<T> toSet(ArrayList<T> collection) {
  return Sets.newHashSet(collection);
}

前者は広範な議論の選択肢に適用できるだけでなく、その結果は他の開発者が提供するコードとより互換性があり、一般的にはインターフェイスへのプログラミングのコンセプトに従います。ただし、前者を使用する最も重要な理由は次のとおりです。

  • ほとんどの場合、結果が使用されるコンテキストは、具体的な実装が提供する多くの詳細を必要とせず、必要としないはずです。
  • インタフェースを遵守することで、より洗練されたコードが作成され、いくつかの特定のシナリオに対応するクラスにさらに別のパブリックメソッドが追加されます。
  • インタフェースは簡単に擬似的であるため、コードはよりテスト可能です。
  • 最後に、このコンセプトは、(少なくともテスト容易性のために)1つの実装のみが期待される場合でも役立ちます。

したがって、ある特定の実装を念頭に置いて新しいコードを書くときに、どのようにしてプログラミングの概念をインターフェースに簡単に適用できますか?一般的に使用する1つのオプションは、次のパターンの組み合わせです。

  • インターフェースへのプログラミング
  • 工場
  • ビルダー

これらの原則に基づく次の例は、いくつかの異なるプロトコル用に作成されたRPC実装の簡略化された切り捨てバージョンです。

public interface RemoteInvoker {
  <RQ, RS> CompletableFuture<RS> invoke(RQ request, Class<RS> responseClass);
}

上記のインタフェースは、ファクトリを介して直接インスタンス化されることは想定されていません。代わりに、HTTP呼び出し用とAMQP用の1つずつの具体的なインタフェースを取得します。それぞれは、ファクトリとインスタンスを構築するビルダを持ちます。上記のインターフェース:

public interface AmqpInvoker extends RemoteInvoker {
  static AmqpInvokerBuilder with(String instanceId, ConnectionFactory factory) {
    return new AmqpInvokerBuilder(instanceId, factory);
  }
}

AMQPで使用するためのRemoteInvokerインスタンスは、ビルダーに応じて簡単に(または複雑に)組み立てることができるようになりました。

RemoteInvoker invoker = AmqpInvoker.with(instanceId, factory)
  .requestRouter(router)
  .build();

要求の呼び出しは次のように簡単です。

Response res = invoker.invoke(new Request(data), Response.class).get();

Java 8では、静的メソッドを直接インターフェイスに配置できるため、 AmqpInvoker.with()置き換えられた上記のコードでは中間的なファクトリが暗黙になりました。バージョン8より前のJavaでは、内部のFactoryクラスでも同じ効果が得られます。

public interface AmqpInvoker extends RemoteInvoker {
  class Factory {
    public static AmqpInvokerBuilder with(String instanceId, ConnectionFactory factory) {
      return new AmqpInvokerBuilder(instanceId, factory);
    }
  }
}

対応するインスタンス化は、次のようになります。

RemoteInvoker invoker = AmqpInvoker.Factory.with(instanceId, factory)
  .requestRouter(router)
  .build();

上記のビルダーはこのように見えるかもしれませんが(実際のものはデフォルトから逸脱した15個までのパラメーターを定義できるので単純化していますが)この構造体はパブリックではないので、上記のAmqpInvokerインタフェースからのみ使用できます。

public class AmqpInvokerBuilder {
  ...
  AmqpInvokerBuilder(String instanceId, ConnectionFactory factory) {
    this.instanceId = instanceId;
    this.factory = factory;
  }

  public AmqpInvokerBuilder requestRouter(RequestRouter requestRouter) {
    this.requestRouter = requestRouter;
    return this;
  }

  public AmqpInvoker build() throws TimeoutException, IOException {
    return new AmqpInvokerImpl(instanceId, factory, requestRouter);
  }
}

一般に、ビルダーはFreeBuilderのようなツールを使って生成することもできます。

最後に、このインタフェースの標準的な(そして唯一の期待される)実装は、インタフェース、ファクトリ、およびビルダーの使用を強制するパッケージローカルクラスとして定義されています。

class AmqpInvokerImpl implements AmqpInvoker {
  AmqpInvokerImpl(String instanceId, ConnectionFactory factory, RequestRouter requestRouter) {
    ...
  }

  @Override
  public <RQ, RS> CompletableFuture<RS> invoke(final RQ request, final Class<RS> respClass) {
    ...
  }
}

一方、このパターンは、機能がどれほど単純か複雑かにかかわらず、新しいコードをすべて開発するのに非常に効率的であることがわかりました。

抽象クラスとインタフェースの使用法: "Is-a"リレーションと "Has-a"リレーション

抽象クラスを使用する場合:複数の関連オブジェクト間で同じまたは異なる動作を実装する

インタフェースを使用する場合:複数の無関係なオブジェクトによる契約を実装する

抽象クラスは、関係は「関係」を作成し、インターフェースは「持つ」機能を提供します。

これは以下のコードで見ることができます:

public class InterfaceAndAbstractClassDemo{
    public static void main(String args[]){
        
        Dog dog = new Dog("Jack",16);
        Cat cat = new Cat("Joe",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;
    }
    public abstract void remember();
    public abstract 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{
    void climb();
}
interface Think {
    void think();
}

interface Learn {
    void learn();
}
interface Apply{
    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:Jack:16
Cat:Cat:Joe: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は、共有属性を持つ抽象クラスです: namelifeExpectancyおよびabstractメソッド: remember()protectOwner()DogCatは、 remember() protectOwner()protectOwner()メソッドを実装したAnimalsです。

  2. Catclimb()ことができますが、 Dogはできません。 Dogthink()ことができthink()が、 Catはできません。これらの特定の機能は、実装によってCatおよびDog追加されます。

  3. ManAnimalはありませんが、 ThinkLearnApplyClimbことができます。

  4. CatManはありませんが、 Climbことができます。

  5. DogManはありませんが、それはLearnことができます

  6. ManCatDogもないが、 AnimalCat 、またはDogを伸ばすことなく後者の能力のいくつかを持つことができる。これはインタフェースで行われます。

  7. Animalは抽象クラスであるにもかかわらず、インターフェイスとは異なり、コンストラクタを持ちます。

TL; DR:

無関係のクラスはインタフェースを介して機能を持つことができますが、関連するクラスは基本クラスの拡張によって動作を変更します。

特定のユースケースでどのドキュメントを使用するかを理解するには、Javaのマニュアルページを参照してください。

次の場合は抽象クラスの使用を検討してください

  1. いくつかの密接に関連するクラスの間でコードを共有したいとします。
  2. 抽象クラスを拡張するクラスには、多くの一般的なメソッドやフィールドがあり、public以外のアクセス修飾子(protectedやprivateなど)が必要です。
  3. 非静的フィールドまたは非最終フィールドを宣言したいとします。

次の場合はインタフェースの使用を検討してください

  1. 無関係のクラスがあなたのインターフェースを実装することを期待します。たとえば、無関係な多くのオブジェクトがSerializableインターフェイスを実装できます。
  2. 特定のデータ型の振る舞いを指定したいが、その振る舞いを誰が実装するかは心配していない。
  3. あなたは型の多重継承を利用したいと思っています。

継承でオーバーライドする

継承のオーバーライドは、サブクラスのスーパークラスからすでに定義されたメソッドを使用する場合に使用されますが、スーパークラスで元々設計された方法とは異なります。オーバーライドを使用すると、既存の素材を使用してコードを再利用し、ユーザーのニーズに合わせて変更することができます。


次の例は、 ClassBが印刷メソッドを通じて送信される内容を変更することによってClassAの機能をオーバーライドする方法を示していClassB

例:

public static void main(String[] args) {
    ClassA a = new ClassA();
    ClassA b = new ClassB();
    a.printing();
    b.printing();
}

class ClassA {
    public void printing() {        
        System.out.println("A");
    }
}

class ClassB extends ClassA {
    public void printing() {
         System.out.println("B");
    }
}

出力:

A

B



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow