4

継承された静的メソッドの静的インポートを使用すると、奇妙な動作が発生します。

com/example/util/BaseUtil.java:

package com.example.util;

/*default*/ class BaseUtil {
    public static final void foo(){ System.out.println("foo"); }
}

com/example/util/Util.java:

package com.example.util;

public final class Util extends BaseUtil{
    public static void bar(){ System.out.println("bar"); }
    //foo() will be inherited
}

com/example/UtilTest.java

package com.example;

import static com.example.util.Util.bar;
import static com.example.util.Util.foo;

public class UtilTest {
    public static void main(String[] args) {
        bar();
        foo();
    }
}

実行UtilTestすると非チェック例外が発生します!

スレッド「メイン」の例外 java.lang.IllegalAccessError: クラス com.example.util.BaseUtil からクラス com.example.UtilTest にアクセスしようとしました

    at com.example.UtilTest.main(UtilTest.java:15)

Utilただし、 (静的インポートなしで)メソッドを参照すると、すべてが期待どおりに機能します。

com/example/UtilTest.java

package com.example;

import com.example.util.Util;

public class UtilTest {
    public static void main(String[] args) {
        Util.bar();
        Util.foo();
    }
}

それで、何が得られますか?

4

3 に答える 3

5
/*default*/ class BaseUtil { //only visible within the package com/example/util

そのクラスにはデフォルトのアクセス指定子があり、そのパッケージの外部からは見えなくなります。

公開する必要があります。

アップデート

逆コンパイルは次のようになります。

public class com.example.UtilTest extends java.lang.Object{
public com.example.UtilTest();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   invokestatic    #16; //Method com/example/util/Util.bar:()V
   3:   invokestatic    #21; //Method com/example/util/BaseUtil.foo:()V
   6:   return

}

以下は、JD GUIを使用して取得したものです

package com.example;

import com.example.util.BaseUtil;
import com.example.util.Util;

public class UtilTest
{
  public static void main(String[] args)
  {
    Util.bar();
    BaseUtil.foo();
  }
}

もちろん、これはコンパイルされません。

ここでは、コンパイラの穴のように見えます (静的インポートが原因である可能性があります)。

于 2012-11-15T23:41:10.757 に答える
1

完全な答えではありませんが、静的関数をインポートするときに考慮すべきことが他にあります。

静的関数/定数を使用している場合、インラインでコンパイルされることがあります。これは、使用しているコンパイラによって異なります。頭のてっぺんからどれがどれか思い出せません。

これは、静的変数/関数を外部ライブラリからインポートし、実行時にそのライブラリをアップグレードすると、コードに OLD 静的関数がまだ含まれている場合に問題になります。

私の提案は、静的関数を完全に避け、代わりにシングルトン オブジェクトを使用することです。実行時にクラスにシングルトンを挿入するには、Spring などのフレームワークを使用します。

このオブジェクトを最終的なものにし、コンストラクターを使用して設定することをお勧めします。

これにより、シングルトンをモックできるため、テストも容易になります。

于 2012-11-16T00:33:45.457 に答える
0

コードの最初のバージョンは、効果的にコンパイルされます

package com.example;

public class UtilTest {
    public static void main(String[] args) {
        com.example.util.Util.bar();
        com.example.util.BaseUtil.foo();
    }
}

パッケージスコープがあるためBaseUtil、別のパッケージから呼び出すことはできず、例外が発生します。

コードの 2 番目のバージョンは、効果的にコンパイルされます。

package com.example;

public class UtilTest {
    public static void main(String[] args) {
        com.example.util.Util.bar();
        com.example.util.Util.foo();
    }
}

はパブリック クラスであるため、Util に表示されるため、Utilを含むすべてのメソッドにアクセスできます。foofoo

私が困惑しているのは、バージョンのいずれかが正しくコンパイルされるのはなぜですか?

于 2012-11-15T23:55:47.633 に答える