This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

オブジェクト指向の基本

Last updated at Posted at 2022-04-22

継承

クラスを定義する際に、クラス名+extends+基底クラス名とすることでクラスを継承し、その機能を使うことができる。

superキーワード

子クラスから親クラスのメソッドやフィールド、コンストラクタへアクセスするために用いる。
共通する処理は親クラスのメソッドに記述し、superで参照する。

sample.java
public class Sample {

	public static void main(String[] args) {
		
		GasolineCar g = new GasolineCar("赤");
		HybridCar h = new HybridCar("白");
		
		g.drive(1.0);
		h.drive(2.0);
		
	}
}
Car.java
//基底クラス
public class Car {
	
	double distance = 0.0; //総走行距離
	String color = "";

	//コンストラクタ
	public Car(String color) {
		this.color = color;
	}
	
	public void drive(double d) {
		
		distance +=d;
		
	}

}
GasolineCar.java
// extendsで継承
public class GasolineCar extends Car{
	
	public GasolineCar(String color) {
		super(color);//親クラスCarのコンストラクタを参照
	}
	
	public void drive(double d) {
			
		super.drive(d);//親クラスのdriveメソッドを呼び出す
		System.out.println("-----------------------");
		System.out.println("ぶーん");
		System.out.println("ガソリンを消費して"+d+"km走行しました。");
		System.out.println("マイレージは、"+distance+"kmです。");
		}


}
HybridCar.java
public class HybridCar extends Car {
	
	public HybridCar(String color) {
		super(color);
	}
	
	public void drive(double d) {
		
		super.drive(d);
		System.out.println("-----------------------");
		System.out.println("すいーん");
		System.out.println(d+"km走行しました。燃費もいいですよ");
		System.out.println("マイレージは、"+distance+"kmです。");
	}


}

抽象クラスと抽象メソッド

抽象化インスタンス化できないクラスで、abstractを先頭につけて定義する。
継承してより具体性の高いクラスを作らないと使用できない。

抽象メソッドは、メソッド名や受け取るパラメータ、返す値の型は書かれているが、処理ブロックは書かれていないメソッドのことである。継承したクラスで実装し、処理を記述する。
抽象メソッドを1つでも持つクラスは抽象クラスであり、クラス名の前にabstractをつける必要がある。
サブクラスにあるメソッドを必ず持たせたいという場合は、スーパークラスに抽象メソッドとして定義しておく。

Sample.java
public class Sample {

	public static void main(String[] args) {

		Praus p = new Praus("グレー");

		p.drive(1.0);
		p.drive(5.0);
		p.drive(100.0);

	}
}
Car.java
//抽象化クラスの定義
abstract public class Car {

	double distance = 0.0; // 総走行距離
	String color = "";

	public Car(String color) {
		this.color = color;
	}

	public void drive(double d) {

		distance += d;

	}

}
GasolineCar.java
abstract public class GasolineCar extends Car {

	public GasolineCar(String color) {
		super(color);
	}

	public void drive(double d) {

		super.drive(d);
		this.useGasoline(d);

	}
 
    // 抽象メソッドの定義
	abstract void useGasoline(double d);

}
HybridCar.java
abstract public class HybridCar extends Car {

	public HybridCar(String color) {
		super(color);
	}

	public void drive(double d) {

		super.drive(d);
		this.useEnergy(d);

	}

	abstract void useEnergy(double d); 

}
Praus.java
//抽象クラスの継承
public class Praus extends HybridCar {

	public Praus(String color) {
		super(color);
	}
     
    //抽象メソッドの実装
	@Override
	void useEnergy(double d) {
		System.out.println(d + "km走行するための燃料を使いました。");
	}

	@Override
	public void drive(double d) {
		System.out.println("--------------------------------");
		System.out.println(this.color + "のプラウスが走っています。");
		super.drive(d);//親クラスであるHybridCarクラスのdriveメソッドが実行される
	}

}

結果
--------------------------------
グレーのプラウスが走っています
1.0km走行するための燃料を使いました
--------------------------------
グレーのプラウスが走っています
5.0km走行するための燃料を使いました
--------------------------------
グレーのプラウスが走っています
100.0km走行するための燃料を使いました

上記例でのクラスの関係は、下の図の通り。
クラス関係.png

カプセル化

