Javaチャレンジャー#1:JVMでのメソッドのオーバーロード

Javaチャレンジャー#1:JVMでのメソッドのオーバーロード


すべての良い一日。


コース「Java Developer」の次のストリームをすでに開始していますが、まだ共有したい資料がいくつかあります。


Java Challengersの記事シリーズへようこそ! この一連の記事は、Javaプログラミング機能に焦点を当てています。 それらの開発は、高度な資格を持つJavaプログラマーになるための方法です。


このシリーズの記事で説明した手法を習得するには多少の労力が必要ですが、Java開発者としてのあなたの日々の経験には大きな効果があります。 基本的なJavaプログラミング手法を正しく適用する方法を知っていると、エラーを回避しやすくなり、Javaコードで何が起こっているかを正確に知ると、エラーを追跡するのがはるかに簡単になります。


Javaでのプログラミングの基本概念を習得する準備はできていますか? それでは、最初のパズルから始めましょう!


拡張ボックス化可変引数


「メソッドのオーバーロード」という用語

オーバーロードという用語について開発者はシステムの再起動について話していると考えがちですが、そうではありません。 プログラミングでは、 メソッドのオーバーロードとは、異なるメソッドで同じメソッド名を使用することを意味します。

メソッドのオーバーロードとは何ですか?


メソッドのオーバーロードは、同じクラスの開発者が異なるパラメーターを持つメソッドに同じ名前を使用できるようにするプログラミング手法です。 この場合、メソッドがオーバーロードされていると言います。


リスト1は、数、タイプ、順序が異なるさまざまなパラメーターを持つメソッドを示しています。


リスト1.メソッドをオーバーロードするための3つのオプション。


//   public class Calculator { void calculate(int number1, int number2) { } void calculate(int number1, int number2, int number3) { } } //   public class Calculator { void calculate(int number1, int number2) { } void calculate(double number1, double number2) { } } //   public class Calculator { void calculate(double number1, int number2) { } void calculate(int number1, double number2) { } } 

メソッドのオーバーロードとプリミティブ型


リスト1では、プリミティブ型intおよびdouble 。 少し脱線して、Javaのプリミティブ型を思い出してみましょう。


表1. Javaのプリミティブ型


種類範囲デフォルト値大きさリテラルの例
ブール値真か偽か1ビット真偽
バイト-128 ... 12708ビット1、-90、-128
チャーUnicode文字または0〜65 536\ u000016ビット「a」、「\ u0031」、「\ 201」、「\ n」、4
短い-32,768 ... 32,767016ビット1、3、720、22,000
int-2 147 483 648 ... 2 147 483 647032ビット-2、-1、0、1、9
長い-9,223,372,036,854,775,808から9,223,372,036,854,775,807064ビット-4000L、-900L、10L、700L
浮く3.40282347 x 1038、1.40239846 x 10-450.032ビット1.67e200f、-1.57e-207f、.9f、10.4F
ダブル1.7976931348623157 x 10308、4.9406564584124654 x 10-3240.064ビット1.e700d、-123457e、37e1d

メソッドのオーバーロードを使用する必要があるのはなぜですか?


オーバーロードを使用すると、コードが簡潔になり読みやすくなり、プログラムのエラーを回避するのにも役立ちます。


リスト1とは対照的に、 calculate2calculate3calculate2似た名前の多くのcalculate()メソッドを持つプログラムを想像してください。 compute calculate()メソッドをオーバーロードすると、同じ名前を使用して、必要なものだけ(パラメーター)を変更できます。 また、オーバーロードされたメソッドはコードでグループ化されているため、非常に簡単に見つけることができます。


過負荷ではないもの


変数名の変更はオーバーロードではないことに注意してください。 次のコードはコンパイルされません。


 public class Calculator { void calculate(int firstNumber, int secondNumber){} void calculate(int secondNumber, int thirdNumber){} } 

メソッドシグネチャの戻り値を変更してメソッドをオーバーロードすることもできません。 このコードもコンパイルしません。


 public class Calculator { double calculate(int number1, int number2){return 0.0;} long calculate(int number1, int number2){return 0;} } 

コンストラクターのオーバーロード


