🐕

Java言語におけるstatic修飾子についての個人的まとめ

2022/09/29に公開

staticメンバについての認識が甘かったのでまとめてみる。以下のコードについて見ていく。知り合いの宿題。

サンプルコード

main.java
package homework;
import java.util.Scanner;
public class main {//mainクラス

	public static void main(String[] args) {//main関数とその処理↓
		new main().hw01();// ①自クラスmain()のhw01メソッドを実体にして(newして)起動
  }
	public void hw01() {//メソッド
		Scanner s = new Scanner(System.in);
		int a = s.nextInt();
		int b = s.nextInt();
		int c = s.nextInt();
		checkTriangle(a, b, c);//②このメソッドが呼ばれる
	}

	private int checkTriangle(int a, int b, int c) {//③三角形の計算メソッド、今は重要ではない
		assert a>0 && b>0 && c>0: "Impossible";
		//if(a!=0 && b!=0 && c!=0) {
			if((a<b+c) && (b<a+c) && (c<a+b)) {
				if(a==b && b==c) {
					System.out.println("���O�p�`");
				}else if(a==b || a==c || b==c) {
					System.out.println("�����O�p�`");
				}else {
					System.out.println("�O�p�`");
				}
			}
		return 0;
	}
}

staticメンバとインスタンスメンバの違い

(メンバとは、クラスのフィールド変数とメソッド(関数)のことを指す)

  • staticメンバ:クラス名.メソッド名で実行できる。
    -> 元々は、実態としてコンパイル前にメモリ上に存在している
  • インスタンスメンバ:インスタンス名.メソッド名で実行できる。
    -> 元々は、実態ではなく設計図(クラス)のままで、インスタンス化するまでメモリには存在しないで、main関数実行中にnewでコピーして作成(インスタンス化)する

要は作成されるタイミングの違いと言うことができ、クラス=非実体、インスタンス=実体の違いという感じ。

これを踏まえて以下考える


hw01()メソッドを直接呼んだら良くない??って言われて挙動不審になった僕

A:「こうしたらエラーなのなんでなん??」

main.java
public class main {//mainクラス

	public static void main(String[] args) {//main関数とその処理↓
		Scanner s = new Scanner(System.in);
		int a = s.nextInt();
		int b = s.nextInt();
		int c = s.nextInt();
		checkTriangle(a, b, c);//まずい
	}
  private int checkTriangle(int a, int b, int c) {
    //以下割愛
  }
}

私:mainメソッド内にsっていうオブジェクト用意して、checkTriangleメソッドして起動、、、って感じで一見よくわからなかった。「ええんちゃう?」て。

このコード(staticメンバとインスタンスメンバの混合クラス)の問題点はなんでしょう?

答えは

  • staticメソッド内で呼び出せるのはstaticなメンバかインスタンスメソッドのみ、ということ

簡単にいうと、

  • 「すでに実体であるmain関数にまだ実体になっていないメソッドcheckTriangle()を置けないよね」ってこと

この問題を解決する方法を考えてみた。

  1. checkTriangle()メソッドにstaticをつける
  2. main()関数のstaticを外す
  3. checkTriangle()メソッドをインスタンス化してmain関数内で呼び出す

もちろん 3. checkTriangle()メソッドをインスタンス化してmain関数内で呼び出す

が正解。

①:staticメソッドは継承したりできない。インスタンス化もできないので、「再利用したり使い回したり」ができない。後々オーバーライドしたり状態が変わったりする可能性があるならstaticメソッドにしてはいけないのである。
(むやみに車を作ってはいけないよね、後で車カスタマイズするときに困るよねw)

②:main()関数はいつでもランする時に呼ばれる関数(原始関数)なのでstaticにするべき。
(車に常に必要な部品は先に作っておこうぜ!)
-> Javaでは原則main()メソッドはstaticで宣言する

③:staticメソッド内では必ず「インスタンスメソッド」で関数を実行(=「すでに実態になったメソッド」を実行)しないといけない。(存在しているはずのstaticメソッド内にまだ設計書段階の処理は置けないよ、実態として確定させてよお!)

重要点

  • メモリに前もって実態を作っておくのが「staticメソッド」
  • newでコピーしてやっと実態になるのが「インスタンスメソッド」

よって

「staticメソッド内では「インスタンスメソッド」じゃないと実行できない」 のである。

最後に

エラー文としては、「Cannot make reference ... to the main()method」的なエラー文が出るはず。
「新わかりやすいJavaオブジェクト指向徹底解説」の3.2「メンバの仕組み」を参考にしました、ぜひ一読ください。


GitHubで編集を提案

Discussion