メソッドの概念と使用法
メソッド定義
メソッドは、特定の機能を実行できるツールのようなものです。Java には、前のセクションの nextLine()
の後に括弧が付いているなど、事前に作成されたメソッドも多数あります。 。
(場所によっては、メソッドが関数と呼ばれることもあります (主に、他の言語を学習してから無意識のうちに関数と呼ばれたり、複数言語のシナリオに適応したりするためです) )、詳しく調べると、実際には同じではありません。ただし、混乱を避けるために、関数が実際に何を意味するのかを理解する必要があります)
実際、いくつかのメソッドをカスタマイズして、特定の関数を完了しやすくすると同時に、コードの冗長性を減らすこともできます。これは、このメソッドを一度作成すれば複数回呼び出すことができるためです。
では、どうやってメソッドを定義すればよいのでしょうか?構文は次のとおりです
修饰符 返回值类型 方法名称([参数类型 形参 ...]){
方法体代码;
[return 返回值];
}
//[]括住的是可选的,不是一定要有 ...代表数量可变
識別子については、現在の学習段階では public static
のように記述できます。詳細については、次のクラスとオブジェクトに関する章で説明します。
それでは、他のものは何を意味するのでしょうか?例を使って説明しましょう。以下は 2 つの整数の和を求める方法です。
public static int add(int x, int y) {
return x + y;
}
各コンポーネントを個別に説明しましょう。
- 識別子:書き込み方法を修正
- 戻り値の型: 2 つの加算の合計を返したい
int
ので、型は同じである必要がありますint
- 名前: メソッド名はキャメルケースの原則に従います。
- 仮引数: 2つの数値を加算する場合、必ず2つの数値が渡されるので、仮引数を使用して受け取ります。2つの数値なので、仮引数が2つ作成されます。
- メソッド本体: 実際に実行されるコード。次のようになります。
a + b
return
: return ステートメント。計算された最終値を戻すために使用されます。
メソッドを定義する際の考慮事項をいくつか示します。
- メソッドをネストすることはできません。つまり、メソッドはメソッド内で定義されます。
- 戻り値がない場合、戻り値の型は次のようになります。
void
- 戻り値は最大 1 つです
- メソッドにパラメータを含めることはできません。パラメータがない場合は、中央の大括弧を空にすることができます。
メソッド実行プロセス
ここではまず、上記の加算メソッドによるメソッドの実行プロセスを理解します。
public class Test {
public static int add(int x, int y) {
return x + y;
}
public static void main(String[] args) {
int a = add(5,3);
}
}
では、上記のコードはどのように機能するのでしょうか?
まず、5
と 3
を と add
に渡します。 > に返し、その値を を計算し、最後に計算された値を 、次に x
y
x + y = 8
add(5, 3)
a
実際、動作モードはすべてのメソッドで同様です。被调用--->接收参数--->执行方法体--->如果有返回值就进行返回没有就直接结束
仮パラメータと実パラメータ
上記のコードを例として引き続き使用します
public class Test {
//x y就是形式参数,简称形参
public static int add(int x, int y) {
return x + y;
}
public static void main(String[] args) {
//5 3就是实际参数,简称实参
int a = add(5,3);
}
}
形式パラメータは金型に相当し、実パラメータはフィラーに相当し、両者を組み合わせることで初めて最終製品を作ることができます。
メソッドが実行されると、実際のパラメータは仮パラメータに割り当てられ、仮パラメータによってパラメータが計算されます。注意:この 2 つは相互運用できません
この問題を説明するための例として、2 つの整数の位置を交換するメソッドを書いてみましょう。
public class Test {
public static void swap(int x, int y){
int tmp = x;
x = y;
y = tmp;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("交换前 a = " + a + " b = " + b);
swap(a, b);
System.out.println("交换后 a = " + a + " b = " + b);
}
}
位置がまったく変わっていないことがわかりますが、なぜでしょうか?メソッド内のコードが交換されていませんか?
実際、メソッドを呼び出すと、メモリ上の領域に空きができます。この領域はスタック領域と呼ばれ、メソッドが空きを開く操作をスタックのプッシュと呼びます。では、このスペースは何に使用されるのでしょうか? 仮パラメータと実行メソッド本体を格納するために使用されます。
言い換えれば、仮パラメータが使用されるとき、実際には新しい変数を作成するのと同じことになります。したがって、上記のコードが交換を実行するとき、実際に交換されるのは、実際のパラメータではなく、新しく作成された 2 つの変数です。
したがって、メソッドを使用して変数を交換する方法については、この研究の後半で説明するとして、今のところは保留しておきます。
メソッドのオーバーロード
上記の加算方法を作成したときに、その制限が非常に高いことがわかりました。
は 2 つの数値の合計を計算できるだけでなく、 int
型のみを計算できます。次に、Java を使用すると、メソッドをオーバーロードして、その使用範囲を拡大できます。
引き続き加算演算を例に挙げます
public class Test {
public static int add(int a, int b){
return a + b;
}
//拓展了参数个数
public static int add(int a, int b, int c){
return a + b + c;
}
//拓展了参数类型
public static double add(double a , double b){
//倘若只改变返回值类型不算做方法的重载,会因为定义冲突报错
return a + b;
}
}
メソッドのオーバーロードに関して注意すべき点がいくつかあります。
- メソッドは複数回オーバーロードできますが、その数は適切である必要があります
- メソッドのオーバーロードの核心はパラメータリストの違いであり、修飾子や戻り値は影響しません。
すると、「あなたも賢くないです。ではn
数字を追加したいのですが、n
何を追加すればいいのかわかりません」と言う人もいるかもしれません。特定の値を扱う
この時点で特別なパラメータ、変数パラメータを使用できます。
変数パラメータ
これにより、メソッド定義で引数の数を明示的に指定せずに、メソッドが可変数の引数を受け入れることができます。
変数パラメータを定義する例を示します
public static int test(int...x){
}
次に、任意の数のパラメータを渡すことができます。test()
実は可変パラメータとは、入力したデータの数に応じて定義される配列のことですが、配列の知識が関係するため、ここでは使い方の説明はひとまず省略し、まずは理解してください。
メソッドのシグネチャ
上記のメソッドのオーバーロードでは、同じ名前のメソッドを複数記述しました。そうすると、「なぜローカル変数名は同じにできないのに、同じクラス内のメソッド名は同じにできるのか?」と疑問に思う人もいるでしょう。
実際、Java は、メソッド名とメソッド パラメータの型で構成されるメソッド シグネチャに基づいて、メソッドが競合するかどうかを判断します。
次のコードを例として、バイトコード ファイルを逆コンパイルしてメソッド シグネチャを確認することもできます。
public class Test {
public static int add(int a, int b){
return a + b;
}
public static int add(int a, int b, int c){
return a + b + c;
}
public static double add(double a , double b){
return a + b;
}
public static void main(String[] args) {
add(1,3);
add(1.3,1.1);
}
}
逆コンパイル
IDEA では、Java プログラムを実行するたびに、out
フォルダにバイトコード ファイルが生成されます。まずこのフォルダを開いてファイル内のバイトコードを見つけ、そのパスにアクセスします。
次に、このパスで cmd
を開き、 サフィックスを追加せずに javap -v +文件名字
と入力します。.class
最後までスクロールすると、ここでメソッドを呼び出すためのプロンプトが表示されます。
はそれぞれ add:(II)I
と add:(DD)D
を呼び出します。その合成形式は として説明できます。方法名:(参数类型1参数类型2)返回值类型
戻り値の型は含まれていますが、競合は戻り値が異なる場合にのみ発生するため、実際にはメソッド シグネチャに属しません。
ここではいくつかの特殊文字が関係しています。一般的な特殊文字をいくつか示します (理解するだけです)。
特殊文字 | データの種類 |
---|---|
で | void |
と | boolean |
B | byte |
C | char |
S | short |
私 | int |
J | long |
F | float |
D | double |
[ | 配列には複数の要素が含まれます[ 。N は N 次元配列であることを意味します |
L | 参照型。 で始まり、参照型の完全なクラス名で終わります。L ; |
メソッドの再帰
再帰、つまりそれ自体の呼び出しでは、実際には、大きな問題を小さな問題に分割するというアイデアが使用されます。
たとえば、!5
が必要な場合は、!4
を見つけて、5
を掛けて < a i=4> は になります。 が見つかったら、分割をやめて元に戻して答えを取得します。!4
!3*4
1
再帰を使用する場合の注意:
- サブメソッドと元のメソッドの解決策は一貫している必要があります
- 境界条件を設定する必要があり、デッド再帰を防ぐために各再帰後に境界条件に近づく必要があります。
次に、再帰を使用して階乗を見つけるコードを実装します。
public class Test {
public static int fact(int n) {
//边界条件
if (n == 0 || n == 1) {
return 1;
} else {
//递归
return fact(n - 1) * n;
}
}
public static void main(String[] args) {
System.out.println(fact(5));
}
}
再帰の長所と短所
ここでは、最初に再帰を使用してフィボナッチ数列を見つける方法を実装します。
public class Test {
public static int fib(int n) {
if(n == 0){
return 0;
} else if (n == 1) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
public static void main(String[] args) {
System.out.println(fib(45));
}
}
は、40
より多くの計算をさせると、出力が非常に遅くなることがわかります (これはコンピュータの構成によって異なります)
なぜ?カウンターを作成して確認することもできます
public class Test {
//全局计数器
static int count = 0;
public static int fib(int n) {
//给执行的边界情况计数
if(n == 0){
count++;
return 0;
} else if (n == 1) {
count++;
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
public static void main(String[] args) {
System.out.println(fib(45));
System.out.println(count);
}
}
下限の呼び出し回数が計算したい回数を超えていることがわかりますが、ここでは途中の計算量さえ加えていないため、計算量は非常に恐ろしいものになります。
したがって、場合によっては、問題を解決するために再帰を使用することが推奨されず、ループを使用することが推奨されます。
public class Test {
public static int fib(int n) {
int num1 = 0;
int num2 = 1;
int ret = 0;
for (int i = 0; i < n-1; i++) {
ret = num1 + num2;
num1 = num2;
num2 = ret;
}
return ret;
}
public static void main(String[] args) {
System.out.println(fib(45));
}
}
ここでのループの計算量は実際にはループ回数であり、n-1
回であり、非常に少ないです
練習する
再帰を使用して解決するハノイの塔の問題
一度に移動できるプレートは 1 枚だけで、移動中は常に 3 本のロッドの下部に大きなプレート、上部に小さなプレートが配置され、操作中はどのロッドにもプレートを置くことができます。 A、B、C。
アイデアの分析
この問題は再帰的に解決できるため、n
プレートの移動の問題を n-1
プレートの移動と別のプレートの移動に変換する方法を考えてもよいでしょう。プレートの問題
n
プレートを B
に移動する場合は、まず一番下の大きなプレートを B
に移動する必要があります。動きの中で、大きな市場を一番下に、小さな市場を一番上に保つ必要があるため、アイデアが出てきます
どこに移動するかは考慮せず、n
プレートの移動のみを考慮します。その後、n-1
プレートを < に移動するかどうかは関係ありません。 a i=3> または 回数は同じである必要がありますB
C
最初に下部プレートを B
に移動する必要があるため、次に上部 n-1
プレートを C
に移動する必要があります。 、 状況は図
現時点では、C
の上の n-1
を B
に移動するだけです。
n
プレートを移動する操作は次のように分割されます: 1. 最初に n-1
プレートを移動します 2. 次に 1 つのプレートを移動します 3. 移動n-1
プレート
式で表すと、F(n) = 2F(n-1) + 1
上記のアイデアを使用すると、コードを実装するのは非常に簡単になります。
public class Test {
public static int hanoi(int n) {
//边界条件
if (n == 0 || n == 1) {
return n;
} else {
//递归
return 2 * hanoi(n - 1) + 1;
}
}
public static void main(String[] args) {
System.out.println(hanoi(10));
}
}