【Java入門】クラスについて（クラスの定義、インスタンス化、コンストラクタ）

#目的

Java言語を含めたプログラミングの学習を始めたばかりの方、既学習者の方は復習用に、
今回は**クラス**について学ぶために書いています。

[【Java入門目次】](https://qiita.com/morioheisei/items/6c7fc063c26e63d890ac)
・[変数と型](https://qiita.com/morioheisei/items/3d27e82d6cd88068dded)
・[型変換](https://qiita.com/morioheisei/items/28ab5fd69570e01cd317) 
・[変数のスコープ](https://qiita.com/morioheisei/items/c56ab32b68ce92d32206)
・[文字列の操作](https://qiita.com/morioheisei/items/e58adadd8535971b69be)
・[配列の操作](https://qiita.com/morioheisei/items/b6acbb1b0c07b40e7f56)
・[演算子](https://qiita.com/morioheisei/items/63088c61e8234dc1f7f5)
・[条件分岐](https://qiita.com/morioheisei/items/194cdc73a29bddade0a4)
・[繰り返し処理](https://qiita.com/morioheisei/items/e686e33b60c6a60e87f0)
・クラスについて ←今ここ
・抽象クラス（準備中）
・インターフェース（準備中）
・カプセル化（準備中）
・モジュールについて（準備中）
・[例外処理について](https://qiita.com/morioheisei/items/d25d2b67e7530c1aab9d)
・[ラムダ式について](https://qiita.com/morioheisei/items/2bfcc3d8d8440b00e6a9)
・[Stream APIについて](https://qiita.com/morioheisei/items/3a7be38b4d3ef712ccb2)

#クラスとは

- `属性(変数)` : そのクラスを元に生成された実体のデータに当たるもの。
 - メンバ変数と呼ばれ、**インスタンス変数**と**static変数(クラス変数)**の2種類があります。


- `操作(メソッド)` : そのクラスを元に生成された実体の属性を処理するもの。
 - メンバメソッドと呼ばれ、**インスタンスメソッド**と**staticメソッド(クラスメソッド)**の2種類があります。


上記をまとめた**設計図(雛形)**の様なものです。

**クラスの定義方法**

```text:構文
(修飾子) class クラス名 {
  // メンバ変数
  // メンバメソッド
}
```

**変数の宣言方法**

```java:構文と例
// (修飾子) データ型 変数名
String name;
private int age = 5; // 初期化をする事も可能
```

**メソッドの定義方法**

```text:構文
// (修飾子) 戻り値の型 メソッド名(引数) { 処理 };
```

戻り値の型には、メソッドを呼び出し値を返す場合、その返す結果のデータ型を記述します。
(int型同士の計算結果を返したいならint、String型の文字列結合を行って返したいならString)

戻り値を何も返さなくて良い場合は、**void**と記述します。

何かしら値を返す場合(void以外の時)、処理の最後に`return 戻す値(データ型は戻り値の型)`としなければいけません。



```java:メソッドの記述例

// 引数に何も受け取らず、戻り値としてString型を返す
public String getName() {
  return // String型の値
}

// 引数にString型の値を受け取り、戻り値は何も返さない
public void setName(String name) { }

// 引数にint型の値を受け取り、戻り値はint型の配列を返す
private int[] getNumbers(int i) {
  return // int型の配列
}
```

修飾子についての詳しい説明は、別記事にてまとめる予定ですので本記事では割愛します。


では、クラスを作成します。

```java:クラスの例
public class Animal {

  String name; // インスタンス変数
  static int count; // static変数(クラス変数)

  // コンストラクタの定義(コンストラクタについては後述)
  Animal() {
    count++; // countをインクリメント
  }

  // インスタンスメソッド(nameを取得するため)
  public String getName() {
    return name;
  }
  // インスタンスメソッド(nameに値を代入するため)
  public void setName(String name) {
    this.name = name;
  }

  // staticメソッド(countを取得するため)
  public static int getCount() {
    return count;
  }

}
```

これでAnimalクラスの定義は完了です。

#オブジェクトとは

`クラス(設計図)を元に作成された実体の事です。`設計図だけではプログラムを動かす事が出来ないので、オブジェクトを作成する必要があります。
クラスからオブジェクトを作成するには、`newキーワードを用います`。これを**インスタンス化**と言います。

```text:構文
データ型 変数名 = new クラス名();
```

先ほどのAnimalクラスを元にインスタンス化してみます。

```java:インスタンス化の例
// Animalクラスを定義
class Animal {
  String name;
  static int count;

  Animal() { count++; }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }

  public static int getCount() {
    return count;
  }
}

// Mainクラスを定義
class Main {
  public static void main(String[] args) {

    // catという変数名でオブジェクトを作成(インスタンス化)
    Animal cat = new Animal();
    cat.setName("きなこ"); // catのnameをセット
    System.out.println(cat.getName()); // catのnameを取得
    System.out.println(Animal.getCount()); // Animalクラスのcountを取得

    // dogという変数名でオブジェクトを作成(インスタンス化)
    Animal dog = new Animal();
    dog.setName("小太郎"); // dogのnameをセット
    System.out.println(dog.getName()); // dogのnameを取得
    System.out.println(Animal.getCount()); // Animalクラスのcountを取得

  }
}
```

```text:実行結果
きなこ
1
小太郎
2
```

Animalクラス(設計図)を元にcat、dog(オブジェクト)を作成しています。
Animalクラスで定義されている各メソッドを呼び出し、name変数への代入や値の取得、static変数(クラス変数)の値の取得が出来ています。

#コンストラクタとは

`新たなオブジェクトを作成(インスタンス化)する時に一番初めに実行される処理の事です。`

コンストラクタの定義方法は以下になります。

**1.クラス内で明示的に定義する**
**2.明示的に定義しなかった場合はコンパイラによって追加される(クラス内に1つもコンストラクタがない時)**。

明示的に定義する方法はメソッドと似ていますが、以下のルールに注意しなければいけません。

- コンストラクタ名はクラス名と同じ
- 戻り値は持たないので戻り値の型宣言もしない
- 引数を受け取る事が出来る

コンストラクタの処理には、**インスタンス化された時に同時に行っておきたい事**を記述します。

```text:構文
(修飾子) コンストラクタ名(引数) {
  // 処理
}
```



コンストラクタの呼び出し方法は以下になります。

```text:コンストラクタの呼び出し方
new コンストラクタ名()
new コンストラクタ名(引数)
```

先ほどのAnimal cat = `new Animal()`;は、コンストラクタを呼び出していたという事になります。
クラス内に定義していなかったので、**コンパイラによって追加されていたのです**。
これを`デフォルトコンストラクタ`と呼びます。(明示的にコンストラクタを定義した場合、デフォルトコンストラクタは作成されなくなる。)




では、コンストラクタを明示的に定義して、インスタンス化時に行ってもらいたい処理を記述してみます。


```java:コンストラクタの例
class Animal {

  String name;

  // コンストラクタを定義
  Animal(String name) {
    this.name = name; // 引数で受け取った値をインスタンス変数に代入している
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}


class Main {
  public static void main(String[] args) {

    Animal cat = new Animal("きなこ"); // コンストラクタを呼び出し、値を渡している
    // cat.setName("きなこ"); ← コンストラクタがnameをセットしてくれるため、不要になった
    System.out.println(cat.getName());


    // Animal dog = new Animal(); // 引数に何も書かないとコンパイルエラーになる(デフォルトコンストラクタがなくなった為)    
    Animal dog = new Animal("小太郎");
    // dog.setName("小太郎"); ← コンストラクタがnameをセットしてくれるため、不要になった
    System.out.println(dog.getName());

  }
}
```

この様に初期化作業など行えるため、先ほどは3行で行っていた処理を2行で行う事が出来ました。

##オーバーロード

初期化はしたくない時は、何も処理をしない用のコンストラクタを定義しましょう。
明示的にコンストラクタを定義したため、引数なしのデフォルトコンストラクタをコンパイル時に用意してくれなくなった為です。


```java:コンストラクタを複数定義する例
class Animal {

  String name;

  // コンストラクタを定義
  Animal(String name) {
    this.name = name;
  }

  // コンストラクタを定義2 ←追加
  Animal() {
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}


class Test {
  public static void main(String[] args) {

    Animal cat = new Animal("きなこ");
    System.out.println(cat.getName());

    // Animal dog = new Animal("小太郎");
    Animal dog = new Animal(); // ←追加 引数に何も書かなくてもエラーにならない
    dog.setName("小太郎"); // ←追加 その代わりに、名前を忘れずにセットする事
    System.out.println(dog.getName());

  }
}
```

この様に`引数の順番やデータ型、数が異なっている`という条件を満たしている場合、
**同じ名前のコンストラクタを複数定義する事が可能です。**

これを**オーバーロード**と呼び、`メソッドも同様に条件を満たしていれば複数定義する事が可能です。`

条件を満たしていない場合は、コンパイルエラーになるので注意しましょう。

```java:メソッドのオーバーロードの例
class Animal {

  String name;

  public String getName() {
    return name;
  }

  // OK!
  public String getName(String str, int num) {
    return name;
  }

  // OK!
  public String getName(int num, String str) {
    return name;
  }

  // NG! オーバーロード出来ずコンパイルエラー
  // public String getName() {
  //   return name;
  // }

}
```



#終わりに

オブジェクト指向において基本となるクラスについて学びました。
基本ですのでしっかり理解を深めておきたいですね。
修飾子や継承やインターフェースとまだまだ学ぶ事は多いと感じました。

#参考サイト

**[クラスの基本](https://www.javadrive.jp/start/about/)**