【Java Silver対策】インスタンスとメソッドについて学習しよう【例題にも挑戦!】中編

資格学習
ハック
ハック

こんにちは、運営者のハックです。

今回はデイトラJava Silver対策編「第6章の対策」のうち、中編の学習記録を紹介します。

引き続き「インスタンスとメソッド」について学習します

第6章ではインスタンスとメソッドについて学習しますが、中編の今回は主に「メソッドの呼び出しと定義」「可変長引数」「return文」「メソッドのオーバーロード」について解いていきます。

前編はこちら

今回も引き続き解説の参考と例題の引用は【黒本】と呼ばれる「徹底攻略Java SE 11 Silver問題集」から行っていきます。

メソッドの呼び出しと定義

メソッドを呼び出すには、「メソッド名(引数)」を記述しなければいけません。

例えば、Calculatorというクラスに以下のようにメソッドを定義したとします。

public class Calculator {
    // メソッドの定義
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }

    public double divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("Divisor cannot be zero");
        }
        return (double) a / b;
    }
}

呼び出し元のメソッドに値を戻すには、return文を使用します。
次に、Calculatorクラスのインスタンスを生成し、そのインスタンスを使ってメソッドを呼び出します。

public class Main {
    public static void main(String[] args) {
        // Calculatorクラスのインスタンスを生成
        Calculator calculator = new Calculator();

        // メソッドの呼び出し
        int sum = calculator.add(10, 5);           // 10 + 5 = 15
        int difference = calculator.subtract(10, 5); // 10 - 5 = 5
        int product = calculator.multiply(10, 5);    // 10 * 5 = 50
        double quotient = calculator.divide(10, 5);  // 10 / 5 = 2.0

        // 結果の表示
        System.out.println("Sum: " + sum);
        System.out.println("Difference: " + difference);
        System.out.println("Product: " + product);
        System.out.println("Quotient: " + quotient);
    }
}

メソッド呼び出しの書式について、以下のように呼び出されるメソッドがインスタンスのメソッドなのか、staticなメソッドなのかを確認します。

  • 同じインスタンスに定義されているメソッド場合…メソッド名(引数)
  • インスタンスに定義されているメソッドの場合…変数.メソッド名(引数)
  • staticなメソッドの場合…クラス名.メソッド名(引数)

メソッドはクラス内に定義され、インスタンスを通して呼び出されます。メソッドの呼び出しにはメソッド名と必要な引数を指定し、戻り値がある場合はそれを変数に代入して使用します。

また、戻り値については以下のポイントを押さえておきましょう。

  • メソッド宣言で戻り値型の宣言は必須。戻り値に何も戻さない場合には、戻り値型にvoidを指定する。
  • 戻り値型がvoidであるメソッドは値を戻せない。
  • 戻り値型と、実際に戻す値の方は同じでなければならない。
  • 戻り値を戻さない(戻り値型がvoidである)メソッドに対し、戻り値を受け取る変数を宣言して受け取ることはできず、コンパイルエラーが発生する。
  • 何らかの戻り値を戻すメソッドを呼び出しても、その戻り値を受け取る必要はない。戻り値を受け取り、変数に代入しなければ、その戻り値は破棄される。
モナ
モナ

実際に例題を解いて理解を深めましょう。

次のプログラムを確認してください。

1. public class Sample {
2.     private String value;
3.     public void setValue(String value){
4.        this.value = value;
5.     }
6.     public String getValue(){
7.         return this.value;
8.     }
9.  }

このクラス利用する以下のプログラムを、コンパイル、実行したときの結果として、正しいものを選びなさい。(1つ選択)

1. public class Main{
2.    public static void main(String[] args) {
3.        Sample s = new Sample();
4.        String val = s.setValue("hello");
5.        s.getValue();
6.        System.out.println(val);
7.    }      
8.  }             

