【20章】Javaを学ぼう

前章（【19章】Javaを学ぼう）で自転車と車のプログラムを作成しました。今回は重要な「オブジェクト指向」である継承について学び、さらに作成したプログラムを改良していきたいと思います！
私自身のアウトプットの場となりますので、よろしくお願いいたします！

#継承とは
既存のクラスのフィールドやメソッドを別のクラスに引き継ぐ機能を**「継承」**といいます。さらに継承してできる新しいクラスには独自のフィールドやメソッドを追加してカスタマイズすることも可能です。継承されるクラスを**「スーパークラス」**、継承してできる新しいクラスを**「サブクラス」**と呼びます。

##CarとBicycleの重複
CarクラスとBicycleクラスは、下図のように重複があります。コードの重複は修正・改善のしやすさなどを下げるため、できるだけ避けなければなりません。

```java:Car.java
import java.util.Scanner;
class Car {
 private String name;
 private String color;
 private int distance = 0;
 //private int fuel = 100;
 
 Car(String name, String color) {
  this.name = name;
  this.color = color;
 }

 public String getName() {
  return this.name;
 }

 public String getColor() {
  return this.color;
 }
  
 public void printData() {
  System.out.println("名前：" + this.name);
  System.out.println("色：" + this.color);
  System.out.println("走行距離：" + this.distance + "km");
  //System.out.println("ガソリン量：" + this.fuel + "L");
 }
}
```

```java:Bicycle.java
class Bicycle {
 private String name; 
 private String color;
 private int distance = 0;

 Bicycle(String name, String color) {
  this.name = name;
  this.color = color;
 }

 public String getName() {
  return this.name;
 }

 public String getColor() {
  return this.color;
 }

 public void printData() {
  System.out.println("名前：" + this.name);
  System.out.println("色：" + this.color);
  System.out.println("走行距離：" + this.distance + "km");
 }
}
```

オブジェクト指向では、あるクラスの内容を他のクラスが「引き継ぐ」ことができます。
先ほどの重複部分を、Vehicleクラス（乗り物）に定義し、そのクラスをCarクラスとBicycleクラスが引き継ぐことができれば、重複部分をなくすことができます。

##継承の方法
継承を用いて新しくサブクラスを定義するときは、**「extends」**を用いて、**「class サブクラス名 extends スーパークラス名」**としてクラスを定義します。

```java:スーパークラス
class スーパークラス名 {
 
}
```

```java:サブクラス
class サブクラス名 extends スーパークラス名 {
                 //スーパークラスを継承
}
```

それでは実際に作成したプログラムを継承によって改良していきたいと思います。
まず、CarクラスとBicycleクラスで重複しているコードをVehicleクラスに移動させます。移動させたら、CarクラスとBicycleクラスでVehicleクラスを継承します。

```java:Vehicle.java
// Vehicleクラスを定義し、
// CarクラスとBicycleクラスの共通部分を移動
class Vehicle {
 private String name;
 private String color;
 private int distance = 0;

 public String getName() {
  return this.name;
 }
 public String getColor() {
  return this.color;
 }
 public int getDistance() {                              //後に使うので、新たに定義した
  return this.distance;
 }
 public void setName(String name) {                      //後に使うので、新たに定義した
  this.name = name;
 }
 public void setColor(String color) {                    //後に使うので、新たに定義した
  this.color = color;
 }
 public void printData() {
  System.out.println("名前：" + this.name);
  System.out.println("色：" + this.color);
  System.out.println("走行距離：" + this.distance + "km");
 }
}
```

```java:Car.java
// Vehicleクラスを継承
class Car extends Vehicle {
 
}
```

```java:Bicycle.java
// Vehicleクラスを継承
class Bicycle extends Vehicle {
 
}
```

継承するため、新たに定義したVehicleクラスや、Vehicleクラスを継承したCarクラスとBicycleクラスの状態は上記の通りですが、一応Main.javaファイルの中身も確認しておきます。これから改善していきますので、とりあえずの状態です。

```java:Main.java
class Main {
 public static void main(String[] args) {
  Car car = new Car();
  Bicycle bicycle = new Bicycle();
 }
}
```

##スーパークラスのメソッドを呼び出す
CarクラスとBicycleクラス（サブクラス）はVehicleクラス（スーパークラス）のフィールドとメソッドを引き継いでいます。よって、CarクラスとBicycleクラス自体にはまだ何も定義されていませんが、CarクラスやBicycleクラスのインスタンスに対して、Vehicleクラスのインスタンスメソッドを呼び出すことが可能です。

```java:Vehicle.java
class Vehicle {
  .
  .
  .
 public void setName(String name) {                 
  this.name = name;
 }
 public void setColor(String color) {               
  this.color = color;
 }
  .
  .
}
```

```java:Car.java
class Car extends Vehicle {      // Vehicleクラスのインスタンスメソッドを継承
 
}
```

```java:Bicycle.java
// Vehicleクラスを継承
class Bicycle extends Vehicle {  // Vehicleクラスのインスタンスメソッドを継承
 
}
```

```java:Main.java
class Main {
 public static void main(String[] args) {
  Car car = new Car();
  car.setName("フェラーリ");                  //スーパークラスのインスタンスメソッドを呼び出す
  car.setColor("赤");

  Bicycle bicycle = new Bicycle();
  bicycle.setName = ("ジオス");             //スーパークラスのインスタンスメソッドを呼び出す
  bicycle.setColor = ("青");

  System.out.println("【車の情報】");         
  car.printData();                         //スーパークラスのインスタンスメソッドを呼び出す

  System.out.println("=================");
  System.out.println("【自転車の情報】");
  bicycle.printData();                     //スーパークラスのインスタンスメソッドを呼び出す
 }
}
```

