web-dev-qa-db-ja.com

Javaの抽象クラス

Javaの「抽象クラス」とは何ですか?

260
keyur

抽象クラスはインスタンス化できないクラスです。抽象クラスは、インスタンス化できることができる継承サブクラスを作成することによって使用されます。抽象クラスは継承サブクラスに対していくつかのことを行います。

  1. 継承サブクラスで使用できるメソッドを定義します。
  2. 継承サブクラスが実装しなければならない抽象メソッドを定義します。
  3. サブクラスを他のすべてのサブクラスと交換できるようにする共通のインタフェースを提供します。

これが例です:

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

「abstractMethod()」にはメソッド本体がないことに注意してください。このため、次のことはできません。

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

abstractMethod()を実装するメソッドはありません。そのため、JVMがnew ImplementingClass().abstractMethod()のようなものになったときにどうするべきかを知る方法はありません。

これは正しいImplementingClassです。

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

implementedMethod()finalMethod()を定義する必要はありません。それらは既にAbstractClassによって定義されています。

これは正しいImplementingClassです。

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

この場合、あなたはimplementedMethod()をオーバーライドしました。

ただし、finalキーワードのため、次のことは不可能です。

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

AbstractClass内のfinalMethod()の実装はfinalMethod()の最後の実装としてマークされているので、これを行うことはできません。他の実装は許可されません。

これで抽象クラスを2回実装することもできます

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

今どこか別の方法を書くことができます。

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

bAbstractClass型として宣言していても、"Overriden!"が表示されていることに注意してください。これは、インスタンス化したオブジェクトが実際にはImplementingClassであり、そのimplementedMethod()はもちろんオーバーライドされているためです。 (あなたはこれを多態性と呼ぶのを見たことがあるかもしれません。)

特定のサブクラスに固有のメンバーにアクセスしたい場合は、まずそのサブクラスにキャストダウンする必要があります。

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

最後に、次のことはできません。

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

一度に拡張できるクラスは1つだけです。複数のクラスを拡張する必要がある場合は、それらはインタフェースである必要があります。あなたはこれを行うことができます:

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

これがインタフェースの例です。

interface InterfaceA
{
    void interfaceMethod();
}

これは基本的に同じです。

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

唯一の違いは、2番目の方法では、それが実際にはインタフェースであることをコンパイラに知らせないことです。他の人にはインターフェースを実装させず、他の人にはインターフェースを実装させたくない場合に便利です。ただし、一般的な初心者用の経験則として、抽象クラスに抽象メソッドしかない場合は、おそらくそれをインタフェースにする必要があります。

以下は違法です。

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

インターフェースにメソッドを実装することはできません。つまり、2つの異なるインタフェースを実装しても、それらのインタフェースの異なるメソッドが衝突することはありません。インターフェース内のすべてのメソッドは抽象的なので、そのメソッドを実装する必要があります。また、そのメソッドが継承ツリーの唯一の実装であるため、コンパイラーはそのメソッドを使用する必要があることを認識しています。

329
Imagist

Javaクラスは、以下の条件下で抽象クラスになります。

1.少なくとも1つのメソッドが抽象としてマークされている:

public abstract void myMethod()

その場合、コンパイラはクラス全体を抽象としてマークするように強制します。

2。クラスは抽象としてマークされています。

abstract class MyClass

すでに述べたように、抽象メソッドがある場合、コンパイラはクラス全体を抽象としてマークするように強制します。しかし、抽象メソッドがなくても、クラスを抽象としてマークすることはできます。

一般的な用途:

抽象クラスの一般的な用途は、インタフェースと同じようなクラスの概要を提供することです。しかし、インタフェースとは異なり、すでに機能を提供できます。つまり、クラスの一部が実装され、一部がメソッド宣言で概説されています。 ("抽象")

抽象クラスはインスタンス化できませんが、抽象クラスに基づいて具象クラスを作成し、それをインスタンス化することはできます。そのためには、抽象クラスから継承し、抽象メソッドをオーバーライドする、つまりそれらを実装する必要があります。

71
Daniel Rikowski

abstractキーワードを使用して宣言されたクラスはabstract classとして知られています。抽象化は、データ実装の詳細を隠し、機能だけをユーザーに表示するプロセスです。抽象化によって、オブジェクトの動作ではなくオブジェクトの動作に焦点を合わせることができます。