メソッドと同じ方法でコンストラクターをオーバーロードできます。


 public class Calculator { private int number1; private int number2; public Calculator(int number1) { this.number1 = number1; } public Calculator(int number1, int number2) { this.number1 = number1; this.number2 = number2; } } 

メソッドのオーバーロードの問題を解決する


最初のテストの準備はできていますか? 見つけよう!


次のコードを注意深く調べることから始めます。


リスト2.メソッドのオーバーロードの課題


 public class AdvancedOverloadingChallenge3 { static String x = ""; public static void main(String... doYourBest) { executeAction(1); executeAction(1.0); executeAction(Double.valueOf("5")); executeAction(1L); System.out.println(x); } static void executeAction(int ... var) {x += "a"; } static void executeAction(Integer var) {x += "b"; } static void executeAction(Object var) {x += "c"; } static void executeAction(short var) {x += "d"; } static void executeAction(float var) {x += "e"; } static void executeAction(double var) {x += "f"; } } 

いいね コードを学習しました。 結論はどうなりますか?


  1. べフェ
  2. bfce
  3. efce
  4. aecf

正解は記事の最後に記載されています。


今何が起こったの? JVMがオーバーロードされたメソッドをコンパイルする方法


リスト2で何が起こったのかを理解するには、JVMがオーバーロードされたメソッドをコンパイルする方法についていくつかのことを知る必要があります。


まず第一に、JVMは適度に怠:です。メソッドを実行するための努力は常に最小限に抑えられます。 したがって、JVMがオーバーロードをどのように処理するかを考えるときは、コンパイラの3つの重要な機能に留意してください。


  1. 広がる
  2. パッケージ化(オートボックス化およびボックス化解除)
  3. 可変長引数(可変引数)

これらのテクニックに出会ったことがない場合は、いくつかの例を参考にして理解してください。 JVMは、リストされている順序でそれらを実行することに注意してください。


次に拡張機能の例を示します。


 int primitiveIntNumber = 5; double primitiveDoubleNumber = primitiveIntNumber ; 

これは、プリミティブ型の拡張順序です。


プリミティブ型の拡張順序


トランスレータの注意-JLSでは、プリミティブ拡張は大きなバリエーションで記述されます。たとえば、longはfloatまたはdoubleに展開できます。


自動パッケージングの例:


 int primitiveIntNumber = 7; Integer wrapperIntegerNumber = primitiveIntNumber; 

コードをコンパイルすると、舞台裏で何が起こるかに注目してください。


 Integer wrapperIntegerNumber = Integer.valueOf(primitiveIntNumber); 

解凍の例を次に示します。


 Integer wrapperIntegerNumber = 7; int primitiveIntNumber= wrapperIntegerNumber; 

このコードをコンパイルすると、舞台裏で何が起こりますか。


 int primitiveIntNumber = wrapperIntegerNumber.intValue(); 

そして、ここに可変長の引数を持つメソッドの例があります。 可変長メソッドは常に最後に実行されることに注意してください。


 execute(int... numbers){} 

可変長引数とは何ですか?


可変長引数は、3つのドット(...)で指定された値の配列です。 このメソッドにint数を渡すことができます。


例:


 execute(1,3,4,6,7,8,8,6,4,6,88...); //  ... 

可変長引数(varargs)は、値をメソッドに直接渡すことができるという点で非常に便利です。 配列を使用した場合、値を持つ配列インスタンスを作成する必要があります。


拡張:ケーススタディ


数値1を直接executeAction()メソッドにexecuteAction()と、JVMはそれをintとして自動的に解釈します。 このため、この番号はexecuteAction(short var)メソッドに渡されません。


同様に、 1.0を渡す1.0 JVMはそれがdoubleであることを自動的に認識します。


もちろん、数値1.0floatにすることもできますが、そのようなリテラルのタイプは事前定義されています。 したがって、リスト2では、 executeAction(double var)メソッドがexecuteAction(double var)ます。


Doubleラッパーを使用する場合、2つのオプションがあります。数値をプリミティブ型に展開するか、 Objectに展開するかのいずれかです。 (JavaのすべてのクラスがObjectクラスを拡張することを思い出してください。)この場合、JVMはアンパックよりも労力が少ないため、 ObjectDouble型の拡張機能を選択します。


最後に渡すのは1L 、型を指定したため、 longです。


一般的な過負荷エラー


おそらく、物事がメソッドのオーバーロードと混同される可能性があることを理解しているので、遭遇する可能性のあるいくつかの問題を見てみましょう。


ラッパーを使用したオートボクシング


Javaは強く型付けされたプログラミング言語であり、ラッパーで自動ラッピングを使用する場合、考慮すべきことがいくつかあります。 まず、次のコードはコンパイルされません。


 int primitiveIntNumber = 7; Double wrapperNumber = primitiveIntNumber; 

コードをコンパイルすると、次と同等になるため、自動パッキングはdouble型でのみ機能します。


 Double number = Double.valueOf(primitiveIntNumber); 

このコードはコンパイルされます。 最初のintdoubleに展開され、 Doubleパックされます。 ただし、自動パッケージ化では、型の拡張子はなく、 Double.valueofコンストラクターはintではなくdouble予期します。 この場合、次のように明示的な型変換を行うと、自動パッキングが機能します。


 Double wrapperNumber = (double) primitiveIntNumber; 

IntegerLongおよびFloatたり、 Doubleすることはできません。 継承はありません。 これらの各タイプ( IntegerLongFloatDouble )は、 NumberObjectです。


疑問がある場合は、ラッパー番号をNumberまたはObject展開できることを覚えておいてください。 (ラッパーについて言えることは他にもたくさんありますが、別の記事に残しましょう。)


コードリテラル


リテラル番号のタイプを指定しない場合、JVMはタイプを計算します。 コードで数値1を直接使用する場合、JVMはそれをintとして作成します。 shortを受け入れるメソッドに1直接渡そうとすると、コンパイルされません。


例:


 class Calculator { public static void main(String... args) { //      // ,   char, short, byte,  JVM    int calculate(1); } void calculate(short number) {} } 

番号1.0場合、同じ規則が適用1.0ます。 それはfloatかもしれませんが、JVMはそれをdoubleと見なします。


 class Calculator { public static void main(String... args) { //      // ,   float,  JVM    double calculate(1.0); } void calculate(float number) {} } 

もう1つのよくある間違いは、 Doubleまたは他のラッパーがdoubleを取得するメソッドに適しているという仮定です。


事実、JVMはプリミティブなdouble型に解凍するのではなく、 ObjectDoubleラッパーを拡張する労力が少ないということです。


要約すると、Javaコードで直接使用すると、 1intなり、 1.0doubleます。 拡張を実行するのが最も簡単な方法です。その後、パッケージ化または展開が行われ、最後の操作は常に可変長のメソッドになります。


奇妙な事実のように。 型char数字を受け入れることを知っていますか?


 char anyChar = 127; // ,  ,    

過負荷について覚えておく必要があること


オーバーロードは、異なるパラメーターで同じメソッド名が必要な場合に非常に強力な手法です。 正しい名前を使用するとコードが読みやすくなるため、これは便利な手法です。 メソッド名を複製してコードに混乱を加える代わりに、単純にオーバーロードすることができます。


これにより、コードがクリーンで読みやすくなり、メソッドの重複によってシステムの一部が破損するリスクも軽減されます。


留意点:メソッドをオーバーロードするとき、JVMは最小限の労力で作業を行います。


実行までの最も遅延のあるパスの順序は次のとおりです。



考慮すべき事項:数値を直接宣言する場合、難しい状況が発生します1int1.0doubleです。


また、 float 1Fまたは1fdouble 1Dまたは1dの構文を使用して、これらの型を明示的に宣言できることを忘れないでください。


これで、メソッドのオーバーロードにおけるJVMの役割は終了です。 JVMは本質的にレイジーであり、常に最も遅延したパスに従うことを理解することが重要です。


答え


リスト2の答えはオプション3です。


Javaでのメソッドのオーバーロードの詳細



メソッドとメソッドのオーバーロードに関する小さなセクションを含む、絶対的な初心者向けのクラスとオブジェクトの紹介。



Javaが厳密に型指定された言語であることが重要である理由と、Javaプリミティブ型について学習します。



メソッドのオーバーロードの制限と欠点、およびカスタム型とパラメーターオブジェクトを使用してそれらを解決する方法を学びます。



Source: https://habr.com/ru/post/J428307/


All Articles