Javaにおけるオブジェクト指向のまとめ
目次
クラスの定義
- 
classというキーワードでクラスを宣言
- 
new クラス名()でインスタンスの生成
class Foo {}
Foo foo = new Foo();
コンストラクタ、フィールド、メソッド
- クラス名と同名の関数を宣言するとコンストラクタになります (コンストラクタの返り値は書かない)
- フィールドとメソッドのアクセス修飾子を省略した場合は、 同一パッケージからアクセスできるメンバとなります
class Point {
    public int x;
    public int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public Point add(Point other) {
        return new Point(this.x + other.x, this.y + other.y);
    }
    public String toString() {
        return "(" + this.x + ", " + this.y + ")";
    }
}
public class Main {
    public static void main(String[] args) {
        Point p1 = new Point(1, 2);
        Point p2 = new Point(3, 4);
        System.out.println( p1.add(p2) );
    }
}
クラスメソッド、クラス変数
- クラスメソッドは static修飾子を使います
- クラス変数も static修飾子を使います
class User {
    // staticフィールド
    private static int userNum = 0;
    // staticメソッド
    public static int getUserNum() {
        return userNum;
    }
    public User() {
        userNum++;
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println(User.getUserNum()); //=> 0
        User user1 = new User();
        User user2 = new User();
        System.out.println(User.getUserNum()); //=> 2
    }
}
アクセス権
アクセス修飾子は public と private と protected の3種類あります。 アクセス修飾子を省略した場合は、同一パッケージからアクセスできるようになります。 なので、基本的には全てのメンバにアクセス修飾子をつけるのが、混乱が少なくて良いと思います。
オーバーロード
同じ名前のメソッドを定義することでオーバーロードすることができます。
class Sample {
    public static int foo(int x) {
        return x + 1;
    }
    public static String foo(String x) {
        return x + "1";
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println( Sample.foo(123) );   // => 124
        System.out.println( Sample.foo("123") ); // => 1231
    }
}
継承、オーバーライド
- 継承をするには class 子クラス extends 親クラスと書きます
- 親クラスへの参照は superを使います
- オーバーライドをするには、@Overrideアノテーションをメソッド宣言の前に付けます
class Point {
    public int x;
    public int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public String toString() {
        return "(" + this.x + ", " + this.y + ")";
    }
}
class Point3D extends Point {
    public int z;
    public Point3D(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
    @Override
    public String toString() {
        return "(" + this.x + ", " + this.y + ", " + this.z + ")";
    }
}
public class Main {
    public static void main(String[] args) {
        System.out.println( new Point(1, 2) );      // => "(1, 2)"
        System.out.println( new Point3D(1, 2, 3) ); // => "(1, 2, 3)"
    }
}
抽象クラス
抽象クラス・抽象メソッドを定義するには、abstract キーワードを付けます。
// 抽象クラスの定義
abstract class AbstractMusic {
    public abstract void play();
    public abstract void stop();
}
class Music extends AbstractMusic {
    @Override
    public void play() {
        System.out.println("play!");
    }
    @Override
    public void stop() {
        System.out.println("stop!");
    }
}
public class Main {
    public static void main(String[] args) {
        Music music = new Music();
        music.play(); // => "play!"
    }
}
インターフェース
インターフェースを定義するには、interface キーワードを付けます。
interface USBInterface {
    public static final float USB_VERSION = 3.0;
    public abstract boolean connectUSB();
    public abstract boolean disconnectUSB();
}
// Printerクラス は USBInterface を実装する
class Printer implements USBInterface {
    public boolean connectUSB() {
        // ...
    }
    public boolean disconnectUSB() {
        // ...
    }
    public boolean print(PDF pdf) {
        // ...
    }
}
また、Java8ではインターフェースに「デフォルトメソッド」を定義できるようになりました。
interface GreetingInterface {
    default String sayHello() {
        return "Hello Java8!";
    }
}
class GreetingInterfaceImpl implements GreetingInterface {}
class Main {
    public static void main(String[] args) {
        System.out.println(new GreetingInterfaceImpl().sayHello());
        // => Hello Java8!
    }
}
ジェネリックス
- ジェネリックを定義するには、class クラス名<仮の型名>と書きます
- 型を制限することもできます
    - 
<仮の型名 extends 他のクラス名>と書けば、他のクラスを派生しているクラスに限定することができます
- 
<仮の型名 super 他のクラス名>と書けば、他のクラスが継承しているクラスに限定することができます
 
- 
- 型を制限するときは、クラス名だけでなく、インターフェース名で指定することも可能です
// Rangeクラスは、上界と下界を持つ範囲クラス
// T型はComparableインターフェースに限定
class Range<T extends Comparable<T>> {
    T begin;
    T end;
    public Range(T begin, T end) {
        if (begin.compareTo(end) > 0) {
            throw new RuntimeException("Range: warning: *begin* must be less than *end*");
        }
        this.begin = begin;
        this.end   = end;
    }
    public boolean include(T item) {
        return (item.compareTo(begin) >= 0 && item.compareTo(end) < 0);
    }
}
public class Main {
    public static void main(String[] args) {
        Range<Integer> intRange = new Range<Integer>(new Integer(1), new Integer(9));
        System.out.println(intRange.include(5)); // => true
        Range<String> stringRange = new Range<String>("a", "e");
        System.out.println(stringRange.include("c")); // => true
        System.out.println(stringRange.include("z")); // => false
    }
}