抽象クラスの主なもの

  • 抽象クラスは抽象メソッドを含んでいてもいなくてもかまいません。非抽象メソッドが存在する可能性があります。

    抽象メソッドは、次のように、実装なしで宣言されたメソッドです(中括弧なしで、その後にセミコロンが付きます)。

    例:abstract void moveTo(double deltaX, double deltaY);

  • クラスに少なくとも1つの抽象メソッドがある場合、そのクラスは抽象クラスでなければなりません

  • 抽象クラスはインスタンス化できません(抽象クラ​​スのオブジェクトを作成することはできません)

  • 抽象クラスを使用するには、それを別のクラスから継承する必要があります。その中のすべての抽象メソッドに実装を提供します。

  • 抽象クラスを継承する場合は、その中のすべての抽象メソッドに実装を提供する必要があります。

抽象クラスを宣言する宣言時にクラスの前にabstractキーワードを指定すると抽象クラスになります。以下のコードを見てください。

abstract class AbstractDemo{ }

抽象メソッドを宣言する宣言中のメソッドの前にabstractキーワードを指定すると抽象化されます。以下のコードを見てください。

abstract void moveTo();//no body

なぜクラスを抽象化する必要があるのか​​

オブジェクト指向の描画アプリケーションでは、円、長方形、線、ベジェ曲線、およびその他の多くのグラフィックオブジェクトを描画できます。これらのオブジェクトはすべて特定の状態(例:位置、向き、線の色、塗りつぶしの色)と動作(例:moveTo、回転、サイズ変更、描画)を共有しています。これらの状態や動作の一部は、すべてのグラフィックオブジェクトで同じです(例:塗りつぶしの色、位置、およびmoveToの場合)。他のものは異なる実装を必要とします(例:サイズ変更や描画)すべてのグラフィックオブジェクトは、自分自身で描画またはサイズ変更できる必要があります。それらは、描画方法が異なるだけです。

これは抽象スーパークラスにとっては完璧な状況です。次の図に示すように、類似点を利用して、すべてのグラフィックオブジェクトを同じ抽象親オブジェクトから継承するように宣言できます(例:GraphicObject)。 enter image description here

まず、抽象クラスGraphicObjectを宣言して、現在位置やmoveToメソッドなど、すべてのサブクラスで完全に共有されるメンバー変数とメソッドを提供します。 GraphicObjectは、drawやresizeなどの抽象メソッドも宣言しています。これは、すべてのサブクラスによって実装される必要がありますが、異なる方法で実装される必要があります。 GraphicObjectクラスは次のようになります。

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

サブクラスでの抽象メソッドの使用法GraphicObjectCircleなどのRectangleの各非抽象サブクラスは、drawおよびresizeメソッドの実装を提供する必要があります。

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

mainメソッド内では、次のようにすべてのメソッドを呼び出すことができます。

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

Javaで抽象化する方法

Javaで抽象化を実現する方法は2つあります。

  • 抽象クラス(0〜100%)
  • インターフェース(100%)

コンストラクタ、データメンバ、メソッドなどを持つ抽象クラス

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

出力:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

2つの規則を覚えておいてください:

  • クラスに抽象メソッドと具象メソッドがほとんどない場合は、それをabstractクラスとして宣言します。

  • クラスに抽象メソッドしかない場合は、それをinterfaceとして宣言します。

参考文献:

20
Dev4World

これはインスタンス化できないクラスであり、クラスの実装に、おそらくそれが概説する抽象メソッドの実装を強制することになります。

4
Noon Silk

ここにあなたの答えを得なさい:

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

抽象クラ​​スはfinalメソッドを持てますか?

ところで - それらはあなたが最近尋ねた質問です。評判を築くための新しい質問について考えてください。

編集:

このポスターと参照されている質問のポスターの名前は同じであるか少なくとも類似していますが、user-idは常に異なることがわかりました。つまり、技術的な問題、keyurが再びログインして彼の質問に対する答えを見つけることに問題がある、あるいはこれはSOコミュニティを楽しませるための一種のゲームです)

3
Andreas_D

簡単に言えば、抽象クラスはもう少し機能のあるインターフェースのように考えることができます。

抽象クラスにも当てはまるインタフェースをインスタンス化することはできません。

あなたのインターフェース上であなたはただメソッドヘッダを定義することができ、そしてすべてのインプリメンターはそれらの強制を実装することallです。抽象クラスではメソッドヘッダを定義することもできますが、ここで - インタフェースの違いから - メソッドの本体(通常はデフォルトの実装)を定義することもできます。さらに、他のクラスが抽象クラスを拡張する(注意、実装しない、したがって子クラスごとに1抽象クラスを持つこともできる)場合、それらは抽象クラスのすべてのメソッドを実装することを強制されません。 abstract methodを指定しない限り(そのような場合はインターフェースの場合と同様に機能しますが、メソッド本体を定義することはできません)。

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

