Javaを使ったオブジェクト指向プログラミング総まとめ

# Javaを使ったオブジェクト指向プログラミング総まとめ

勉強会に向けて作った資料が、「まぁ自分の割にはそこそこなの作れたのかな」と思ったので、これを期に初投稿。といいつつ、これで間違った内容を書いていたらとてもとても恥ずかしい。

## クラスとは

オブジェクト指向では、__振る舞い__と__属性__を持つ1の単位を__オブジェクト__と呼び、このオブジェクトの種類を__クラス__と呼ぶ。もう少し話を砕くと、

* 振る舞い：ある動作。メソッド
* 属性：ある情報。フィールド
* オブジェクト： メソッド＋フィールド（つまり__メンバ__）
* クラス：オブジェクトの種類

である。

クラスの定形構文は以下の通りである。

```java
class sandbox {
  public int field;
  public void method() {
    // Write anything process.
  }
}
```

## 基本的なクラスの使い方

### インスタンス化

__クラスオブジェクトを生成すること__。別名「`new`する」。インスタンス化は以下のように行う。インスタンス化することで、インスタンス化したクラスのメンバやメソッドが使える。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class(); // Create instance.
    cls.method(); // You can action method() of  Class.
  }
}

class Class {
  public int field;
  public void method() {
    // Write anything process.
  }
}
```

### コンストラクタ

コンストラクタとは__インスタンス化された際に一度だけ実行されるメソッド__。コンストラクタを生成する際は、メソッド名をクラス名と同じにすれば良い。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class();
    // Create instance and action constructor.
  }
}

class Class {
  public int field;
  public Class() {
    System.out.println("Action constructor.");
  }
  public void method() {
    // Write anything process.
  }
}
```

実行結果

```
Action constructor.
```

### 修飾子

#### 1. アクセス修飾子

アクセス修飾子をつけることで、外部からのアクセスを制限することができる。

|アクセス修飾子|アクセス可能範囲|
|:---:|:---|
|`public`|すべて|
|`protected`|同一パッケージ内・自クラス・サブクラス|
|なし|同一パッケージ内・自クラス|
|`private`|自クラス|

簡単なアクセス例は以下の通り。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class(); // Create instance.
    System.out.println("You can access " + cls.public_fld + " field.");
    System.out.println("You can access " + cls.protected_fld + " field.");
    System.out.println("You can access " + cls.nothing_fld + " filed.");

    // Compile err.
    // System.out.println("You can " + cls.private_fld + " field.");
  }
}

class Class {
  public String public_fld = "public";
  protected String protected_fld = "protected";
  String nothing_fld = "nothing";
  private String private_fld = "private";
}
```

実行結果

```
You can access public field.
You can access protected field.
You can access nothing field.
```

最後の`System.out.println("You can " + cls.private_mbr + "member");`をコメント解除してコンパイルしようとすると、アクセス制限でコンパイルエラーが起きる。

#### 2. `static`修飾子

`static`修飾子をつけると、実行時にメモリ上に展開されてインスタンス化しなくてもアクセスできるようになる。

```java
class sandbox {
  public static void main(String[] args) {
    System.out.println("You can access " + Class.static_fld + " field.");
  }
}

class Class {
  static String static_fld = "static";
}
```

実行結果

```
You can access static field.
```

#### 3. `final`修飾子

`final`修飾子を使用することで、定数とし、値の変更ができなくなる。

```java
class sandbox {
  public static void main(String[] args) {
    System.out.println("You can access " + Class.static_fld + "member.");

    // Compile err.
    // Class.static_fld = "final";
  }
}

class Class {
  static final String static_fld = "static";
}
```

### カプセル化

フィールドとメソッドをひとまとめにして、保護したいメンバに`private`をつけてアクセスできないようにすること。カプセル化は基本、

* 値を取得する：`getter`
* 値を代入する：`setter`

がよく使われている。この2つのメソッドのことは__アクセサメソッド__と呼ぶ。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class();
    cls.setField("hoge");
    System.out.println(cls.getField());
  }
}

class Class {
  private String field = "";

  /**
   * Accessor method.
   * setField(String param) -> Setter
   * getField() -> Getter
  **/
  void setField(String param) {
    field = param;
  }

  String getField() {
    return field;
  }
}
```

実行結果

```
hoge
```

