もじゃもじゃな人の雑記

当方は高専生でしたが今は腐れ大学生.今後は日記および備忘録として動きます.

Javaの復習してた 18/12/09

注意:若干長いけどゴミ記事です.


最近Javaの授業のお手伝いをすることがあるので,拙い知識を補うために復習してました.

それで,パラパラと教科書を見てたらインターフェースの継承の項目があって,あんまりやろうと思ったことがなかったのでやってみました.

なんか消すのももったいない(地味にハマりかけたので)けどGitに上げるほどでも当然ないのでここに置いときます.


作るもの:MyVector インターフェース

今回はベクトルっぽいものを実装するためのインターフェースとしてMyVectorインターフェースを作ります.

選んだ理由は,ベクトル自体が何らかの概念に従うものであって,2次元ベクトルなどさらに具体的なものを考える根幹である(と思っている)からです.

とはいえ数学もJavaも詳しくないので,解釈や思想はどこか変であるかもしれないという想定でいてください.その辺の懸念もあって,ベクトルインターフェースにはMyVectorと名付けて,オレオレVectorインターフェースということにしておきます.


MyVectorの定義

確か加法性とか必要だったよね?とか思いつつ,とりあえずWikipedia先生を見に行く.

ベクトル - Wikipedia

これを見つつ,インターフェースのためできるだけ一般的なものにしたいので,数学の項にある次の定義を参考にすることにします.

ベクトル空間の元。線形性を持つ、すなわち和とスカラー倍を取る事ができる量。一般の(広い意味での)ベクトル。

つまり,MyVectorインターフェースを実装するオブジェクトは線型性が保証されている必要があるわけですかね.

というところを踏まえて,定義してみます.

MyVectorに関する定義 : 線型性を持つ.

ただし線型性とは,ベクトル\vec{v}\vec{w},実数aがあるとき,

  1. \vec{v}+\vec{w}となるベクトル\vec{x}が(唯一)存在する
  2. a\vec{v}となるベクトル\vec{y}が(唯一)存在する

を満たす性質である.


JavaでMyVectorの実装

ではさっきの定義に従って,線型性を満たすインタフェースであるMyVectorインターフェースを書いてみます.

ちゃんと線型性のインターフェースを先に書いて,MyVectorインターフェースはそれを継承させることにします. また,線型性はすごく一般的な概念なので,Genericsを使うべきかなーと思ってそのようにします.

interface Linearity <T> {
    T add(T v);
    T multiply(double c);
}

interface MyVector <T> extends Linearity<T> {
    double magnitude();
    String toString();
}

うーん中身は簡単ですね.Genericsのところでちょっと引っかかってしまいましたが,こんな感じになりました.

Linearityでは加算とスカラー乗算の抽象メソッドを記述しています.どちらも演算の結果,自身と同型のものを返すので定義に合っていますね(多分).

それを継承するMyVectorですが,一応ベクトルなので大きさを持つだろうということでMyVectorにはmagnitudeメソッドを置いてます.

もっとたくさん持っていて欲しいものはありますが(内積外積偏角,etc.),実装するのが面倒なのでこれとtoStringだけにします.


2次元ベクトルのクラス(Vector2)を作る

インターフェースができたので,具象化します.

簡単なやつということで,2次元ベクトルのクラスにします.

class Vector2 implements MyVector<Vector2> {
    private double x, y;
    
    public Vector2() {
        x = 0.0;
        y = 0.0;
    }
    
    public Vector2(double x, double y) {
        this.x = x;
        this.y = y;
    }
    
    public Vector2 add(Vector2 v) {
        return new Vector2(this.x+v.x, this.y+v.y);
    }
    
    public Vector2 multiply(double c) {
        return new Vector2(this.x*c, this.y*c);
    }
    
    public double magnitude() {
        return Math.sqrt(x*x+y*y);
    }
    
    public String toString() {
        return "("+x+", "+y+")";
    }
}

インターフェースができていると何も考えずに実装するだけなので簡単ですね.オブジェクト指向のそういうところ好き.

同様にすれば当然n次元ベクトルも定義できるはず.

余談ですが,前にフィールドをリストにしてコンストラクタの引数も可変長引数にして,そもそもn次元に対応できるオブジェクトを作ろうと企んだこともあったんですが,面倒になってやめました(当時はC++を使っていて,templeteがよく分からず死んだ思い出がある).だってそもそも2次元と3次元さえあれば問題ないですもの.


使ってみる

public class Main {
    public static void main(String[] args) {
        Vector2 v = new Vector2(1.0, 2.0);
        Vector2 w = new Vector2(3.0, -1.0);
        double c = 3.0;
        
        System.out.println(v.add(w));       // (4.0, 1.0)
        System.out.println(v.multiply(c));  // (3.0, 6.0)
        System.out.println(v.magnitude());  // 2.23606797749979
    }
}

使えそうです.以上.