📌

オブジェクト指向 少し発展

2024/04/29に公開

1.フィールドに他のクラスのインスタンス変数を定義する

class SampleA{
    private String name;
    SampleA(String name){ //生成時に引数で受け取る文字列を変数nameにセット
        this.name = name;
    }
    public void print(){
        System.out.println("This Is a" + this.name);
    }
}

上記のようなサンプルAクラスのインスタンス変数を持つサンプルBクラスを定義すると

class SampleB{
    private SampleA sample; //SampleA型の変数sampleを生成

    public SampleA getSample(){ //戻り値はSampleA型(インスタンス)
        return this.sample;
    }
    public void setSample(SampleA sample){
//this.sampleはこのクラス内で定義されいるSampleA型の変数、右辺は引数として受け取るSampleA型の別の変数
        this.sample = sample;
    }
}

SampleBで定義されているgetter/setterはそれぞれ

class Main{
    public static void main(String[] args){
        SampleA sample_a = new SampleA("No.1");//SampleAのインスタンスを生成(nameにNo.1を持っている)
        SampleB sample_b = new SampleB();//SampleBのインスタンスを生成
        //↑この時点ではsample_bが持っているSampleA型の変数にはNULLが入っている
        sample_b.setSample(sample_a);//sample_bが持っているSampleA型のインスタンスのnameに「No.1」がセットされる
        sample_b.getSample().print(); //sample_bが持っているSampleA型のインスタンスのprintメソッドが実行される
        //This Is a No.1が出力

    }
}

2.多態性
まず、2つのクラスを考える。

class Person{ //コンストラクタは記述を省略
    String name;
    int age;
    public void buy(Car car){
        car.setOwner(this);//このメソッドが呼ばれると、Car型のインスタンスのPerson型変数に対して自身の情報を与える。
    }
}
class Car{
    String name;
    int price;
    Person owner;
    public void setOwner(Person person){
        this.owner = person; //所有者情報をセット
    }
}

実際の使い方としては

Person person("JOH",20); //Person型のインスタンスを生成
Car car = new Car("BMW",1000); //Car型のインスタンスを生成(所有者所法を表すownerはNULL)
person.buy(car); //ここ要注意★

★の部分についての記述を説明する。
まず、★は「car.setOwner(person);」としても同様の結果になる。しかしこの書き方では、人が買うという行為を行ったときに所有者が確定するという現実の動作と齟齬が発生する。
personが買うことでcarの所有者が決定する、つまり、personインスタンスから所有者を決定できるようにしたいという意図がある。
★の部分の動作だが、まず、person内のbuyメソッドが呼び出される、それに渡すcar型のインスタンスは既に生成している。
そして、buyメソッドでは、「受け取ったcar型インスタンス内のPerson型変数に、呼び出し元のPerson型インスタンスの情報をセットする」という動作が行われる。
自分が理解しづらかった点は、呼び出し先で、呼び出し元の情報を呼び出し先の変数に代入する、という行ったり来たりのデータのやり取りの流れがつかみにくいところだった。

前置きが長くなったが、多態性(ポリモーフィズム)とは、
このbuyメソッドが受け取る変数型をスーパークラス型にできるということだ。
いま、Person内のbuyメソッドはCar型変数しか受け取れないが、乗り物というのはCar以外にもたくさんあり、Car型はその中の一種にすぎない。つまり、Carのスーパークラスとして、Vehicle型が定義されていれば、buyメソッドはCarのスーパークラスであるVehicle型を受け取るようにすると、Car型を含めたVehicleのサブクラス全ての変数の受け取りが可能となる。
「継承」とは、単にフィールドやメソッドを受け継ぐだけでなく、方そのものも受け継いでいるので、仮に、Carクラスを

class Car extends Vehicle{
}

として定義していれば、Car carとして生成されたCar型インスタンスcarは、「Car」と「Vehicle」の両方の型を持っているということになる。
サブクラスごとに別の処理が施されていれば、それらのスーパークラスを引数として受け取って何らかの処理を行うようなメソッドを複数のサブクラスから呼び出したとき、それらの振る舞いが変わることがある。同じメソッドを呼び出しているにもかかわらず、動作が異なって見えることがあるので、これを多態性という。

Discussion