26

実験によって、Javaの非静的メソッドが、静的コンテキストでもスコープ内のすべての同じ名前のメソッドをオーバーライドすることを発見しました。パラメータのオーバーロードを許可しなくても。好き

import java.util.Arrays;    
import static java.util.Arrays.toString;

public class A {
    public static void bar(Object... args) {
        Arrays.toString(args);
        toString(args);     //toString() in java.lang.Object cannot be applied to (java.lang.Object[])
    }
}

スペックにはこれについて何も見つかりません。これはバグですか?そうでない場合、そのような言語を実装する理由はありますか?

UPD:Java6はこの例をコンパイルしません。問題は-なぜですか?

4

4 に答える 4

24

説明は簡単ですが、動作が非常に直感的でないという事実は変わりません。

呼び出されるメソッドを解決するとき、コンパイラーが最初に行うことは、正しい名前のメソッドを持つ最小の囲みスコープを見つけることです。そうして初めて、過負荷の解決やゲーム内の共同作業などの他のものが登場します。

ここで起こっていることは、メソッドを含む最小の囲みスコープは、toString()メソッドを継承するクラスAであるということですObject。したがって、そこで停止し、それ以上検索しません。悲しいことに、次にコンパイラは、指定されたスコープ内のメソッドの最適なものを見つけようとし、それらのいずれも呼び出すことができず、エラーが発生することに気付きます。

つまり、オブジェクトのメソッドと同じ名前のメソッドを静的にインポートすることはありません。これは、自然にスコープ内にあるメソッドが静的インポートよりも優先されるためです(JLSはメソッドのシャドウイングを詳細に説明していますが、この問題については、覚えておいてください)。

編集:@alfは、全体像を知りたい人のためのメソッド呼び出しを説明するJLSの適切な部分を親切に提出しました。それはかなり複雑ですが、問題も単純ではないので、それは予想されることです。

于 2012-01-23T13:34:38.920 に答える
4

オーバーライドではありません。それが機能した場合でも、オーバーライドが発生した場合とは異なり、代わりにthis.toString()のメソッドにアクセスします。AArrays.toString

言語仕様では、静的インポートはstaticメソッドと型の解決にのみ影響すると説明されています。

n という名前のフィールドをインポートする、パッケージ p のコンパイル ユニット c 内の single-static-import 宣言 d は、c 内の static-import-on-demand 宣言によってインポートされた n という名前の静的フィールドの宣言を c 全体にわたって隠します。

シグネチャ s を持つ n という名前のメソッドをインポートする、パッケージ p のコンパイル ユニット c 内の単一静的インポート宣言 d は、c の静的インポート オンデマンド宣言によってインポートされるシグネチャ s を持つ n という名前の静的メソッドの宣言をシャドウします。 、c全体を通して。

n という名前の型をインポートするパッケージ p のコンパイル ユニット c 内の single-static-import 宣言 d は、次の宣言をシャドウします。

  • c の static-import-on-demand 宣言によってインポートされた n という名前の任意の静的型。
  • p の別のコンパイル単位 (§7.3) で宣言された n という名前の最上位の型(§7.6)。
  • c の type-import-on-demand 宣言 (§7.5.2) によってインポートされたn という名前の任意の型。c。

静的インポートは、非静的メソッドまたは内部型をシャドーしません。

したがって、toStringは非静的メソッドをシャドーしません。名前toStringは の非静的メソッドを参照できるため、 のメソッドを参照Aできず、スコープ内で使用できる名前付きの唯一のメソッドである にバインドされます。そのメソッドは引数を取ることができないため、コンパイル エラーが発生します。 staticArraystoStringtoStringString toString()

セクション 15.12.1はメソッドの解決について説明しており、メソッド内ではなくメソッド内で使用できないメソッド名をシャドウできるように完全に書き直す必要がstaticありmemberます。

私の推測では、言語設計者はメソッド解決規則を単純に保ちたいと考えていたのでしょう。つまり、同じ名前は、staticメソッドに表示されるかどうかに関係なく同じことを意味し、変更されるのはどれが使用可能かだけです。

于 2012-01-23T13:25:20.180 に答える
1

たようなコードを実行しようとすると、コンパイラ エラーは発生しません。

import static java.util.Arrays.sort;
public class StaticImport {
    public void bar(int... args) {
        sort(args); // will call Array.sort
    }
}

これがコンパイルされ、あなたのものがコンパイルされないtoString()理由は、Object がクラスの親であるため、(またはクラス Object で定義された他のメソッド) がまだ Object クラスにスコープされているためです。したがって、コンパイラがオブジェクトクラスからこれらのメソッドの一致するシグネチャを見つけると、コンパイラエラーが発生します。私の例では、 Object クラスにはメソッドがないため、コンパイラはそれをstatic importsort(int[])と正しく一致させます。

于 2012-01-23T13:43:35.097 に答える
0

バグや通常のインポートとは違うものではないと思います。たとえば、通常のインポートの場合、インポートされたものと同じ名前のプライベートクラスがある場合、インポートされたものは反映されません。

于 2012-01-23T13:34:55.607 に答える