オブジェクト内のクラスやメソッド、フィールドに対して外部からアクセスできないようにすること。クラス間の依存関係を低減することができるという意義がある。
他のクラスから変更されたくないフィールドやメソッドのアクセス修飾子をprivate修飾子にすることでカプセル化できる。継承先でアクセスしたい場合は、protected修飾子を付ける(または何もつけない)。
フィールドはprivate、メソッドはpublicにするのが定石。

内部処理を知らずともそのクラスを利用することができるため、プログラムの拡張が容易になる。また、機能をAPIとしてクラス単位で提供することができるため、プログラムの構造が整理される。

ゲッターとセッターの定義

オブジェクト内部のメンバ変数に外部からアクセスするために用意されたメソッドをアクセサという。オブジェクト指向においてインスタンス内の変数などは内部の状態を表すものであり、外部から直に参照したり操作したりすべきでないという考え方に基づく。変数などへのアクセスに必ず対応するメソッドを経由することにより、メソッド内で適切にチェックや処理を行って破綻の無いように外部からのアクセスをコントロールできるという利点がある。
一方、Javaのようにpublic宣言が用意されている言語では、特に事情がない限り外部に公開してもよい変数などは直に操作するようにしたほうが記述が完結になり、コード量や処理量も軽量になるため、必ずしもすべてにアクセサを用意する必要はないとする考え方もある。C#やSwiftのように、アクセサを自動生成して変数を直接参照するようなコードを記述すると内部的に自動でアクセサ経由にしてくれる言語もある。

ゲッターを生成すると、カプセル化されたフィールドを外部から参照できるようになる。
セッターを生成すると、カプセル化されたフィールドを外部から変更できるようになる。

Person.java
public class Person {
	final static int MAN = 1;
	final static int WOMAN = 2;

	private String name;//メンバ変数のカプセル化
	private int age;
	private int sex;

	public Person(String name,int age,int sex) {
		
		this.name = name;
		this.age = age;
		this.sex = sex;

	}
	
	// ゲッターの生成
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	public int getSex() {
		return sex;
	}

    // セッターの生成
	public void setAge(int age) {
		if (age<0) {
			System.out.println("マイナスの年齢をセットできません");
			return;
		}
		this.age = age;
	}

多態性

ポリフォーリズムとも呼ばれる概念で、サブクラスのインスタンスはスーパークラスのクラス型変数に代入できる。これにより同じ内容を持つメソッドを、親クラスから呼び出すことでコードをシンプルにすることができる。
メソッドの名前が同じで、パラメータの種類だけが違うものをメソッドのオーバーロードというが、これを一つのメソッドで記述する。

instanceof演算子

あるオブジェクトの型を動的に判定するための演算子。
以下の判定などに用いる。

  • オブジェクトが、あるクラスのインスタンスか
  • オブジェクトが、あるクラスの子クラスのインスタンスか
  • オブジェクトが、特定のインターフェースを実装したインスタンスか
オブジェクト instanceof 

例1

sample.java
public class Sample {

	public static void main(String[] args) {

		Praus praus = new Praus("グレー");
		FlyingRandyCruiser randy = new FlyingRandyCruiser("白");
		FlyingPerson person = new FlyingPerson("太郎", 8, Person.MAN);

		driveThreeTimes(praus);
		makeItFlyThreeTimes(randy);

	}

	// Praus,FlyingRandyCruiserの親クラスCarをパラメータに設定
	static void driveThreeTimes(Car car) {
		car.drive(1.0);
		car.drive(2.0);
		car.drive(3.0);

		// HybridCarを継承したインスタンスなら実行
		if (car instanceof HybridCar) {
			System.out.println("環境に優しいですね");
		}
	}