A. Mainクラスの4行目でコンパイルエラーが発生する。
B. Mainクラスの5行目でコンパイルエラーが発生する。
C. Mainクラスの4行目と5行目でコンパイルエラーが発生する。
D. 何も表示されない。
E. nullが表示される。
F. 実行時に例外がスローされる。

「徹底攻略 Java SE 11 Silver 問題集」より抜粋
ねこ奈
ねこ奈

Mainクラスの4行目でsetValueメソッドを呼び出して、それをvalに代入しようとしているのにゃ。でも、setValueメソッドを見ると戻り値型がvoidになっているのにゃ。そーすると、returnがないため何も受け取れないのに代入しようとしたって意味になるからコンパイルエラーが発生すると思うのにゃ。だから正解はAかCだにゃ。

5行目のs.getValueメソッドの呼び出しは、呼び出しはできているけど何も受け取ってないのにゃ。この場合、さっきの「point」の説明文にあったとおり、破棄されるって認識でいいのにゃ?

モナ
モナ

その認識でOKです!

戻された戻り値を使うか使わないかは、呼び出し元のメソッド側の自由です。なので5行目ではコンパイルエラーは発生しません。

よって正解は選択肢Aです。

可変長引数

ねこ奈
ねこ奈

可変長引数って、JavaSilver対策編第1章の回で問題解説の時にモナが少しだけ説明していた奴なのにゃ!

もなぁ
もなぁ

よく覚えていますね…

第1章の回でも触れたとおり、可変長引数とはその数を自由に変更できる引数のことです。
可変長引数は「sample(int… num)」のようにデータ型の直後にピリオド3つを付けて宣言します。

可変長引数のポイント

1.メソッドの引数リストにおいて、可変長引数は1つだけ使用できます。また、それは引数リストの最後に位置する必要があります。

// 正しい例
public void exampleMethod(String fixedArg, int... varArgs) { }

// 間違った例(コンパイルエラー)
public void wrongExample(int... varArgs, String anotherArg) { }

2.可変長引数はメソッド内部では配列として扱われます。そのため、配列操作と同様にアクセスできます。

public void printNumbers(int... numbers) {
    for (int number : numbers) {
        System.out.println(number);
    }
}

3.可変長引数を持つメソッドは、引数を渡さなくても呼び出すことができます。この場合、空の配列が渡されます。

Calculator calculator = new Calculator();
int result = calculator.sum(); // 結果は0
モナ
モナ

それでは、可変長引数に関する例題を解いてみましょう。

次の中から、メソッドの宣言として正しいものを選びなさい。(1つ選択)

A. void method(void){}
B. void method(int values…){}
C. void method(int… values, String name){}
D. void method(int… a,int… b ){}
E. 選択肢CとDの両方とも正しい
F. 選択肢はすべて正しい
G. 選択肢AからDはすべて間違っている

「徹底攻略 Java SE 11 Silver 問題集」より抜粋
ねこ奈
ねこ奈

まず、CとDはさっきの説明で「引数リストの最後に位置する必要がある」って言っていた項目でコンパイルエラーが発生するコードの例にあった奴なのにゃ!だから、C、D、E、Fは誤りだににゃ。

Bもデータ型の後じゃなくて変数に「…」が付いてないから誤りなのにゃ。

Aは引数の中にvoidは入れないと思うので誤りだと思うのにゃ。

そうなると、正解は選択肢Gかにゃ?

モナ
モナ

正解です!

なお、Javaでは引数を受け取らないことを明示するためには中身なしの括弧を記述するだけで良いですが、C言語とC++は引数を受け取らないことを明示するために、括弧の中にvoidを記述するそうです。

return文

return文(ジャンプステートメント)はJavaSilver対策編第4章後半の回でも紹介しましたが、呼び出し元のメソッドに値を戻すという機能のほかに、呼び出し元に制御を戻すという機能も備えています。そのため、returnだけを記述することも可能です。

