メソッド(method)

あるまとまった処理をするためにいくつかの命令を組み合わせた小さなプログラムをメソッドといいます.Javaでは実行文はすべて,クラスの中に記述されるメソッドに含まれていなければなりません.

メソッドの基本(Basics of Methods)

メソッドは,ヘッドとボディでできていて,

[修飾子] 戻り値のデータ型 メソッド名(データ型 仮引数1,データ型,仮引数2,)
{
    実行文;
    return(式);
}
の形をとります. 例えば,

    public static int cube(int x)
    {
    return x*x*x;
}

において,public static int cube(int x)がヘッドで, ボディは { return x*x*x; }です.

メソッドは値を返すという性質を持っていますので,そのメソッドがどのような型のデータを返すかをメソッド名の前に,メソッドの戻り値のデータ型として宣言する必要があります.return(式文)の式文の値が関数の返す値として呼び出し元に返されるので,式の値と関数のデータ型は一致しなければなりません.値を戻さないメソッドの場合は,メソッドのデータ型としてvoid型を指定し,式の記述のないreturn文を指定します.また,値を返さないメソッドの場合,return文自体を省略することができます.

この例はメソッドの中でも最も単純なものの一つです.一般にメソッドのボディはもっと大きいが,メソッドのヘッドはほとんどの場合一行で収まります.

main()もメソッドで,そのヘッドは
public static void main(String[] args)
です.そのボディはプログラム自身です.main()の戻り値の型はvoidであり,関数名はmainです.

メソッドのreturn文はメソッドの実行を終了する役目とメソッドを呼んだプログラムに値を戻す役目があります.そして,その構文は
return 式文;
となります.

メソッドの種類

Javaのメソッドはインスタンスメソッドとクラスメソッドに分けることができます.インスタンスメソッドは普通に記述するメソッドです.一方のクラスメソッドはstatic修飾子を付けますので,これをstaticメソッドとよぶこともあります.両者はメソッドの指定方法に違いがあります.

クラスメソッドは,クラス名.クラスメソッド名();
インスタンスメソッドは,インスタンス名.インスタンスメソッド名();
のようにして,指定します.

メソッドの呼び出し(Invoking Methods)

呼び出し側と呼び出されるメソッドの間でのデータの受け渡しは引数を用いて行なわれます.呼び出し側で使用する引数を実引数(actual parameter),メソッド側で使用する引数を仮引数(formal parameter)といいます.メソッドの定義において,引数のデータ型を宣言する必要があります.実引数には,定数,変数,式を記述することができますが,仮引数はデータを受け取る器として使用されるので,記述できるのは変数だけです.また,実引数と仮引数のデータ型は必ず一致していなければなりません.

\begin{figure}\centering
\includegraphics[width=9.0cm]{CPPPIC/func.eps}
\end{figure}

基本データ型の受け渡し(値渡し法(Pass by Value))

Javaで引数(実引数)の値をメソッド(仮引数)へ渡す方法を値渡し(pass by value)といいます.メソッドが呼び出されたとき,実引数の値は仮引数のメモリ上にコピーされ,メソッド側で仮引数にコピーされた値を変更しても,呼び出し側の実引数の値には影響が及ばない方法です.基本データ型は全てこの方法で渡されます.値渡しによるデータの受け渡しは,呼出し側から呼び出されるメソッド側への一方通行となります.

例題 5..1   データを読み込んで和と差を求める
\framebox{
\begin{minipage}{13.65cm}
{\rm mainメソッドから実数データa,bをユーザメソッドsumとユーザメソッドdiffに渡して,その和と差を計算して表示するプログラムを作成せよ.}
\end{minipage}}

解答
1.2つの値x,yの和を計算するユーザメソッドをsum(),差を計算するユーザメソッドをdiff()とすると,ユーザメソッドsum()とdiff()は次のように表せる.

private static void sum(double a, double b){ private static void diff(double a, double b){
System.out.println("a+b = " + (a+b)); System.out,println("a-b = " + (a-b));
} }

2.mainメソッドから読み込んだa,bの値をユーザメソッドsum()に渡す.同様にユーザメソッドdiff()に渡す.ではプログラムを作成しよう.

class SumAndDiff
{
  public static void main(String[] args)
  {
    double x = Double.parseDouble(args[0]);
    double y = Double.parseDouble(args[1]);
    sum(x,y);
    diff(x,y);
  }
  private static void sum(double a, double b)
  {
    System.out.println("a+b = " + (a+b));
  }
  private static void diff(double a, double b)
  {
    System.out.println("a-b = " + (a-b));
  }
}

