web-dev-qa-db-ja.com

Javaコンパイラの場合、インスタンス経由で静的メソッドを呼び出してエラーにならないのはなぜですか?

私はあなたが私が意味する動作を知っていると確信しています-次のようなコード:

Thread thread = new Thread();
int activeCount = thread.activeCount();

コンパイラの警告を引き起こします。なぜエラーではないのですか?

編集:

明確にするために:質問はスレッドとは関係ありません。スレッドの例は、実際に混乱させる可能性があるため、これについて議論するときにしばしば与えられます。しかし、実際の問題は、そのような使用法はalwaysナンセンスであり、そのような呼び出しを(適切に)書いてそれを意味することはできないということです。このタイプのメソッド呼び出しの例はすべて、気難しいでしょう。ここに別のものがあります:

String hello = "hello";
String number123AsString = hello.valueOf(123);

これにより、各Stringインスタンスに「String valueOf(int i)」メソッドが付属しているように見えます。

75
tmtest

基本的に、Javaデザイナーは言語の設計時にミスを犯したと思います。また、関連する互換性の問題のために修正するには遅すぎます。はい、あなたはIDEがIMOとしてエラーを扱うように設定されていることを確認する必要があります。言語を自分で設計する必要がある場合は、避けるべきこと:)

DJClayworthのポイントに対応するために、C#で許可されていることを次に示します。

_public class Foo
{
    public static void Bar()
    {
    }
}

public class Abc
{
    public void Test()
    {
        // Static methods in the same class and base classes
        // (and outer classes) are available, with no
        // qualification
        Def();

        // Static methods in other classes are available via
        // the class name
        Foo.Bar();

        Abc abc = new Abc();

        // This would *not* be legal. It being legal has no benefit,
        // and just allows misleading code
        // abc.Def();
    }

    public static void Def()
    {
    }
}
_

なぜ誤解を招くと思いますか?コードsomeVariable.SomeMethod()を見ると、someVariableの値を使用になると予想されるためです。 SomeMethod()が静的メソッドの場合、その期待は無効です。コードは私をだましています。どうすればgoodになるのでしょうか?

奇妙なことに、Javaは、初期化されていない可能性のある変数を使用して、静的メソッドを呼び出すことはできません。一貫性がなく、役に立たない混乱。

編集:この編集は、静的メソッドの継承を許可すると主張するクレイトンの回答に対する応答です。そうではありません。静的メソッドはポリモーフィックではありません。以下は、それを実証するための短いが完全なプログラムです。

_class Base
{
    static void foo()
    {
        System.out.println("Base.foo()");
    }
}

class Derived extends Base
{
    static void foo()
    {
        System.out.println("Derived.foo()");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Base b = new Derived();
        b.foo(); // Prints "Base.foo()"
        b = null;
        b.foo(); // Still prints "Base.foo()"
    }
}
_

ご覧のとおり、bの実行時の値は完全に無視されます。

78
Jon Skeet

なぜエラーになるのですか?インスタンスはすべての静的メソッドにアクセスできます。静的メソッドは、インスタンスの状態を変更することはできません(isを試みてコンパイルエラー)。

よく知られている例の問題は、静的メソッドの呼び出しではなく、threadsに固有のものです。 threadによって参照されるスレッドのactiveCount()を取得しているように見えますが、実際には呼び出しスレッドのカウントを取得しています。これは、プログラマーとしてのあなたが犯している論理エラーです。この場合、コンパイラは警告を発行することが適切です。警告に注意し、コードを修正するのはあなた次第です。

編集:私は言語の構文がallowingであり、誤解を招くコードを書くことができることを理解していますが、コンパイラとその警告も言語の一部であることを忘れないでください。この言語を使用すると、コンパイラーが疑わしいと見なすことができますが、問題を引き起こす可能性があることを確認するための警告が表示されます。

13
Bill the Lizard

すでに存在するすべてのコードのため、彼らはそれをもうエラーにすることはできません。

エラーになるはずです。コンパイラが警告をエラーにアップグレードするためのオプション/プロファイルが必要な場合があります。

Update:1.4でassertキーワードを導入したとき、古いコードと同様の潜在的な互換性の問題がある、 ソースモードを明示的に「1.4」に設定した場合にのみ使用可能 。新しいソースモード「Java 7」でエラーになる可能性があると思います。しかし、それが面倒なことを引き起こすことを考えると、彼らがそれを行うことを疑います。他の人が指摘したように、混乱を招くコードを書くことを防ぐことは厳密に必要ではありません。そして、言語変更Javaは、この時点で厳密に必要なものに制限する必要があります。

9
Thilo

短い答え-言語はそれを許可するので、エラーではありません。

6
PaulJWilliams

それは仕様の一部であるため、エラーではありませんが、当然のことながら、理論的根拠について尋ねているのは明らかです。

私の推測では、このソースは実際にはクラスのメソッドが同じクラスの静的メソッドを簡単に呼び出すことを許可することです。 x()を呼び出すことは正当であるため(自己クラス名がなくても)、this.x()を呼び出すことも正当である必要があります。

また、これにより、ユーザーが状態を変更しない場合にプライベート関数を静的に変更することをユーザーに促すことができます。

それに加えて、コンパイラは一般に、これが直接的なエラーにつながる可能性がない場合、エラーの宣言を回避しようとします。静的メソッドは状態を変更したり、呼び出しオブジェクトを気にしたりしないため、実際のエラー(混乱だけ)を引き起こしてこれを許可することはありません。警告で十分です。

2
Uri

インスタンス変数参照の目的は、静的を囲む型を提供することだけです。 instance.staticMethodまたはEnclosingClass.staticMethodを介してstaticを呼び出すバイトコードを見ると、同じinvoke staticメソッドバイトコードが生成されます。インスタンスへの参照は表示されません。

答えは、なぜそこにあるのかということです。クラスを使用している限り。インスタンスを介してではなく、将来の混乱を避けるのに役立ちます。

2
mP.

これをエラーにしない同じ論理の可能性が高い:

public class X
{
    public static void foo()
    {
    }

    public void bar()
    {
        foo(); // no need to do X.foo();
    }
}
2
TofuBeer

コンパイラの観点から、本当に重要なことは、シンボルを解決できることです。静的メソッドの場合、特定のオブジェクトに関連付けられていないため、どのクラスを調べるかを知る必要があります。 Javaの設計者は、オブジェクトのクラスを決定できるため、オブジェクトのインスタンスからそのオブジェクトの静的メソッドのクラスも解決できることを明らかに決定しました。彼らはこれを許可することを選択します-おそらく@TofuBeerの観察によって揺らいでいます-プログラマーにいくらかの便利さを与えるために。他の言語設計者はさまざまな選択を行っています。私はおそらく後者のキャンプに落ちたでしょうが、それは私にとってそれほど大したことではありません。私はおそらく@TofuBeerが言及する使用法を許可しますが、インスタンス変数からのアクセスを許可しないという私の立場を許可したことは、あまり受け入れられません。

2
tvanfosson

おそらく、IDE(Eclipse Preferences-> Java-> Compiler-> Errors/Warnings)で変更できます。

1
Dutow

選択肢はありません。 Java(他の多くの言語と同様))では、クラス名またはそのクラスのインスタンスオブジェクトを介して、クラスのすべての静的メンバーにアクセスできます。より使いやすくするために使用すべきソフトウェアソリューション。

0
Pooria