	// FlyingPerson,FlyingRandyCruiserが共に実装しているFlyableインターフェイスをパラメータに設定
	static void makeItFlyThreeTimes(Flyable obj) {
		obj.fly();
		obj.fly();
		obj.fly();

	}

}
結果
1.0km走行するための燃料を使いました
--------------------------------
グレーのプラウスが走っています
2.0km走行するための燃料を使いました
--------------------------------
グレーのプラウスが走っています
3.0km走行するための燃料を使いました
環境に優しいですね
おおランディクルーザーが飛びました
おおランディクルーザーが飛びました
おおランディクルーザーが飛びました

上記例のクラスとインターフェイスの関係は以下の通り。
クラス関係1.png

例2

Main.java
class Main {
  public static void main(String[] args) {
    Person person1 = new Person("Kate", "Jones", 27, 1.6, 50.0);
    Person person2 = new Person("John", "Christopher", "Smith", 65, 1.75, 80.0);

    Car car = new Car("フェラーリ", "赤");
    Bicycle bicycle = new Bicycle("ビアンキ", "緑");
    
    // PersonクラスのインスタンスをVehicleクラスのインスタンス変数ownerにセット
    person1.buy(car);
    person2.buy(bicycle);

    System.out.println("【車の情報】");
    car.printData();
    System.out.println("-----------------");
    System.out.println("【車の所有者の情報】");
    car.getOwner().printData(); // getOwnerメソッドで返されるPersonクラスのインスタンスに対してprintDataメソッドを呼び出す

    System.out.println("=================");
    System.out.println("【自転車の情報】");
    bicycle.printData();
    System.out.println("-----------------");
    System.out.println("【自転車の所有者の情報】");
    bicycle.getOwner().printData();
  }
}

Person.java
class Person {
  private String firstName;
  private String middleName;
  private String lastName;
  private int age;
  private double height;
  private double weight;

  Person(String firstName, String lastName, int age, double height, double weight) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.height = height;
    this.weight = weight;
  }

  Person(String firstName, String middleName, String lastName, int age, double height, double weight) {
    this(firstName, lastName, age, height, weight);
    this.middleName = middleName;
  }
  
  public String fullName() {
    if (this.middleName == null) {
      return this.firstName + " " + this.lastName;
    } else {
      return this.firstName + " " + this.middleName + " " + this.lastName;
    }
  }

  public void printData() {
    System.out.println("名前は" + this.fullName() + "です");
    System.out.println("年齢は" + this.age + "歳です");
    System.out.println("身長は" + this.height + "mです");
    System.out.println("体重は" + this.weight + "kgです");
    System.out.println("BMIは" + Math.round(this.bmi()) + "です");
  }

  public double bmi() {
    return this.weight / this.height / this.height;
  }
  
  // Vehicle型の値を値を受け取るbuyメソッド
  public void buy(Vehicle vehicle) {
    // buyメソッドを呼び出しているPersonクラスのインスタンスをVehicleクラスのインスタンス変数ownerにセット
    vehicle.setOwner(this);
  }
  
}
Vehicle.java
abstract class Vehicle {
  private String name;
  private String color;
  protected int distance = 0;
  private Person owner;

  Vehicle(String name, String color) {
    this.name = name;
    this.color = color;
  }
  
  // ゲッターを定義
  public String getName() {
    return this.name;
  }
  public String getColor() {
    return this.color;
  }
  public int getDistance() {
    return this.distance;
  }
  public Person getOwner() {
    return this.owner;
  }
  
  // セッターを定義
  public void setName(String name) {
    this.name = name;
  }
  public void setColor(String color) {
    this.color = color;
  }
  public void setOwner(Person person) {
    this.owner = person;
  }
  
  // 名前、色、走行距離を出力するメソッド
  public void printData() {
    System.out.println("名前:" + this.name);
    System.out.println("色:" + this.color);
    System.out.println("走行距離:" + this.distance + "km");
  }

  public abstract void run(int distance);
}
Car.java
class Car extends Vehicle {
  private int fuel = 50;

  Car(String name, String color) {
    super(name, color);
  }

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

  public void printData() {
    super.printData();
    System.out.println("ガソリン量:" + this.fuel + "L");
  }

  public void run(int distance) {
    System.out.println(distance + "km走ります");
    if (distance <= this.fuel) {
      this.distance += distance;
      this.fuel -= distance;
    } else {
      System.out.println("ガソリンが足りません");
    }
    System.out.println("走行距離:" + this.distance + "km");
    System.out.println("ガソリン量:" + this.fuel + "L");
  }

  public void charge(int litre) {
    System.out.println(litre + "L給油します");
    if (litre <= 0) {
      System.out.println("給油できません");
    } else if (litre + this.fuel >= 100) {
      System.out.println("満タンまで給油します");
      this.fuel = 100;
    } else {
      this.fuel += litre;
    }
    System.out.println("ガソリン量:" + this.fuel + "L");
  }
}
Bicycle.java
class Bicycle extends Vehicle {
  Bicycle(String name, String color) {
    super(name, color);
  }

  public void run(int distance) {
    System.out.println(distance + "km走ります");
    this.distance += distance;
    System.out.println("走行距離:" + this.distance + "km");
  }
}
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up