実行結果

\begin{figure}\centering
\includegraphics[width=7.8cm]{JAVAFIG/SumAndDiff.eps}
\end{figure}

練習問題 5..1   平均の計算
main関数から実数データa,bを関数aveに渡して,平均を計算して表示するプログラムを作成せよ.

参照型渡し(Pass by Reference)

Javaでは基本データ型以外は,参照型渡しが用いられます.参照型というと難しそうですが,通常は,基本データ型と同じように扱うことができます.

ローカル変数とメソッド(Local Variables and Methods)

ローカル変数はブロック内で宣言された変数です.したがって,そのブロック内からしかアクセスできません.メソッド自身,一つのブロックですので,メソッド内で宣言された変数はローカル変数です.また,メソッドの引数もローカル変数とみなされます.

例題 5..2   階乗関数
\framebox{
\begin{minipage}{13.65cm}
{\rm n!の計算をするユーザメソッドfact()を作成しなさい.}
\end{minipage}}

階乗は例題4.5で紹介した.nの階乗$n!$はnにn以下の全ての正の整数を掛けたものです.

n! = n(n-1)(n-2) ... (3)(2)(1)

private static int fact(int n)
{
    int f = 1;
    while (n > 1)
       f *= n$--$;
    return f;
}

実行結果

\begin{figure}\centering
\includegraphics[width=7.8cm]{JAVAFIG/FactorialRec.eps}
\end{figure}

このメソッドは2つのローカル変数nとfを持っています.引数nはユーザメソッドfact()で宣言されているのでローカル変数です.変数fはメソッドのボディで宣言されているので,ローカル変数です.

メソッドのオーバーロード(多重定義)(Overloading methods)

メソッドのオーバーロードとは,引数の型や数の違いによって,同じ名前のメソッドを用いることです.メソッドをオーバーロードすると,関連する複数の操作を同じ名前で参照できるので,プログラムの複雑さを軽減することが可能となります.

例えば,Cのライブラリには,整数の絶対値を求めるためのabs()関数,長整数の絶対値を求めるためのlabs()関数,そして,浮動小数点数の絶対値を求めるためのfabs()関数と3つの関数が含まれています.

しかし,これらの3つの関数はみな絶対値を返し,違いはデータ型だけです.このようなとき,Javaでは,3つの異なるデータ型に対して,次のようにして1つの名前をオーバーロードすることができます.
int myabs(int n);
long myabs(long n);
double myabs(double n);

例題 5..3   多重定義 \framebox{
\begin{minipage}{13.65cm}
{\rm myabs()の多重定義を行い,-10の絶対値,-10.34の絶対値を出力するプログラムを作成しなさい.}
\end{minipage}}

解答

class OverloadingMethod
{
  public static void main(String[] args)
  {
    System.out.println("-10の絶対値は" + myabs(-10));
    System.out.println("-10.34の絶対値は" + myabs(-10.34));
  }
  private static int myabs(int n)
  {
    return n < 0 ? -n : n;
  }
  private static double myabs(double d)
  {
    return d < 0 ? -d : d;
  }
}

実行結果

\begin{figure}\centering
\includegraphics[width=7.8cm]{JAVAFIG/OverloadingMethod.eps}
\end{figure}

確認問題 5..1  

1. 関数の宣言はどこにおかれるべきか

3. 関数の定義を別のファイルに置くことの利点を述べよ.

4. 引数による受け渡しと参照による受け渡しの違いを述べよ.

5. 次の宣言の間違いを直せ.
    int f(int a, int b=0, int c);

演習問題 5..1  

1. 次のうるう年を判定するプログラムコードはどちらが効率がよいか調べよ.

y % 4 == 0 && y % 100 != 0 || y % 400 == 0
y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)

2. 4つの整数から最も小さい整数を見つける次の関数を完成しなさい.

int min(int, int, int, int)

3. n個からk個を選び順番をつけて並べる並べ方P(n,k)は

$\displaystyle P(n,k) = \frac{n!}{(n-k)!}$

で与えられる.この関数のプログラムコードを作成せよ.

4. 例題5-3のように,min(int, int)とmin(double, double)の多重定義関数を作成し,min(10,20)とmin(10.34, 20,45)を出力せよ.