しかし、`getter`と`setter`を作って、せっかく`private`をつけたフィールドにアクセスできてしまうと意味がないという話もあって、純粋な`getter`や`setter`はカプセル化を実現しないと、[この記事](https://qiita.com/katolisa/items/6cfd1a2a87058678d646)に書いていた。

ちなみにカプセル化は、データや処理を気にせずに目的を達成できるようにしたものという意味もある（コメントで教えていただき、[記事](https://qiita.com/shiracamus/items/ee10c7cf16102898bbeb#_reference-867e1b32cdfedfcc02e2)にもしてくれました。）。

## 発展的なクラスの使い方

### 継承

クラスに__親子関係をもたせる__こと。親クラスを継承した子クラスは、__親クラスの機能が受け継がれる__。

```java
class sandbox {
  public static void main(String[] args) {
    Child cld = new Child();
    cld.sayCommentByPerson();
    cld.sayCommentByChild();
  }
}

// Super class.
class Person {
  void sayCommentByPerson() {
    System.out.println("I am Person.");
  }
}

// Sub class.
class Child extends Person {
  void sayCommentByChild() {
    System.out.println("I am Child.");
  }
}
```

実行結果

```
I am Person.
I am Child.
```

#### 親クラスのコンストラクタを呼ぶには

もし、親にコンストラクタがあり、それを呼びたいときは、`super();`とすれば良い。

```java
class sandbox {
  public static void main(String[] args) {
    Child cld = new Child();
    cld.sayCommentByChild();
  }
}

// Super class.
class Person {
  Person() {
    System.out.println("I am Person.");
  }
}

// Sub class.
class Child extends Person {

  //Call constructor of super class.
  Child() {
    super();
  }

  void sayCommentByChild() {
    System.out.println("I am Child.");
  }
}
```

実行結果

```
I am Person.
I am Child.
```

### オーバーロード

オーバーロードとは__異なる引数を持つ同じ名称のメソッドを複数生成する__こと。

```java
class sandbox {
  public static void main(String[] args) {
    Class strClass = new Class("hoge");
    Class intClass = new Class(1);
  }
}

class Class {
  Class(String param) {
    System.out.println("String: " + param);
  }
  
  Class(int param) {
    System.out.println("Integer: " + param);
  }
}
```

実行結果

```
String: hoge
Integer: 1
```

### オーバーライド

オーバーライドは、__親クラスから継承されたメソッドを子クラスで上書きする__こと。

```java
class sandbox {
  public static void main(String[] args) {
    Child cld = new Child();
    cld.sayComment();
  }
}

// Super class.
class Person {
  void sayComment() {
    System.out.println("I am Person.");
  }
}

// Sub class.
class Child extends Person {

  @Override
  void sayComment() {
    System.out.println("I am Child.");
  }
}
```

### 多態性（ポリモーフィズム）

オーバーロードやオーバーライド、インタフェース（後述）によって、用途によって振る舞いを変えることができること。

### 抽象クラス

__親クラスの用途のみを考えたクラス__。したがって、直接インスタンス化することはできない。

```java
class sandbox {
  public static void main(String[] args) {
    // Compile err.
    // Person prson = new Person();

    Child chld = new Child();
    chld.sayCommentByPerson();
    chld.sayCommentByChild();
  }
}

abstract class Person {
  void sayCommentByPerson() {
    System.out.println("I am Person.");
  }
}

class Child extends Person {
  void sayCommentByChild() {
    System.out.println("I am Child.");
  }
}
```

実行結果

```
I am Person.
I am Child.
```

### インタフェース

__抽象クラスをさらに抽象化したもの__。インタフェースではメソッドの宣言はできるが、処理は原則書かない。__普通に__処理を書こうとするとコンパイルエラーが起きる。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class();
    cls.sayComment();
  }
}

class Class implements Interface {
  public void sayComment() {
    System.out.println("I am Class.");
  }
}

interface Interface {
  void sayComment();
}
```

また、`interface`内のメソッドは`public`として扱われるため、`Class`で`interface`の`sayComment()`を使うときは、`public`を付けなければならない。また、`interface`内のメンバは`public static final`として扱われる。

#### `interface`内で処理を記述するとき

`default`修飾子をつける。

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class();
    cls.sayComment();
  }
}

class Class implements Interface {

}

interface Interface {
  default void sayComment() {
    System.out.println("I am Interface.");
  }
}
```

実行結果

```
I am Interface.
```

#### クラスは複数の`interface`を取り込むことができる

```java
class sandbox {
  public static void main(String[] args) {
    Class cls = new Class();
    cls.sayComment1();
    cls.sayComment2();
  }
}

class Class implements Interface1, Interface2 {

}

interface Interface1 {
  default void sayComment1() {
    System.out.println("I am Interface1.");
  }
}

interface Interface2 {
  default void sayComment2() {
    System.out.println("I am Interface2.");
  }
}
```

実行結果

```
I am Interface1.
I am Interface2.
```