Javaの「メソッド」とは、「一連の処理をひとつにまとめたもの」を指します。しかし「メソッド」というと難しい感じがして、下記のような悩みを抱えている人もいるのではないでしょうか。
- そもそもメソッドの意味がわからない
- メソッドの使い方がよく理解できない
- メソッドの応用的な活用法を知りたい
Javaのメソッドについて詳しく理解しておくと、さまざまな場面で役立ちます。本記事ではJavaのメソッドの概要や使い方、実戦に役立つ応用テクニックなどについてサンプルプログラム付きで解説します。
目次
Javaの「メソッド」とは

まずは、Javaの「メソッド」の基本的な知識について、下記2つの観点から確認しておきましょう。
- 一連の処理や機能をまとめたもの
- コードの可読性と再利用性の向上などのメリットがある
一連の処理や機能をまとめたもの
そもそもJavaの「メソッド」とは、プログラムの一連の処理や機能をひとつにまとめたものです。「メンバ関数」や「サブルーチン」などの用語もメソッドと同義で、ほかのプログラミング言語では「関数」とも呼ばれる場合もあります。ひとつの機能を実現するための一連の処理や、反復する処理などをまとめたものがメソッドです。
Javaのメソッドには、「特定のクラスやオブジェクトに所属する」という性質があり、プログラムでほかのメソッドから呼び出して使います。言い換えれば、Javaのプログラムは「メソッド呼び出し」の繰り返しによって、成り立っているということです。私たちがいつもコードを書いている「mainメソッド」も、その名のとおりメソッドのひとつなのです。
メソッドのイメージをつかむために、電卓プログラムを作る場合のソースコードの流れを考えてみましょう。おおむね下記のような流れになるのではないでしょうか。
- ユーザーが計算式を入力する
- ユーザーの入力を分析する
- データを基にして計算する
- 計算した結果を画面に表示する
上記はあくまで一例ですが、これらをmainメソッドにベタ書きするのではなく、4つのステップごとに処理を分けるのがメソッドの役目です。その結果、mainメソッドで上記4つの機能ごとのメソッドを呼び出し、プログラムを進めるという流れになります。こうすることにより、さまざまなメリットが得られるのです。
コードの可読性と再利用性の向上などのメリットがある
Javaでメソッドを意識的に活用するようにすると、ソースコードの可読性と再利用性が大幅に高まります。たとえば、下記のような流れのプログラムを考えてみましょう。
- ファイルからデータを読み込む
- 読み込んだデータを解析する
- データ内容に応じた処理を行う
- 不正なデータがあれば対処する
- 「1」へ戻って次のファイルを処理する
上記のようなプログラムを、すべてmainメソッド内に書くと、どのようになるでしょうか。ソースコードが非常に長くなり、読みづらくなるはずです。ソースコードの読みやすさを「可読性」と呼びます。プログラムにおいては、可読性が低いとバグが生じやすくなります。どこにどんなコードが書いてあるか分かりづらく、問題を特定しづらいからです。
一方、ステップ「1」から「5」をメソッドに分割して記載すると、処理内容や機能ごとにまとめることができるため、ソースコードの可読性が大幅に高まります。さらに、作成したメソッドをほかのプログラムに再利用することも可能です。たとえば、ファイルからデータを読み込むメソッドは、ファイルを使用するほかのプログラムにも使えます。
そもそもJavaは「オブジェクト指向」のプログラミング言語。処理内容や機能ごとにメソッドを作るのは、まさにJavaのコンセプトそのものです。このように、よく使う処理・繰り返し行う処理をメソッドとして分離しておくと、コードのスリム化と効率化が図れるのです。
Javaのメソッドを定義する方法

