JavaRush /Java Blog /Random-JA /Java の抽象クラスと具体的な例

Java の抽象クラスと具体的な例

Random-JA グループに公開済み
こんにちは!これまでの講義では、インターフェースについて学び、それが何に必要なのかを理解しました。今日のトピックは前回のトピックと共通する点があります。Java の 抽象クラスについて話しましょう。Java の抽象クラスと具体的な例 - 1

クラスが「抽象」と呼ばれる理由

おそらく「抽象化」とは何かを覚えているでしょう - すでに説明しました :) 突然忘れてしまったとしても、大丈夫です、思い出してください:これは OOP の原則であり、これに従ってクラスを設計したりオブジェクトを作成したりするときに、次のことを強調する必要があります。エンティティの主なプロパティのみを抽出し、二次的なプロパティは破棄します。たとえば、学校の教師などのクラスを設計している場合、「高さSchoolTeacher」特性は必要ないと思われます。確かに、教師にとって、この特性は重要ではありません。しかし、プログラム内にバスケットボール選手というクラスを作成すると、身長が主な特徴の 1 つになります。したがって、抽象クラスは、将来のクラスのグループにとって最も抽象的で、まあまあ近い「空白」です。この調製物は、完成した形では使用できません。「生」すぎるためです。ただし、これは、将来のクラス (抽象クラスの継承者) が持つ特定の一般的な状態と動作を記述します。 BasketballPlayer

Java 抽象クラスの例

車の簡単な例を見てみましょう。
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
最も単純な抽象クラスは次のようになります。ご覧のとおり、特別なことは何もありません :) 何に必要なのでしょうか? まず第一に、彼は私たちが必要とする実体、つまり車を可能な限り最も抽象的な方法で説明します。抽象という言葉がここにあるのには理由があります。世の中に「ただの機械」は存在しません。トラック、レースカー、セダン、クーペ、SUVがあります。 私たちの抽象クラスは、後で車のクラスを作成するための単なる「青写真」です。
public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println("The sedan accelerates!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}
これは、相続に関する講義で話した内容とよく似ています。Carそこにのみ、抽象ではないクラスとそのメソッドがありました。ただし、この解決策には多くの欠点があり、それらは抽象クラスで修正されます。何よりもまず、抽象クラスのインスタンスは作成できません。
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
この「トリック」は、Java の作成者によって特別に実装されました。もう一度、覚えておいてください。抽象クラスは、将来の「通常の」クラスの単なる青写真です。図面のコピーは必要ありませんよね?したがって、抽象クラスのインスタンスを作成する必要はありません :) そして、クラスがCar抽象クラスでない場合は、そのオブジェクトを簡単に作成できます。
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // some logic
   }

   public  void brake() {
       // some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Everything is OK, the machine has been created
   }
}
さて、私たちのプログラムにはある種の理解できない車が含まれています - トラックでも、レーシングカーでも、セダンでもなく、一般的なものです。自然界には存在しない、同じ「ただの機械」です。同じ例が動物にも当てはまります。プログラムにオブジェクトがAnimal単なる動物」として登場した場合を想像してください。それがどのような種類で、どの科に属し、どのような特徴を持っているのかは不明です。彼を番組で見るのは奇妙だろう。自然界には「ただの動物」は存在しません。犬、猫、キツネ、モグラなどのみ。抽象クラスは私たちを「単なるオブジェクト」から解放します。これらは私たちに基本的な状態と動作を与えます。たとえば、すべての車にはモデル最高速度が設定されている必要があり、またアクセルブレーキもできる必要があります。それだけです。これは一般的な抽象スキームであり、必要なクラスは自分で設計します。 注意:抽象クラス内の 2 つのメソッドもabstractとして指定されており、まったく実装されていません。理由は同じです。抽象クラスは「単なるマシン」の「デフォルトの動作」を作成しません。彼らは、すべての車を作ることができればいいと言っているだけです。ただし、それでもデフォルトの動作が必要な場合は、抽象クラスにメソッドを実装できます。Java はこれを禁止していません。
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Let's go!");
   }

   public abstract void brake();

   //getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan slows down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
