第10講 関数の再帰的呼び出し=関数の自己再帰の学習
第1話 関数の再帰的呼び出し=関数の自己再帰とは?


関数の再帰的呼び出しとは何でしょうか。
関数の自己再帰という名称からある程度予想できるように、
関数が自分自身を呼び出すことです。
次のようなプログラムコードを作り、実行してみてください。
public class A{
  public static void main(String args[]){
    cn=0;
    f();
  }
  public static void f(){
    System.out.println("初心者のためのJava 入門 基礎から応用まで");
    f();
  }
}
すると、
入門
と流れ続けて、途中でエラーしてしまいます。
C++やVBならエラーしないで無限に続きます。
実は無限ループです。
永遠にf()がf()を呼び続けるからです。
自分が自分を呼び自分のところに帰ってくるので、関数の再帰的呼び出し=関数の自己再帰と呼ぶわけです。
(Javaは無限ループになる場合途中で止める機能があるようで、エラーします。)
再帰的呼び出しの場合途中で止める条件が必要です。
そこで、クラス変数を用意して
public class A{
  static int cn; //クラス変数=静的メンバー変数
  public static void main(String args[]){
    cn=0;
    f();
  }
  public static void f(){
    System.out.println("初心者のためのJava 入門 基礎から応用まで");
    cn++;
    if(cn<20)f();
  }
}
と変更しましょう。
構造化プログラミングの思想のところで述べたように基本的に変数はすべて関数の中のみで有効な
ローカル変数です。
関数を超えて、変数を使いたい場合はC++やVBAならグローバル変数を使います。
そのグローバル変数にJavaで対応するものが、
クラス変数または静的メンバー変数です。
ただし、static=静的の意味は、C++やVBなどとは少し意味が違います。
C++やVBでは、メモリに常駐する変数をstatic変数といいますが、
Javaの場合、直接使える変数をいいます。
もし、staticを外して
int cn;
のように宣言した場合、関数の外側で宣言してあっても、
後に述べるインスタンス化(実体化)という手続きをしないと使えません。
インスタンス化は、鯛焼きの型と鯛焼きの関係を思い出してください。
関数の外側で
int cn;
と宣言した場合、
変数そのものの宣言でなく変数の雛形(つまり鯛焼きの型に相当する)を宣言したにすぎません。
クラス内でこの変数を利用するためには、
鯛焼きの型から、鯛焼き(これがインスタンス化したもの)を作らなければなりません。
つまり、
static int cn;
と宣言した場合、直接鯛焼き=変数ができるのに対して、
int cn;
の場合は、鯛焼きの型ができたにすぎないのです。
ですから、変数=鯛焼きを使いたい場合は、鯛焼きの型から鯛焼きを作らなければなりません。
今の比喩による説明がわかりにくい方は、
static int cn;
の場合は直接、変数ができるのに対して
int cn;
のときには、変数の設計書ができるのにすぎないと理解するとよいかもしれません。
車を使いたいときは、
車の設計図から、車を作らなければならないように、
int cn;
と宣言した場合には、それは変数の設計図にすぎないので、
設計図から実際のもの=インスタンス=変数=鯛焼きをつくななければならないのです。
以上の説明を読んでも、なかなかイメージできないと思いますが、
インスタンス化については、後に独立の講を作りますので、
もう少し我慢して先を読んでください。
Java
ローカル変数(プログラム全体で通用する変数)に相当するクラス変数=メンバ変数を用意するのは、
関数mainと関数f()の両方で使用するからです。
今回はメンバ変数(正確には静的メンバ変数=クラス変数)は、回数を数えるために用意しました。
つまり、回数が20回で止めるようにしてあります。
実際、実行画面
初心者
を見ると20回でプログラムを止めています。

20回で止めるようにしてあることを明確にするため、
コードを次のように変更してみて、コンパイル・実行してみてください。
public class A{
  static int cn; //クラス変数=静的メンバー変数
  public static void main(String args[]){
    cn=0;
    f();
  }
  public static void f(){
    System.out.println("初心者のためのJava 入門 基礎から応用まで");
    cn++;
    if(cn==20)return;
    f();
  }
}
結果は同じです。


自分が自分を呼び出し自分のところに返ってくるとはどういう意味でしょうか。
それは、f()がf()を呼び出し、仕事が終わってからf()に戻るからです。
関数の再帰的的呼び出し=関数の自己再帰は、2つの意味で自己再帰なのです。
f()が自分自身f()を呼び出し、f()に戻るという意味です。
自分が自分を呼び出し、自分に戻る・・・・
『何言ってるだ?佐藤さん』という声が聞こえてきそうです。
本講義のトップページに書いてある
 プログラミングの学習において、完全に理解してから次に進むという完全主義は、学習を妨げることになります。基本は、意図したとおりコンピュータが動けばよいです。村はじまって以来の数学の天才だった世界的文豪のスタンダールは、(−)×(−)が(+)になることがどうしても納得できなくて、数学につまずいてしまったということですが、反対の反対は元に戻る程度の理解で妥協しなかったことが災いしたわけです。その時点で、完全にわからなくても学習が進むとすっきりわかってくるものです。ですから、決して諦めないで粘り強く学習を続ける、先を読み続けるという姿勢で取り組んでいただければと思います。もちろん、時々前を読み返して復習することも必要です。わからない点があっても先を読み続け、時々前を読み返す、ということを繰り返していれば、茨の道も必ず通り抜けることができます。雲がかかり頂上が見えなくても、歩みを続けなければ頂上にたどり着くことはありません。茨の道であるほど、困難な登頂であるほど、達成したときの喜びは大きいものですよね。是非とも、粘り強く学習し360度の視界を獲得しましょう。  

を常に忘れないでください。
後何話か読み続けると、意味は明瞭になります。

ところで関数の自己再帰を途中で止めるためのカウンタ(数えるものという意味)として、
メンバ変数cnを用意しましたが、実は引数を利用すればメンバ変数を使う必要がありません。
それを考えてください。


第9講第7話へ 第2話へ

戻る

VB講義へ
VB講義基礎へ
vc++講義へ第1部へ
初心者のための世界で一番わかりやすいVisual C++入門基礎講座
初心者のための世界で一番わかりやすいVisual Basic入門基礎講座
初心者のための世界で一番わかりやすいVBA入門講義(基礎から応用まで)
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第1部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第2部
初心者のための VC++による C言語 入門 C++ 入門 基礎から応用まで第3部
初心者のための Java 入門 サイト 基礎から応用まで第1部
初心者のための Java 入門 サイト 基礎から応用まで第2部
初心者のための Java 入門 サイト 基礎から応用まで第3部