使用上の注意点
  1. 戻り値の型に注意: return文で返す値の型は、メソッドの戻り値の型と一致している必要があります。型が一致しない場合、コンパイルエラーが発生します。
  2. 全てのコードパスで値を返す: 戻り値を持つメソッドでは、全てのコードパスが値を返すことを保証する必要があります。そうしないとコンパイルエラーになります。
  3. メソッドの終了を意図して使用: return文はメソッドの終了を意図して使用します。特に途中で処理を終了する場合は、意図しない終了が発生しないように注意が必要です。
  4. 後続のコードが実行されない: return文の後に続くコードは実行されません。これはメソッド内の早期終了を目的とする場合に有用ですが、後続の処理が必要な場合は注意が必要です。
モナ
モナ

return文についての例題も解いてみましょう。

次のプログラムをコンパイル、実行したときの結果として、正しいものを選びなさい。(1つ選択)

1. public class Sample{
2.    public void method(int num) {
3.       if(num < 0) return;
4.       System.out.println("A");
5.       return;
6.       System.out.println("B");
7.    }
8. }                 

A. 3行目でコンパイルエラーが発生する。
B. 5行目でコンパイルエラーが発生する。
C. 6行目でコンパイルエラーが発生する。
D. 「A」と表示される。
E. 「A」「B」と表示される。

「徹底攻略 Java SE 11 Silver 問題集」より抜粋
ねこ奈
ねこ奈

さっきの説明で「 return文の後に続くコードは実行されません。」ってあったのにゃ!だから6行目でコンパイルエラーが発生するのにゃ!

3行目は負の数以外では実行されるという意味だからコンパイルエラーにはならないとにゃ。5行目もコンパイルエラーになる要素はないのにゃ。

そうすると、正解は選択肢Cだにゃ!

モナ
モナ

正解です!

このように実行されないことが明白なコードがあった場合、コンパイラは「到達不可能なコードがある」としてコンパイルエラーを発生させます。

メソッドのオーバーロード

モナ
モナ

オーバーロードについてはJavaコース初級編Day13の回で「オーバーライド」に似ている用語として少しだけ紹介しましたが、今回はオーバーロードについて詳しく学びます。

ねこ奈
ねこ奈

オーバーロードとオーバーライドは似ている言葉だけど、中身は違うから注意だにゃ!

メソッドのオーバーロードとは、同じ名前のメソッドを複数定義し、異なる引数リストを持たせることです。この方法により、同じ操作を異なる方法で行うことができます。オーバーロードされたメソッドは、引数の数や型によって呼び出されるメソッドが決定されるため、コードの可読性と柔軟性が向上します。

具体例を実際のコードで確認してみましょう。

public class MathUtils {

    // 2つの整数の和を計算するメソッド
    public int add(int a, int b) {
        return a + b;
    }

    // 3つの整数の和を計算するメソッド
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 2つの小数の和を計算するメソッド
    public double add(double a, double b) {
        return a + b;
    }

    public static void main(String[] args) {
        MathUtils mathUtils = new MathUtils();

        // 2つの整数の和を計算
        System.out.println("Sum of 2 and 3: " + mathUtils.add(2, 3)); // 5

        // 3つの整数の和を計算
        System.out.println("Sum of 2, 3, and 4: " + mathUtils.add(2, 3, 4)); // 9

        // 2つの小数の和を計算
        System.out.println("Sum of 2.5 and 3.5: " + mathUtils.add(2.5, 3.5)); // 6.0
    }
}
  1. メソッド名:
    • 全てのメソッドがaddという名前を持っています。
  2. 引数リスト:
    • 最初のaddメソッドは2つの整数(int a, int b)を引数に取ります。
    • 二番目のaddメソッドは3つの整数(int a, int b, int c)を引数に取ります。
    • 三番目のaddメソッドは2つの小数(double a, double b)を引数に取ります。
  3. 呼び出し時の挙動:
    • mathUtils.add(2, 3)は2つの整数を引数に取るaddメソッドを呼び出します。
    • mathUtils.add(2, 3, 4)は3つの整数を引数に取るaddメソッドを呼び出します。
    • mathUtils.add(2.5, 3.5)は2つの小数を引数に取るaddメソッドを呼び出します。