コンソール出力: 「加速してください!」 ご覧のとおり、抽象クラスに 1 つのメソッドを実装しましたが、2 番目のメソッドは実装していませんでした。その結果、クラスの動作はSedan2 つの部分に分割されました。クラスのメソッドを呼び出すとgas()、親の抽象クラスから「プルアップ」されCarbrake()クラス内のメソッドを再定義しましたSedan。非常に便利で柔軟であることがわかりました。しかし、今のクラスはそれほど抽象的ではありませんか? 結局のところ、実際、彼のメソッドの半分は実装されています。実際、これは非常に重要な機能ですが、クラスのメソッドの少なくとも 1 つが抽象である場合、クラスは抽象です。少なくとも 2 つの方法のうちの 1 つ、1,000 の方法のうちの少なくとも 1 つは問題ではありません。抽象メソッドを残さずにすべてのメソッドを実装することもできます。抽象メソッドのない抽象クラスが存在します。原則として、これは可能であり、コンパイラはエラーを生成しませんが、これは行わない方が良いです。abstract という言葉はその意味を失い、同僚のプログラマーはこれを見て非常に驚くでしょう :/ さらに、メソッドががabstractという単語でマークされている場合、各子孫クラスはabstractを実装するか、abstractと宣言する必要があります。それ以外の場合、コンパイラはエラーをスローします。もちろん、各クラスは 1 つの抽象クラスのみを継承できるため、継承に関しては抽象クラスと通常のクラスに違いはありません。抽象クラスから継承するか、通常のクラスから継承するかは関係ありません。存在できる親クラスは 1 つだけです。

なぜ Java には複数のクラスの継承がないのですか?

Java には多重継承がないことはすでに述べましたが、その理由はまだわかっていません。今度はこれを試してみましょう。重要なのは、Java に複数の継承がある場合、子クラスはどの動作を選択するかを決定できないということです。2 つのクラスがあるとします -TosterNuclearBomb:
public class Toster {


 public void on() {

       System.out.println("The toaster is on, the toast is getting ready!");
   }

   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Взрыв!");
   }
}
ご覧のとおり、どちらにもメソッドがありますon()。トースターの場合はトーストを焼き始め、核爆弾の場合は爆発を引き起こします。Oh :/ さて、あなたが (なぜ突然かわかりませんが) その中間のものを作ろうと決めたと想像してください。そしてここがあなたのクラスです - MysteriousDevice! もちろん、このコードは機能しません。単に「どのように機能するか」の例として示します。
public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // And what should happen here? Will we get a toast, or a nuclear apocalypse?
   }
}
何が得られたか見てみましょう。この謎の装置はトースターと核爆弾の両方から来ています。どちらにもメソッドがありon()、その結果、on()オブジェクトMysteriousDeviceを呼び出した場合にどのメソッドを起動すべきかが明確ではありません。オブジェクトはこれを理解できません。まあ、おまけに、核爆弾には方法がないoff()ので、もし推測が間違っていたら、装置の電源を切る方法がなくなってしまいます。 Java の抽象クラスと具体的な例 - 2 オブジェクトがどの動作を選択すべきか明確ではないこの混乱のため、Java の作成者は多重継承を放棄しました。ただし、Java クラスが多くのインターフェイスを実装していることを思い出してください。ところで、あなたはすでに学習中に少なくとも 1 つの抽象クラスに遭遇したことがあります。とはいえ、気づかなかったかもしれません:)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
ここはあなたの古い友人クラスですCalendar。それは抽象的であり、複数の継承者がいます。そのうちの 1 つは ですGregorianCalendar。すでに日付に関するレッスンで使用しました:) すべてが明確になったようですが、残っている点は 1 つだけです。抽象クラスとインターフェイスの基本的な違いは何ですか? なぜ 1 つに限定せず、両方を Java に追加したのでしょうか? これで十分かもしれません。これについては次の講義でお話します。またね:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION