23

次のコードはコンパイルされません。

package varargspkg;

public class Main {

    public static void test(int... i) {
        for (int t = 0; t < i.length; t++) {
            System.out.println(i[t]);
        }

        System.out.println("int");
    }

    public static void test(float... f) {
        for (int t = 0; t < f.length; t++) {
            System.out.println(f[t]);
        }

        System.out.println("float");
    }

    public static void main(String[] args) {
        test(1, 2);  //Compilation error here quoted as follows.
    }
}

コンパイル時エラーが発行されます。

testへの参照があいまいで、varargspkg.Mainのメソッドtest(int ...)とvarargspkg.Mainのメソッドtest(float ...)の両方が一致します

メソッド呼び出しのパラメータ値は、次のtest(1, 2);ようにプロモートできるため、明らかなintようです。float

パラメータのいずれかまたは両方の末尾にFまたはが付いている場合fは、コンパイルされます。


ただし、次のように、それぞれのラッパータイプを使用してメソッドシグネチャで受信パラメータを表す場合

public static void test(Integer... i) {
    System.out.println("Integer" + Arrays.asList(i));
}

public static void test(Float... f) {
    System.out.println("Float" + Arrays.asList(f));
}

その後、メソッドの呼び出しはtest(1, 2);コンパイルエラーを発行しません。この場合に呼び出されるメソッドは、1つのIntegervarargsパラメーター(前のスニペットの最初のパラメーター)を受け入れるメソッドです。

この場合、最初のケースのようなエラーが報告されないのはなぜですか?ここでは、自動ボクシングと自動タイププロモーションの両方が適用されているようです。エラーが解決されるように、最初に自動ボクシングが適用されますか?

Oracleドキュメントによると、

一般的に言って、varargsメソッドをオーバーロードしないでください。そうしないと、プログラマーがどのオーバーロードが呼び出されるかを理解するのが難しくなります。

このリンクの最後の文。ただし、varargsをよりよく理解するためです。

また、以下に追加するコードは問題なくコンパイルされます。

public class OverLoading {

    public static void main(String[] args) {
        load(1);
    }

    public static void load(int i) {
        System.out.println("int");
    }

    public static void load(float i) {
        System.out.println("float");
    }
}

編集:

以下は、コンパイルエラーを示すスナップショットです。新しいアプリケーションを作成したため、パッケージ名が異なります。

ここに画像の説明を入力してください

JDK6を使用しています。

4

4 に答える 4

10

すべてのクラスはのサブクラスであるため、 (Int to Integer(Boxing)、次にInteger to Object(Widening)が有効である場合を除いて、どちらかWidenまたは両方を行うことはBoxできません。パラメータ)boxing and wideningObjectObjectIntegerObject

同様に、inttoNumberも有効です(int-> Integer-> Number)NumberはそのスーパークラスであるIntegerため、可能です。

あなたの例でこれを見てみましょう:-

public static void test(Integer...i)

public static void test(Float...f)

Boxing、Widening、Var-argsを組み合わせる場合、どのオーバーロードされたメソッドを選択するかを選択するときに従うルールがいくつかあります。

  1. プリミティブの拡大は、smallest可能なメソッド引数を使用します
  2. ラッパータイプを別のラッパータイプに拡張することはできません
  3. intからIntegerにボックス化し、Objectに拡張できますが、Longには拡張できません
  4. 拡大はボクシングを打ち負かし、ボクシングはVar-argsを打ち負かします。
  5. あなたは箱に入れてから広げることができます(Anは経由intになることができます)ObjectInteger
  6. 広げてからボックスにすることはできません(AnintになることはできませんLong
  7. var-argsを、拡大またはボクシングと組み合わせることはできません

したがって、上記のルールに基づいて:-

上記の関数に2つの整数を渡すと、

  • ルール3によると、最初WidenedBoxedに収まる必要がありますLong。これは、ルール5では違法です(拡大してからボックス化することはできません)。
  • したがって、Integervar-argsに格納するためにボックス化されています。

しかし、最初のケースではvar-args、プリミティブ型のメソッドがあります:-

public static void test(int...i)
public static void test(float...f)

次にtest(1, 2)、両方のメソッドを呼び出すことができます(どちらもrule 1適用に適していないため):-

  • 最初のケースではvar-args
  • 2番目のケースでは、Widening、次にVar-args(許可されています)になります

さて、ちょうど1つのintと1つのflostを持つメソッドがある場合:-

public static void test(int i)
public static void test(float f)

次に、を使用して呼び出すtest(1)と、ルール1に従い、可能な限り最小の拡大(つまり、int拡大がまったく必要ない場合)が選択されます。したがって、最初のメソッドが呼び出されます。

詳細については、を参照してください。JLS - Method Invocation Conversion

于 2012-10-14T06:52:40.117 に答える
2

Javaでは、1を表す方法ですint。のインスタンスに自動ボックス化するか、Integerにプロモートするfloatことができます。これは、コンパイラが呼び出すメソッドを決定できない理由を説明しています。Longただし、またはFloat(またはその他のタイプ)に自動ボックス化されることはありません。

一方、を書く場合1F、それはの表現であり、floatに自動ボックス化することができますFloat(そして、同じ精神で、Integerまたは他のものに自動ボックス化されることは決してありません)。

于 2012-10-14T06:42:59.367 に答える
2

Java 6では、instantiationどのメソッドを呼び出すことができるかを見つける前に、ジェネリックスの時点で問題が発生します。

When you write 1,2 
     -> it can be be both int[] or float[] and hence the issue being complained.

When you write 1,2F 
     -> it can be be only float[] and hence the NO issue being complained.

他の2つのオプションと同じ

When you write 1F,2 
     -> it can be be only float[] and hence the NO issue being complained.

When you write 1F,2F 
     -> it can be be only float[] and hence the NO issue being complained.

一方、intまたはを使用する場合float、変数型のインスタンス化はありません。を使用する1と、最初に引数としてwithメソッドを見つけようとしますint。そうでない場合は、型をプロモートし、floatでメソッドを識別します。両方の方法が利用できる場合は、どちらか一方がint最初に使用されます。

Java 7はデータ型のチェックとプロモートの処理が優れているため、あいまいさの問題は発生しません。

于 2012-10-14T06:48:40.507 に答える
2

この場合、最初のケースのようなエラーが報告されないのはなぜですか?ここでは、自動ボクシングと自動タイププロモーションの両方が適用されているようです。エラーが解決される最初に自動ボクシングが適用されますか?

ただの意見-varargsの場合、JVMは実際に引数の配列を作成する必要があります。IntegerとFloatの場合、どのタイプの配列を作成する必要があるかは明らかです。したがって、それがあいまいさのエラーがない理由である可能性があります。

しかし、それでも、デフォルトで1、3が整数であるのに、整数の配列を作成できないのは、ちょっと紛らわしいです。

これは、varargsとオーバーロードに関する過去のバグでSOでここで議論されたように見えますか?議論によると、実際にはバグです。

于 2012-10-14T07:05:31.250 に答える