サブクラスには、スーパークラスにない独自のフィールドやメソッドを追加し、カスタマイズすることができます。
インスタンスフィールドfuelはCarクラスに独自のフィールドです。fuelというフィールドと、そのゲッターをCarクラスに定義してあげましょう。また、chargeメソッドについてもここで定義しましょう。

```java:Vehicle.java
class Vehicle {
  .
  .
//編集なし
  .
  .
}
```

```java:Car.java
class Car extends Vehicle {      
 private int fuel = 50;

 public int getFuel() {
  return this.fuel;
 }

 public void charge(int litre) {
  System.out.println(litre + "L給油します");
  if(litre <= 0) {
   System.out.println("給油できません");
  } if else(litre + this.fuel >= 100) {
   System.out.println("満タンまで給油します");
   this.fuel = 100;
  } else {
   this.fuel += litre;
  }
  System.out.println("ガソリン量：" + this.fuel + "L");
 }
}
```

```java:Bicycle.java
class Bicycle extends Vehicle {  
 // 編集なし
}
```


```java:Main.java
import java.util.Scanner;

class Main {
 public static void main(String[] args) {
  Scanner scanner = new Scanner(System.in);
  Car car = new Car();
  car.setName("フェラーリ");                  
  car.setColor("赤");
  Bicycle bicycle = new Bicycle();
  bicycle.setName = ("ジオス");             
  bicycle.setColor = ("青");

  System.out.println("【車の情報】");         
  car.printData(); 
  car.getFuel(); 
  System.out.println("ガソリン量：" + car.getFuel() + "L");
  System.out.println("-----------------");
  System.out.print("給油する量を入力してください：");
  int litre = scanner.nextInt();
  car.charge(litre);                       

  System.out.println("=================");
  System.out.println("【自転車の情報】");
  bicycle.printData();                     
 }
}
```

##オーバーライド
Carクラスのインスタンスに対してprintDataメソッドを呼び出すときは、ガソリン量は表示できていません。ガソリン量は独自にcar.getFuel();でメソッドを呼び出し表示している状態なので、printDataメソッドをカスタマイズし、ガソリン量も表示させたいと思います。
スーパークラスから継承したメソッドと同名のメソッドをサブクラスに定義することで、スーパークラスのメソッドの内容を上書きすることができます。これを**「オーバーライド」**といいます。つまり、CarクラスにもprintDataメソッドを定義すると、VehicleクラスのprintDataメソッドが上書きされます。

```java:Car.java
class Car extends Vehicle {      
 private int fuel = 50;

 public int getFuel() {
  return this.fuel;
 }

 public void printData() {
  System.out.println("名前：" + this.getName());
  System.out.println("色：" + this.getColor());
  System.out.println("走行距離：" + this.getDistance() + "km");
  System.out.println("ガソリン量：" + this.fuel + "L");
 }

 public void charge(int litre) {
  System.out.println(litre + "L給油します");
  if(litre <= 0) {
   System.out.println("給油できません");
  } if else(litre + this.fuel >= 100) {
   System.out.println("満タンまで給油します");
   this.fuel = 100;
  } else {
   this.fuel += litre;
  }
  System.out.println("ガソリン量：" + this.fuel + "L");
 }
}
```

これで、Main.javaに記載しているcar.getFuel();の部分は不要になったので削除します。

```java:Main.java
import java.util.Scanner;

class Main {
 public static void main(String[] args) {
  Scanner scanner = new Scanner(System.in);
  Car car = new Car();
  car.setName("フェラーリ");                  
  car.setColor("赤");
  Bicycle bicycle = new Bicycle();
  bicycle.setName = ("ジオス");             
  bicycle.setColor = ("青");

  System.out.println("【車の情報】");         
  car.printData(); 
  System.out.println("-----------------");
  System.out.print("給油する量を入力してください：");
  int litre = scanner.nextInt();
  car.charge(litre);                       

  System.out.println("=================");
  System.out.println("【自転車の情報】");
  bicycle.printData();                     
 }
}
```

しかしながら、printDataメソッドのオーバーライドには重複があります。
CarクラスのprintDataメソッドは、ガソリン量を表示している箇所以外は、処理が重複しています。このコードの重複はなくしてあげましょう。

```java:Car.java
class Car extends Vehicle {      
   .
   .
   .
 public void printData() {
  super.printData();       //重複していた部分をスーパークラスのインスタンスメソッドで呼び出す
  System.out.println("ガソリン量：" + this.fuel + "L");
 }
   .
   .
   .
}
```

```java:Vehicle.java
class Vehicle {
   .
   .
   .
 public void printData() {
  System.out.println("名前：" + this.name);
  System.out.println("色：" + this.color);
  System.out.println("走行距離：" + this.distance + "km");
 }
}
```

**「super.メソッド名()」**とすると、サブクラスのインスタンスメソッドから、スーパークラスのインスタンスメソッドを呼び出すことができます。
これを使えば、CarクラスのprintDataメソッドで、ガソリン量を表示する箇所以外の処理はVehicleクラスのprintDataメソッドを呼び出すことで代用することができます。

ここまでが今回の継承についての内容になります。次章ではもう少し高度な継承を学び、今回改良したプログラムをさらに改良していきます！
最後までご覧いただきまして、ありがとうございました！