Javaのメソッドは下記の形式で定義します。
アクセス修飾子 戻り値の型 メソッド名(引数型 引数名) {
メソッドの処理; return式; } |
いくつか難しい用語が出てきましたが、それぞれ下記のような意味があります。
アクセス修飾子 | メソッドがどこからアクセス可能かを示す
(public・protected・privateなど) |
戻り値の型 | 関数が値を返す場合は、その型名を記載する
戻り値がない場合は空欄にする |
メソッド名 | メソッドに付ける名称
(クラス内のほかのメソッドとの重複は不可) |
引数型 | 関数が引数を受ける場合は、その型名を記載する
引数がない場合は空欄にする |
引数名 | 関数に引数がある場合は引数名を記載する |
メソッドの処理 | メソッド内で実際に実行する処理を記載する |
return式 | 関数が値を返す場合は、最後にreturn文で値を返す |
なおアクセス修飾子は、クラスのメンバ変数と同じです。publicはすべてのクラスからアクセス可能、protectedは現在のクラスとサブクラス内からのみ可能、privateは現在のクラスからしかアクセスできません。
メソッドは複数の引数を持つことができます。詳細は後述しますが、メソッドは呼び出し元で指定し、受けた引数は関数内で使用できます。一方で戻り値は、メソッドから呼び出し元へ送り返す値です。つまりメソッドを活用することで、メソッド同士で値のやり取りができるということです。上記のポイントを踏まえて、下記のメソッドを確認してみましょう。
public int sample(int numA, int numB) {
return numA + numB; } |
上記のメソッドは、すべてのクラスからアクセス可能で、int型の値を返す「sample」というメソッドです。引数はint型の「numA」と「numB」の2つで、2つの値を足した値を返します。簡単なメソッドを複数作成して、メソッドに慣れていきましょう。
Javaのメソッドの呼び出し方法

Javaのメソッドの呼び出し方は、戻り値と引数の有無によって変わります。メソッドの呼び出し方には、下記4種類のパターンがあります。
// 引数なし・戻り値なしの場合
メソッド名(); // 引数なし・戻り値ありの場合 戻り値を格納する変数名 = メソッド名() // 引数あり・戻り値なしの場合 メソッド名(引数); // 引数あり・戻り値ありの場合 戻り値を格納する変数名 = メソッド名(引数) |
上記のように、メソッドが戻り値を返す場合は、格納用の変数を用意しておきましょう。さらに、その変数でメソッドの戻り値を受ける必要があります。引数については、引数がないメソッドの場合は「()」だけ、引数がある場合は「()」の中に引き渡したい引数を並べましょう。メソッドの実際の呼び出し型については、後ほど詳しく解説します。
Javaのメソッドの基本的な使い方

Javaのメソッドの呼び出し方・使い方は、大きく分けて「引数の引き渡し」と「戻り値の受け取り」の2つに分けられます。本章では、下記2つのステップに分けて、Javaのメソッドの使い方を解説します。
- メソッドの引数に値を引き渡す
- メソッドの戻り値を受け取る
メソッドの引数に値を引き渡す
Javaのメソッドに引数を引き渡す場合、下記のようにメソッド名のあとの「カッコ」の中に、渡したい引数名を書きます。実際にmainメソッド内で「test」メソッドを呼び出す手順は下記のとおりです。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // 2つのint型変数を用意する int a = 1; int b = 2;
// 「sample」メソッドを呼び出す(引数に変数を指定) sample(a, b);
// 「sample」メソッドを呼び出す(引数に直接値を指定) sample(100, 200); }
public static void sample(int numA, int numB) { System.out.println(numA + numB); } } |
//実行結果 |
3
300 |
上記のプログラムでは、「sample」メソッドの中で2つの引数「numA」と「numB」を足し、その結果を表示しています。今回のプログラムのように、引数が複数ある場合は「カッコ」の中で「コンマ(,)」で区切って引数を指定します。なお、引数には変数名を指定しても構いませんし、直接値を指定することも可能です。
メソッドの戻り値を受け取る
Javaのメソッドが戻り値を返す場合は、下記のようにメソッド呼び出しの左側に、「=」を挟んで変数で戻り値を受けます。実際にmainメソッド内で「test」メソッドを呼び出す手順は下記のとおりです。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // 戻り値を格納する変数を用意する int result;
// 2つのint型変数を用意する int a = 1; int b = 2;
// 「sample」メソッドを呼び出す result = sample(a, b);
// 受け取った戻り値に格納された値を表示する System.out.println(result);
// 「sample」メソッドを呼び出し、戻り値をそのまま表示する System.out.println(sample(100, 200)); }
public static int sample(int numA, int numB) { // 2つの変数を足して戻り値として返す return numA + numB; } } |
//実行結果 |
3
300 |
重要なポイントは、メソッドが返した値を変数で受け取る必要があることです。変数に格納するのではなく、上記プログラムの2つ目の呼び出しのように、そのまま別のメソッドに引数として渡すこともできます。ただし、戻り値を変数に格納しなければ、その値を別のところで使えないので注意が必要です。
Javaのメソッドは2種類

Javaのメソッドには、大きく分けて2種類のものがあります。メソッドの種類によって、呼び出せる場所や振る舞い、ほかのクラスからの呼び出し方などが変わるため、適材適所の使い分けが重要です。本章では、下記2つのJavaメソッドの種類について解説します。
- インスタンスメソッド
- クラスメソッド
インスタンスメソッド
Javaの「インスタンスメソッド」は、クラスのインスタンスに紐づいたクラスです。インスタンスとは「実体」、つまりプログラム内で実際に使える「変数」のこと。クラスという「設計図」を基にして作られるのがインスタンスです。
インスタンスメソッドは、このインスタンスに紐づいた固有のメソッドです。インスタンスメソッドにアクセスするためには、必ずインスタンスを介して呼び出す必要があります。インスタンスメソッドの使い方や特徴を、下記のサンプルプログラムで確認しましょう。
//サンプルプログラム |
class Sample {
// Sampleクラスのインスタンスに紐づいたメソッド public void instanceMethod() { System.out.println(“Sampleクラスのインスタンスメソッド呼び出し”); } } public class Test {
public static void main(String[] args) { // Sampleクラスのインスタンスを生成する Sample instance = new Sample();
// インスタンスから「instanceMethod」を呼び出す instance.instanceMethod();
// Sampleクラスの「instanceMethod」はインスタンスと紐づいているため、 // 下記のような「static参照」はできないことに要注意! // (常にインスタンスを介して参照する必要があります) //Sample.instanceMethod(); } } |
//実行結果 |
Sampleクラスのインスタンスメソッド呼び出し |
いつもの「Test」クラスの上に、新しく「Sample」というクラスを作成しました。その中には「instanceMethod」というインスタンスメソッドがあります。インスタンスメソッドは、「public void instanceMethod()」のように下記の形式で宣言します。
修飾子 戻り値の型 メソッド名 |
詳細は後述しますが、メソッド名の前に「static」を付けなければ、すべてインスタンスメソッドとして扱われます。このインスタンスメソッドは、インスタンス生成後に下記の形式でアクセスすることが可能です。
戻り値を格納する変数 = インスタンス名.インスタンスメソッド(引数); |
今回のサンプルプログラムは、戻り値を返さないため単に「instance.instanceMethod();」と記載しました。これで、instanceというインスタンスに紐づいた、instanceMethodが呼び出されます。
こちらも詳細は後述しますが、「Sample.instanceMethod();」のように書くと、「非staticメソッドinstanceMethod()をstatic参照できません」とエラーが出ます。つまり、インスタンスメソッドは、「インスタンスを生成しなければ使えない」ということです。
クラスメソッド
一方でJavaの「クラスメソッド」は、インスタンスではなくクラスそのものに属するメソッドです。インスタンスに紐づいておらず、インスタンスの影響を受けないため、「Staticメソッド」や「静的メソッド」と呼ばれることもあります。
クラスメソッドは、インスタンスを作成しなくてもアクセスできます。ただし、クラスメソッドはインスタンスに紐づいていないため、インスタンスメソッドにはアクセスできません。まずはサンプルプログラムを確認し、大まかな流れをつかみましょう。
//サンプルプログラム |
class Character {
// キャラクター関連のインスタンス変数 private String name; private int health;
// 現在のキャラクター数を示すクラス変数 private static int count;
// コンストラクタ public Character(String name, int health) { // インスタンス変数を初期化する this.name = name; this.health = health;
// 現在のキャラクター数を増やす count++; }
// キャラクターの情報を表示するインスタンスメソッド public void print() { // そもそも「System.out.printlnメソッド」もクラスメソッド! System.out.println(“キャラクター名:” + name); System.out.println(“体力:” + health); }
// 現在のキャラクター数を表示するクラスメソッド public static void getCount() { System.out.println(“キャラクター数:” + count);
// クラスメソッドはインスタンスを介さずにアクセスするため、 // インスタンスと紐づいたインスタンス変数にはアクセス不可! //System.out.println(“キャラクター名:” + name); //System.out.println(“体力:” + health); } } public class Test {
public static void main(String[] args) { // Characterクラスのインスタンスを複数生成する Character villager = new Character(“村人”, 100); Character soldier = new Character(“兵士”, 500); Character mercenary = new Character(“傭兵”, 1000);
// 現在のキャラクター数を表示する // 「static参照」でクラスメソッドにアクセス Character.getCount(); // 各キャラクター変数から、クラスメソッドにアクセスすることも可能 // ただし、基本的は上記の「static参照」の形式を推奨 villager.getCount(); soldier.getCount(); mercenary.getCount(); } } |
//実行結果 |
キャラクター数:3
キャラクター数:3 キャラクター数:3 キャラクター数:3 |
上記のサンプルプログラムでは、いつもの「Test」クラスの上に、新しく「Character」というクラスを作成しました。これはゲームのキャラクターを管理するためのクラスで、その中にはキャラクター情報の変数と、キャラクター数をカウントするクラス変数(静的変数)があります。インスタンス生成時のコンストラクタで、カウントを増やす仕組みです。
重要なポイントは、キャラクター数のカウント変数と、そのカウントを表示するメソッドの双方に「static」修飾子が付いていることです。クラスメソッドは、「public static void getCount()」のように下記の形式で宣言します。
修飾子 戻り値の型 static メソッド名 |
詳細は後述しますが、メソッド名の前に「static」を付けると、すべてクラスメソッドとして扱われます。このクラスメソッドは、インスタンスを生成しなくても下記の形式でアクセスすることが可能です。
戻り値を格納する変数 = クラス名.クラスメソッド(引数); |
今回のサンプルプログラムは、戻り値を返さないため単に「Character.getCount();」と記載しました。これで、Characterというインスタンスに属する、getCountが呼び出されます。こうしたメソッドの呼び出し方を「static参照」と呼びます。
なお、各インスタンスを介してgetCountにアクセスすることも可能ですが、「クラスメソッドの呼び出し」であることを明確化するため、基本的には上記のstatic参照での呼び出しを推奨します。ところで、こうした書き方には見覚えがないでしょうか。
System.out.println() |
普段からよく使っている、画面上にテキストを表示するためのメソッドです。実はこれもクラスメソッドなので、インスタンスを生成せずにアクセスできます。このように、クラスメソッドはすでに馴染み深いものなのです。
クラスメソッドとインスタンスメソッドの使い分けは、「クラス内のインスタンス変数やインスタンスメソッドを使用する必要があるか」という点を意識すると、わかりやすくなるでしょう。
Javaのメソッドの応用テクニック

Javaのプログラミングを学ぶうえで、メソッドの活用法はぜひとも理解しておく必要があります。とくに各4つの応用テクニックを知っておくと、より効率的で便利なプログラミングができるようになるでしょう。
- メソッドチェーン
- 可変長引数
- オーバーロード
- メソッド名の取得
メソッドチェーン
「メソッドチェーン」とは、メソッドの戻り値で「this」を返すようにして、「.」で続けて連鎖的にメソッドを呼び出せるようにするテクニックです。メソッドチェーンの活用により、処理の流れがつかみやすくなり、ソースコードの可読性と簡潔性を向上します。実際に下記のサンプルプログラムで、メソッドチェーンの使い方を確認しましょう。
//サンプルプログラム |
class Health {
// 健康管理に関するインスタンス変数 private float height; private float weight; private float bodyMassIndex;
// 身長を設定するインスタンスメソッド public Health setHeight(float height) { this.height = height;
// 最後に自身のインスタンス「this」を返すことがポイント! return this; }
// 体重を設定するインスタンスメソッド public Health setWeight(float weight) { this.weight = weight;
// 最後に自身のインスタンス「this」を返すことがポイント! return this; }
// BMI(Body Mass Index)を算出するインスタンスメソッド public Health calculateBMI() { // BIMの計算式は「体重(kg) ÷ (身長(m) × 身長(m))」 bodyMassIndex = weight / ((height / 100) * (height / 100)); // 最後に自身のインスタンス「this」を返すことがポイント! return this; }
// BMIを表示するインスタンスメソッド public void printBMI() { System.out.println(“BMI:” + bodyMassIndex); }
} public class Test {
public static void main(String[] args) { // Healthクラスのインスタンスを生成する Health health = new Health();
// 身長・体重の設定・BMI算出・BMI表示を連鎖的に行う // 「メソッドチェーン」を活用し、「.」で連続して記述する health.setHeight(175).setWeight(70).calculateBMI().printBMI();
// 通常どおり記載すると、下記のようにソースコードが長くなります health.setHeight(175); health.setWeight(70); health.calculateBMI(); health.printBMI(); }
} |
//実行結果 |
BMI:22.857143
BMI:22.857143 |
上記のサンプルプログラムは、ユーザーの健康状態を管理するプログラムの一部です。身長と体重をセットすることにより、BMI(Body Mass Index)を算出することができます。このソースコードのポイントは、Healthクラスの各メソッドの戻り値の型が「Health型」で、戻り値として「this」を返していることです。
thisは「自身のインスタンス」を意味するため、これらの関数は「自分自身を戻り値として返す」ことになります。したがって、メソッド呼び出しの後ろに「.」を付けて、別のメソッドも呼び出せるのです。thisを返すメソッドであれば、すべてこのように繋げることができ、まさにメソッドの連鎖を実現できます。
メソッドチェーンの活用により、ソースコードの大幅な簡潔化が可能です。また、メソッドチェーンを使わないときは、通常どおり単体でメソッドを呼び出せます。戻り値の「this」は、あくまで必要なときに使えばいいので、必要なければ戻り値は無視して構いません。ただし、メソッドチェーンを使いすぎても、プログラムがわかりづらくなるので要注意。
可変長引数
Javaの「可変長引数」は、「個数が未確定」の引数をメソッドに指定するテクニックです。可変長引数の個数は0でも10でも構いません。具体的には、ゼロ個以上の引数を取る可能性がある場合、下記の構文で可変長引数を設定できます。
戻り値の型 メソッド名(引数の型 … 引数の変数名); |
重要なポイントは、「引数の型」と「引数名」の間に「…」とコンマを3つ並べることです。これにより「可変長引数を宣言する」と明示できます。また、通常の固定長引数がある場合は可変長引数の前に書き、可変長引数は最後に記載する必要があります。
int test(String text, float … nums) |
なお、可変長引数の後ろに別の可変長引数を設定することはできません。可変長引数は最後の引数のみに指定できます。実際に可変長引数を使用する手順について、下記のプログラムで確認しておきましょう。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // 可変長引数を取るfunctionAメソッドを呼び出す functionA(“functionA:”, 1, 2, 3);
// 可変長引数の部分は「ゼロ個」でもOK functionA(“functionA:”); // 配列形式の可変長引数を取るfunctionBメソッドを呼び出す functionB(“functionB:”, new int[] {10, 20, 30}, new int[] {100, 200, 300}, new int[] {1000, 2000, 3000} ); }
public static void functionA(String text, int … nums) { // テキストを表示する System.out.println(text);
// 可変長引数の中身は「拡張for文」でのアクセスがおすすめ! for(int num : nums) { System.out.println(num); }
// 可変長引数には通常のfor文でもアクセスできる for(int i = 0; i < nums.length; i++) { // 実は可変長引数の実体は「配列」! System.out.println(nums[i]); } }
public static void functionB(String text, int[] … nums) { // テキストを表示する System.out.println(text);
// 可変長引数の中身は「拡張for文」でのアクセスがおすすめ! for(int[] first : nums) { for(int second : first) { System.out.print(second + ” “); }
System.out.println(); }
// 可変長引数には通常のfor文でもアクセスできる for(int i = 0; i < nums.length; i++) { for(int j = 0; j < nums[i].length; j++) { // 実は可変長引数の実体は「配列」! System.out.print(nums[i][j] + ” “); } System.out.println(); } } } |
//実行結果 |
functionA:
1 2 3 1 2 3 functionB: 10 20 30 100 200 300 1000 2000 3000 10 20 30 100 200 300 1000 2000 3000 |
上記のサンプルプログラムでは、可変長引数を取る2つのメソッドを作成しました。重要なポイントは、メソッド内で可変長引数を扱うときのアクセス方法です。実は、可変長引数は「配列」として扱われるので、サンプルプログラムのように配列と同じ方法で操作できます。具体的には、配列の添え字「[]」でインデックスを指定するだけです。
可変長引数は、プログラム作成時に引数の個数がわからない場合や、拡張性を持たせたいときに便利です。通常の固定長引数を使うと、引数の個数分だけ変数を書く必要があり、ソースコードが長くなってしまいます。可変長引数をメソッドに使うと、ソースコードの可読性や拡張性が高まります。
オーバーロード
Javaの「オーバーロード」は、同じ名前のメソッドを複数作成し、引数の型によって使い分けるテクニックです。オーバーロードを使うと、わざわざメソッド名を別のものにしなくても、プログラマーが引数の型だけを変えて使えるので便利です。実際にサンプルプログラムで、メソッドをオーバーロードする方法を確認していきましょう。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // String型引数のprintメソッドを呼び出す print(“りんご”); // int型引数のprintメソッドを呼び出す print(10); // float型引数のprintメソッドを呼び出す print(3.0); // boolean型引数のprintメソッドを呼び出す print(true);
// すべての引数を取るprintメソッドを呼び出す print(“バナナ”, 50, 10.0, false); }
public static void print(String name) { // テキストを表示する System.out.println(“商品名:” + name); }
public static void print(int count) { // テキストを表示する System.out.println(“販売個数:” + count); }
public static void print(double weight) { // テキストを表示する System.out.println(“重量:” + weight); }
public static void print(boolean flag) { // テキストを表示する System.out.println(“販売可能:” + flag); }
public static void print(String name, int count, double weight, boolean flag ) { // テキストを表示する System.out.println(“商品名:” + name);
// テキストを表示する System.out.println(“販売個数:” + count);
// テキストを表示する System.out.println(“重量:” + weight);
// テキストを表示する System.out.println(“販売可能:” + flag); } } |
//実行結果 |
商品名:りんご
販売個数:10 重量:3.0 販売可能:true 商品名:バナナ 販売個数:50 重量:10.0 販売可能:false |
上記のサンプルプログラムでは、同じ「print」という名称のメソッドが5つあり、それぞれ引数の型と個数が異なっています。これらのメソッドを区別する方法は、まさに引数の型と個数です。呼び出しの引数に、どの型の値を指定するかによって、自動的に呼び出されるメソッドが変わります。
たとえば、printメソッドに「10」を代入する場合はint型引数、「3.0」を代入するとfloat型引数のものが自動的に選ばれます。この型名の判別は厳格に行われるため、float型引数のメソッドにdouble型を代入しようとすると、エラーが表示されます。引数の型によって処理が分岐するので、if文を使わなくても臨機応変な処理が可能となります。
このようにオーバーロードを活用すると、「同じような処理内容を型名によって分岐している」ことがわかりやすいことがメリットです。プログラムに変更が生じたときも、メソッド呼び出しの引数だけ変えればいいので、プログラミングの効率化も図れます。
メソッド名の取得
Javaでプログラミングをしていると、「現在のメソッド名を取得したい」ということがあるかもしれません。たとえば、デバッグ用に現在進行中のメソッド名を、画面上に表示するなどです。
そのようなときは、「実行中のクラスから取得する方法」と「メソッド呼び出しのスタックトレースから取得する方法」の2つで、クラス名を取得することができます。少し複雑な部分もありますが、下記のサンプルプログラムで確認しましょう。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // テスト用メソッドを呼び出す test(); }
public static void test() { // メソッド名取得用の変数 String methodName;
// プログラム実行中のクラスからメソッド名を取得する methodName = new Object(){}.getClass().getEnclosingMethod().getName(); System.out.println(“実行中のクラスから取得したメソッド名 : ” + methodName);
// メソッド呼び出しのスタックトレースからメソッド名を取得する methodName = Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println(“スタックトレースから取得したメソッド名 : ” + methodName); } } |
//実行結果 |
実行中のクラスから取得したメソッド名 : test
スタックトレースから取得したメソッド名 : test |
上記のサンプルプログラムでは、2つの方法で現在のメソッド名を取得し、その結果として「test」が表示されています。いずれもメソッドチェーンを使用していますが、ここではスタックトレースに注目してみましょう。
「スタックトレース」とは、メソッド呼び出しの過程を記録したものです。まず「Thread.currentThread()」で現在のスレッド、つまりプログラムを実行している場所を取得します。それから「getStackTrace()」でスタックトレースを取得します。
Javaでメソッドが呼び出されるとき、メソッドが順番に上に積み上げられていきます。メソッドが終了すると、積み上げたメソッドが取り除かれ、その次のメソッドが進行するのです。こうした構造が「スタック」と呼ばれ、スタックトレースを確認するとメソッド呼び出しの順番がわかります。
getStackTrace()の戻り値は配列型で、その最初(0番目)の要素は常に「getStackTrace」で、その次(1番目)に現在のメソッドが格納されることが特徴です。わかりにくい部分が多いですが、ひとまず上記のコードを丸暗記しておくといいでしょう。
Javaのメソッドの引数に「参照渡し」はなく「値渡し」のみ

Javaでよくある誤解のひとつが、「Javaには『参照渡し』がある」というものです。参照渡しとは、「変数のアドレス」をメソッドに引き渡すことです。変数のアドレスとは、いわば変数がメモリ上で格納されている場所を指します。
参照渡しはC言語やC++では「ポインタ渡し」とも呼ばれ、C#やVB.NETなどでも参照渡しを使えます。しかしJavaには参照渡しがなく、「値渡し」しかありません。値渡しとは、変数の値をコピーして、メソッドに引き渡すことです。Javaの値渡しの振る舞いについて、下記のサンプルプログラムで確認してみましょう。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // int型変数 int num = 0;
// numの値を表示する System.out.println(“最初の値:” + num);
// testメソッドに値を引き渡す test(num); // numの値を表示する System.out.println(“メソッド引き渡し後の値:” + num); }
public static void test(int num) { // メソッド内でnumの値を書き換える num = 100; // numの値を表示する System.out.println(“メソッド内の値:” + num); } } |
//実行結果 |
最初の値:0
メソッド内の値:100 メソッド引き渡し後の値:0 |
上記のサンプルプログラムでは、mainメソッドからtestメソッドに引き渡した「num」を、testメソッド内で変更しています。しかし、最終的にmainメソッドのnumは変更されていません。これは、testメソッドの引数には「コピー」が引き渡されるからです。こうした振る舞いは、「基本データ型(プリミティブ型)」の下記8つの型の変数に当てはまります。
- boolean
- byte
- char
- short
- int
- long
- float
- double
参照型変数をメソッドに引き渡すと中身の書き換えが可能
一方で、上記8つ以外のすべてのデータ型は「参照型」と呼ばれ、まったく異なる振る舞いをします。たとえば配列やクラスなどは、すべて参照型に含まれます。詳細を解説すると非常に長く・複雑になるので割愛しますが、参照型変数は「実体」ではなく「アドレス」が格納されていることが理由です。下記のサンプルプログラムで確認してみましょう。
//サンプルプログラム |
import java.util.Arrays; // Arraysの機能を使用する
public class Test {
public static void main(String[] args) { // int型の変数 int num = 0;
// int型の配列変数 int[] nums = new int[] {1, 2, 3};
// 変数と配列の中身を表示する System.out.println(“変数の中身:” + num); // 「実体」が表示される System.out.println(“配列変数の中身:” + nums); // 「アドレス」が表示される
// 配列の実体の中身を表示する System.out.println(“配列変数の値:” + Arrays.toString(nums)); // testメソッドに値を引き渡す test(nums); // numの値を表示する System.out.println(“メソッド引き渡し後の値:” + Arrays.toString(nums)); }
public static void test(int[] nums) { // メソッド内でnumの値を書き換える nums[0] = 100; nums[1] = 200; nums[2] = 300; // numの値を表示する System.out.println(“メソッド内の値:” + Arrays.toString(nums)); } } |
//実行結果 |
変数の中身:0
配列変数の中身:[I@5ca881b5 配列変数の値:[1, 2, 3] メソッド内の値:[100, 200, 300] メソッド引き渡し後の値:[100, 200, 300] |
ひとつずつ検証していきましょう。printlnメソッドで配列の中身を表示できないのは、変数にアドレスが格納されているためです。画面上に表示される意味不明な文字列はアドレスなのです。
さらにtestメソッドにnums配列を引き渡し、メソッド内部で値を書き換えると、なんと元のmainメソッドのnums配列の中身も変わっています。これは、基本データ型のように「コピー」が渡されるのではなく、「アドレス」が渡されていることが理由です。
これは書類に置き換えてみると少しわかりやすくなります。基本データ型では、書類のコピーがメソッドに渡されます。メソッド内でいくらコピーの値を書き換えても、原本は変更できませんよね。
一方で配列やクラスなど参照型変数の場合は、「原本がある場所が書かれた紙」が渡されます。場所さえわかれば、原本がある場所に行って書類を書き換えることができます。そもそもnums[0]のような記述は、「実体(原本)」を見る・書き換えるためのものなのです。
ただし「参照型引数」そのものの値は書き換えられない
これまでの内容を踏まえると、参照型変数を引き渡すと「参照渡し」になりそうな気がしますよね。しかし実際には、参照渡しではなく「参照の値渡し」となります。ここを理解していないと思わぬバグの原因になるので、下記のサンプルプログラムで振る舞いを確認しておきましょう。
//サンプルプログラム |
import java.util.Arrays; // Arraysの機能を使用する
public class Test {
public static void main(String[] args) { // int型の配列変数 int[] nums = new int[] {1, 2, 3};
// 配列の実体の中身を表示する System.out.println(“配列変数の値:” + Arrays.toString(nums)); // 配列のアドレスを表示する System.out.println(“配列変数のアドレス:” + nums); // testメソッドに値を引き渡す test(nums); // numの値を表示する System.out.println(“メソッド引き渡し後の値:” + Arrays.toString(nums)); // 配列のアドレスを表示する System.out.println(“メソッド引き渡し後のアドレス:” + nums); }
public static void test(int[] nums) { // 新たな配列変数を作成して、numsに上書きする nums = new int[] {100, 200, 300}; // numの値を表示する System.out.println(“メソッド内の値:” + Arrays.toString(nums));
// 配列のアドレスを表示する System.out.println(“新しいnumsのアドレス:” + nums); } } |
//実行結果 |
配列変数の値:[1, 2, 3]
配列変数のアドレス:[I@5ca881b5 メソッド内の値:[100, 200, 300] 新しいnumsのアドレス:[I@24d46ca6 メソッド引き渡し後の値:[1, 2, 3] メソッド引き渡し後のアドレス:[I@5ca881b5 |
上記のプログラムでは、testメソッド内で新たな配列変数を生成し、それを引数のnumsに代入しています。これは厳密にいうと、nums変数に新しい配列の「アドレス」を格納するということです。本当にnumsが参照渡しになっているのであれば、mainメソッドのnums配列の中身も変わっているはずです。
ところが、実際にはnumsの中身は変わっていません。アドレスを確認しても、mainメソッドのnumsは同じままですよね。これは、やはりnums変数は「値渡し」でしかなく、メソッド内でnumsそのものを書き換えても、それは原本ではなくコピーの書き換えに過ぎないということであり、これが「参照の値渡し」と呼ばれる理由です。
しかし、アドレスをたどって配列の実体にアクセスすれば、間接的に実体を書き換えることは可能です。これは配列以外のクラスでも同じことで、メソッドの参照型引数を「[]」や「.」などの記号でたどると、その実体を書き換えられるということです。
基本データ型変数を配列でラップすると中身の書き換えが可能
Javaの参照型変数のメソッド内での振る舞いについて確認しました。以上のことから、もし基本データ型変数をメソッド内で書き換えたい場合は、下記のように配列でラップすればよいことがわかります。
//サンプルプログラム |
public class Test {
public static void main(String[] args) { // int型変数 int value = 100;
// int型の配列変数 int[] array = new int[1];
// 変数の値を表示する System.out.println(“最初の値:” + value);
// 配列に変数の値を代入する array[0] = value;
// testメソッドに値を引き渡す test(array); // 変数に配列の値を代入する value = array[0]; // numの値を表示する System.out.println(“メソッド引き渡し後の値:” + value); }
public static void test(int[] nums) { // 配列の中身を書き換える nums[0] = -1; } } |
//実行結果 |
最初の値:100
メソッド引き渡し後の値:-1 |
上記のように、変数と配列で値のやり取りを行えば、間接的に呼び出し元の値を変更することは可能です。しかしプログラムがわかりづらくなるため、引数を介さずメンバ変数にするか、戻り値で変更後の値を受けるようにするのもひとつの方法です。
Javaのメソッドを活用してプログラムを効率的に書こう

Javaのメソッドは、一連の処理や機能をまとめ、ソースコードの可読性やメンテナンス性を高めるために便利です。戻り値や引数をうまく活用すると、プログラムの大幅な効率化も可能です。ただしJavaの引数には値渡ししかないことや、参照型変数を引き渡すとメソッド内で値の変更が可能なことなど、データ型による振る舞いの違いに注意してください。