使用上の注意点
  1. 引数リストの異なるメソッドを定義する:
    • オーバーロードするメソッドは、引数の数または型が異なる必要があります。引数の型や数が同じで、名前だけが異なるメソッドを定義することはできません。
  2. 曖昧な呼び出しを避ける:
    • 呼び出しが曖昧になる場合、コンパイラはどのメソッドを呼び出すべきか判断できず、エラーが発生します。
モナ
モナ

注意点について、具体的に例題を解いて理解を深めましょう。

次のプログラムをコンパイル、実行したときの結果として、正しいものを選びなさい。(1つ選択)

1. public class Main {
2.    public static void main(String[] args) {
3.        Main m = new Main();
4.       System.out.println(m.calc(2,3));
5.   }
6.    private double calc(double a, int b){
7.       return (a + b)/2;
8.    }
9.    private double calc(int a, double b){
10.        return (a + b)/2;
11.    }
12. }

A. 4行目でコンパイルエラーが発生する。
B. 6行目でコンパイルエラーが発生する。
C. 9行目でコンパイルエラーが発生する。
D. 選択肢BとCの両方。
E. 2.5が表示される。

「徹底攻略 Java SE 11 Silver 問題集」より抜粋
ねこ奈
ねこ奈

え~っとお、まず6行目と9行目は引数の型が異なるからオーバーロードの条件を満たしているのにゃ。だから6行目と9行目ではコンパイルエラーにならないのにゃ。選択肢BとC、ついでに選択肢Dも誤りなのにゃ。

残りはAかEなんだけど、4行目も特におかしくないから実行できる気がするのにゃ。

だから選択肢Eが正解だと思うのにゃ。

モナ
モナ

残念、不正解です。正解は選択肢Aです。

プログラムの中で、Javaはどのメソッドを呼び出すべきかを引数の型や順序によって判断します。問題のコードには次の2つのcalcメソッドが定義されています。

  • private double calc(double a, int b)…このメソッドは、最初の引数がdouble型で、二番目の引数がint型です。
  • private double calc(int a, double b)…このメソッドは、最初の引数がint型で、二番目の引数がdouble型です。

メインメソッドの中で、「System.out.println(m.calc(2, 3));」という行がありますが、ここで呼び出されているcalcメソッドに渡されている引数は、2(int型)と3(int型)です。
Javaは、この引数に最も適したメソッドを探そうとしますが、問題が発生します。

どちらのメソッドを使うべきかが曖昧になってしまうのです。

(double a, int b)に対して:

  • 2はint型ですが、Javaはそれをdouble型(2.0)に変換することができます。
  • 3はint型で、そのまま使うことができます。

(int a, double b)に対して:

  • 2はそのままint型として使えます。
  • 3はint型ですが、Javaはそれをdouble型(3.0)に変換することができます。

このように、どちらのメソッドもcalc(2, 3)という呼び出しに適合します。Javaコンパイラはどちらを使うべきか判断できないため、エラーを出します。

ねこ奈
ねこ奈

「曖昧な呼び出しを避ける」って、こういう意味だったのにゃ…

後編に続きます

今回は「インスタンスとメソッド」について、「メソッドの呼び出しと定義」「可変長引数」「return文」「メソッドのオーバーロード」について解きました。

ハック
ハック

Javaを学習した当初はオーバーロードとオーバーライドの違いがよく理解できませんでした。

このように、具体的な問題やコードを見たり解いたりすることで、その違いについて理解することができました。

プログラミング学習は座学よりも実際にコードを作成して実行した方が上達するという理由が、よく分かる例だと思います。

以上で今回の学習記録を終えます。

ここまでご覧いただきありがとうございました。

コメント

タイトルとURLをコピーしました