それ以外の場合、抽象クラスの通常のメソッドでは、「継承者」は通常どおりデフォルトの動作を使用するか、それをオーバーライドすることができます。

例:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}
3
Juri

Oracleから ドキュメント

抽象メソッドとクラス:

抽象クラスは抽象として宣言されているクラスです。抽象クラスは抽象メソッドを含んでも含まなくてもかまいません。

抽象クラスはインスタンス化できませんが、サブクラス化することはできます

抽象メソッドは、実装なしで宣言されているメソッドです(中括弧なし、セミコロン)、

abstract void moveTo(double deltaX, double deltaY);

クラスに抽象メソッドが含まれている場合は、次のようにクラス自体を抽象として宣言する必要があります。

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

抽象クラスがサブクラス化されると、そのサブクラスは通常、その親クラス内のすべての抽象メソッドの実装を提供します。ただし、そうでない場合は、サブクラスもabstractとして宣言する必要があります。

abstract classesinterfacesは関連しているので、SEに関する以下の質問を見てください。

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

InterfaceクラスとAbstractクラスの違いをどのように説明すればいいですか?

3
Ravindra babu

ソリューション - 基本クラス(抽象)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}
1

これらすべての投稿への追加はほとんどありません。

クラスを宣言したいのに、そのクラスに属するすべてのメソッドを定義する方法がわからない場合があります。たとえば、Writerというクラスを宣言し、その中にwrite()というメンバーメソッドを含めることができます。ただし、write()のコーディング方法はわかりません。これはWriterデバイスの種類によって異なるためです。もちろん、Printer、Disk、Network、ConsoleなどのWriterのサブクラスを派生させることでこれを処理する予定です。

1
adatapost

抽象クラスは直接インスタンス化することはできませんが、使用可能にするためには派生クラスでなければなりません。クラスMUSTが抽象メソッドを含んでいる場合は抽象的でなければなりません。

abstract class Foo {
    abstract void someMethod();
}

間接的に

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

ただし、クラスは抽象メソッドを含まずに抽象クラスにすることができます。直接のインスタント化を防ぐための方法です。

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

後者のスタイルの抽象クラスは、「インタフェースに似た」クラスを作成するために使用されることがあります。インタフェースとは異なり、抽象クラスは非抽象メソッドとインスタンス変数を含むことができます。これを使用して、拡張クラスに基本機能を提供することができます。

もう1つの頻繁なパターンは、抽象クラスで主な機能を実装し、拡張クラスで実装される抽象メソッドでアルゴリズムの一部を定義することです。愚かな例:

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}
1
janko

抽象クラスは、完全には実装されていませんが、サブクラスのための青写真のようなものを提供します。完全に定義された具象メソッドを含むという点で部分的に実装されているかもしれませんが、抽象メソッドを保持することもできます。これらはシグネチャを持つがメソッド本体を持たないメソッドです。どのサブクラスでも抽象メソッドごとに本体を定義する必要があります。それ以外の場合も抽象クラスとして宣言する必要があります。抽象クラスはインスタンス化できないため、利用するには少なくとも1つのサブクラスで拡張する必要があります。抽象クラスをジェネリッククラスと考えてください。サブクラスは欠けている情報を埋めるためにあります。

0
Nick Robertson

具体的な方法と非具体的な方法の両方を持つことができるクラス、つまりボディの有無にかかわらず。

  1. 実装されていないメソッドは 'abstract'キーワードを含まなければなりません。
  2. 抽象クラスはインスタンス化できません。
0
user1639837

抽象クラスは抽象として宣言されたクラスです。抽象クラスは抽象メソッドを含んでも含まなくてもかまいません。抽象クラスはインスタンス化できませんが、サブクラス化できます。

つまり、abstractキーワードで宣言されたクラスは、Javaでは抽象クラスとして知られています。抽象メソッド(本体なしのメソッド)と非抽象メソッド(本体付きのメソッド)があります。

重要な注意: -抽象クラスはオブジェクトのインスタンス化には使用できません。オブジェクト参照の作成に使用できます。実行時ポリモーフィズムに対するJavaのアプローチはスーパークラス参照を使用して実装されるためです。したがって、サブクラスオブジェクトを指すために使用できるように、抽象クラスへの参照を作成することが可能でなければなりません。以下の例でこの機能がわかります。

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 
0
Ketan G

それは何もしません、サブクラスのために共有される共通のテンプレートを提供するだけです。

0
bitfishxyz