本記事のポイント
- mainメソッドのクラス内で定義されたインスタンスメソッドは実行できない
- クラスメソッドであればmainメソッドで直接アクセスできる
- 別のクラスでインスタンスメソッドを定義し、mainメソッドでオブジェクトを生成すれば実行可能
はじめに
初めまして、2020年度新卒入社のsyoと申します。
私は、学生の頃は神経科学の研究室に所属しマウス(ネズミ)を使って遺伝子を調べたり、神経活動を計測する実験をしていました。学生の頃はプログラミングをほとんどやっていないので、プログラミングを本格的に勉強するのは弊社に入ってからでした。
なので、初心者の初心者による初心者のためのつまずいた点というものを自分の経験純度100%で紹介したいと思います。研修ではWebアプリケーションやシステムによく用いられるプログラミング言語のJavaを中心に学んでいます!
つまずいたところ
研修ではメソッドからクラスについて学ぶという流れで進んでいきました。クラスの項目に入った際に、インスタンスメソッドとクラスメソッドについて学びました。
mainメソッドが書かれているクラス内のメソッド定義には、staticというキーワードを付けて定義していることに気づきました。
メソッドには、
- クラスメソッド:
staticというキーワードを付けて(静的メンバで)オブジェクトを生成せずにメソッドを直接参照して実行できるメソッド - インスタンスメソッド:
staticをつけず、オブジェクトを生成して実行するメソッド
の2つがあります。
mainメソッドはクラスメソッドとなっていますが、これがどういった意味を持つのかわかりませんでした。
いざ調査!
そこで先輩社員に質問したところ、「それならば一度mainメソッドでstaticを外して試してみよう」というアドバイスをいただきました。
早速実行したところ、次のような結果になりました。
インスタンスメソッドを定義してmainメソッドで実行
1 2 3 4 5 6 7 8 9 10 11 |
package practice; public class practice1 { public static void main(String[] args) { //Keisanメソッドに引数10を入力して実行 System.out.println(keisan(10)); } //インスタンスメソッドであるKeisanメソッドを定義 public int keisan(int num){ return num += 10; } } |
実行してみた結果、次のようなエラーが起きました。
1 2 3 4 |
Exception in thread "main" java.lang.Error: Unresolved compilation problem: 型 practice1 の非 static メソッド keisan(int) を static 参照することはできません at practice.practice1.main(practice1.java:6) |
非staticメソッドをstatic参照することはできません、とはどういうことなのか、、、
調べてみたところ、次のような規則があることがわかりました。
javaにおいてあるクラスで定義したメソッドは、staticをつけてクラスメソッドとした場合のみ、同一クラス内の別メソッド内で実行することができます*1。この規則によって、mainメソッド内で、同一クラス内に定義したインスタンスメソッドを呼び出そうとしても呼び出すことができずエラーとなっていました。
エラーが起きないようにする方法は2つあります。
それは、
- 同じクラス内でクラスメソッドを定義して実行する
- 別のクラスでインスタンスメソッドを定義し、mainメソッド内でそのオブジェクトを生成して実行する
です。
- インスタンスメソッドは、宣言されているクラスがロードされるタイミングで展開されて参照可能となります。したがって、mainメソッドと同クラス内に定義されているクラスメソッドは最初にロードされるため実行可能となります。
- インスタンスメソッドはオブジェクトを生成しなければ使えるようになりません。したがって、オブジェクトを生成する工程が必要となります。ここでの注意点は、別のクラスで定義されたインスタンスメソッドはmainメソッド内でオブジェクト生成すれば実行可能となる点です*2。
以上を踏まえて実行すると、
1.クラスメソッドの方法
1 2 3 4 5 6 7 8 9 10 |
public class practice2 { public static void main(String[] args) { //Keisanメソッドの実行 System.out.println(keisan(10)); } //クラスメソッド定義 public static int keisan(int num){ return num += 10; } } |
実行結果
1 |
20 |
2. 別のクラスで定義したインスタンスメソッドの方法
1 2 3 4 |
public class practice3 { public int keisan(int num){ return num += 10; } |
1 2 3 4 5 6 7 8 9 |
package practice; public class practice4 { public static void main(String[] args) { //別のクラスで定義したKeisanクラスのオブジェクトを生成 practice3 instance = new practice3(); //keisanメソッドの実行 System.out.println(instance.keisan(10)); } } |
実行結果
1 |
20 |
見事に実行ができました!
ちなみに、上記の通りmainメソッド内でメソッドを実行する方法は2通りあります。
保持したデータを元に処理をしたいときにはインスタンスメソッドを使い、データを持たないメソッド処理の時にはクラスメソッドを用いることで使い分けます。
以下に保持したデータを用いて処理をしたいときの例を挙げます。
処理は、3つの値の合計値を1つ, 2つ, 3つごとでのグループの足し算です。
- クラスメソッドの方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Practice5 { public static void main(String[] args) { // クラスメソッドではデータを持てないため、それぞれで変数定義が必要 int number1 = 10; int number2 = 20; int number3 = 30; int number4 = 40; int number5 = 50; int number6 = 60; int number7 = 70; int number8 = 80; int number9 = 90; System.out.println(sumStatic(number1, number2, number3)); System.out.println(sumStatic(number1, number2, number3) + sumStatic(number4, number5, number6)); System.out.println( sumStatic(number1, number2, number3) + sumStatic(number4, number5, number6) + sumStatic(number7, number8, number9)); } public static int sumStatic(int number1, int number2, int number3) { return number1 + number2 + number3; } } |
実行結果
1 2 3 |
60 210 450 |
2. インスタンスメソッドの方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//インスタンスメソッドSideクラスを定義 public class Side { int instanceNumber1; int instanceNumber2; int instanceNumber3; int sumNumber; public Side(int instanceNumber1, int instanceNumber2, int instanceNumber3) { this.instanceNumber1 = instanceNumber1; this.instanceNumber2 = instanceNumber2; this.instanceNumber3 = instanceNumber3; this.sumNumber = instanceNumber1 + instanceNumber2 + instanceNumber3; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import java.util.ArrayList; import java.util.List; public class Practice6 { public static void main(String[] args) { // インスタンスメソッドによって3種のオブジェクトを生成 Side instance1 = new Side(10, 20, 30); Side instance2 = new Side(40, 50, 60); Side instance3 = new Side(70, 80, 90); // オブジェクトなのでリストに格納できる List<Side> sideList = new ArrayList<>(); sideList.add(instance1); sideList.add(instance2); sideList.add(instance3); // 保持したデータを元に計算が可能 int sumInstance = 0; for (int i = 0; i < sideList.size(); i++) { sumInstance += sideList.get(i).sumNumber; System.out.println(sumInstance); } } |
実行結果
1 2 3 |
60 210 450 |
上記の通り、データを保持して計算できるインスタンスメソッドのほうがスッキリとしたコードになり柔軟な処理が可能となります!
結論
mainメソッドはクラスメソッドであるため、同一クラスで定義されたインスタンスメソッドを実行できないことがわかりました。そのため、mainメソッド内でメソッドを実行する方法は、
- 同一クラス内でクラスメソッドを定義して実行する
- 別のクラスでインスタンスメソッドを定義して実行する
となります。
今回つまずきを解消していくにあたり、コードについて疑問等が起きた場合はいったん自分で実行してみて、挙動を確認することが理解の第一歩であるということを強く実感しました。
今後も研修内でつまずいた点を記事に載せていきたいと思っています。ここまでお付き合いいただきありがとうございました!
参考文献
- mainメソッドとクラスの関係 – クラスとは何か – Java入門(参照 2020-04-26)
- staticなメソッドから非staticなメソッドへのアクセスについて(参照 2020-04-26)