2012-01-31 1 views
8

私はこの仕事を私たちのコードベースで最近見つけました。私は、この列挙がこのように書かれていた理由は全くないアイデア(名前は無実を保護するために変更)持っていることを告白しなければなりません。代わりに、単純にそれはと呼ばれるものを使用していますMysteryEnum.values()を呼び出すのでgetValues()メソッドではsun.misc.SharedSecretsの使用

package foo.bar; 

import sun.misc.SharedSecrets; 
import foo.baz.HasAGetValuesMethod; 

public enum MysteryEnum implements HasAGetValuesMethod { 

    THINGY, BOB; 

    @Override 
    public MysteryEnum[] getValues() { 
     return SharedSecrets.getJavaLangAccess().getEnumConstantsShared(MysteryEnum .class); 
    } 
} 

sun.misc.SharedSecretsun.misc.JavaLangAccessという名前のハンドルを取得し、そのを使用してすべての列挙値の配列を取得します。そのクラスのJavadocは、メソッドが何をしているかを示していますが、なぜ多くを見つけることができませんあなたはそれを呼び出すと思います。

これを書いた開発者はもはや周囲にいないので、私は彼に尋ねることはできません。私はとにかく私のチームに尋ねるつもりですが、私は答えが "それがなぜそれをするのかわからないが、それを変えない方がいい"という気持ちがあります。現時点では、私はこれが、values()メソッドが存在することを知らない人の奇妙なケースか、sun.miscライブラリの私の無知が私に他人に明らかなものを見逃す原因になっていると仮定しています。どのようなアイデアのこのコードは、このように書かれたのですか?基本的SharedSecret

答えて

7

このメソッドは、配列を反映またはコピー/クローニングすることなく同じ配列を返します。これによりパフォーマンスは向上しますが、可変配列を公開することはお勧めできません。

for (int i = 0; i < 3; i++) 
    System.out.println(SharedSecrets.getJavaLangAccess().getEnumConstantsShared(AccessMode.class)); 
AccessMode[] ams = SharedSecrets.getJavaLangAccess().getEnumConstantsShared(AccessMode.class); 
ams[1] = ams[2]; // don't do this !! 
System.out.println(EnumSet.allOf(AccessMode.class)); 

プリント

[Ljava.nio.file.AccessMode;@330cdec1 
[Ljava.nio.file.AccessMode;@330cdec1 
[Ljava.nio.file.AccessMode;@330cdec1 
[READ, EXECUTE, EXECUTE] 

の代わりにこの方法を使用して、私がやっていることは、私はそれを得ることはありません私自身のキャッシュされたコピー

// cannot be modified. 
private static final AccessMode[] ACCESS_MODES = AccessMode.values(); 
+0

私は参照してください。だからそれはパフォーマンスのハックだ。それの外観では、かなり脆いものです。 – Jon

+0

'sun。*'の下では、それを避けるために十分注意してください。 'sun.misc.Unsafe'に似ています;) –

+0

値を調べると、values()メソッドが実際にコンパイラによって追加されたように見えます(Javadoc for Enumにはありません)。そうであれば、どのように最適化されているかをどのように確認できますか?おそらくコンパイラは、値が呼ばれる場所のどこでも同じ配列へのハンドルを返すように最適化されていますか?これをチェックする方法はありますか? – Jon

3

反射を使用して、別のパッケージに実装プライベートメソッドを呼び出すことなく ための機構である「共有秘密」のリポジトリ。

このコードは、クラスを読み込み、定数を返すことによって(リフレクションコールを行う必要なしに)列挙型定数を返します。新しい列挙定数が列挙型に追加された場合、getValues()メソッドは追加された列挙型を返します(ショー全体のコードを変更する必要はありません)。

+0

を使用しています。さらに列挙型の値を追加すると、values()を呼び出すと、元の列挙型と一緒に追加された列挙型も取得されます。実装されているように、getValues()はそれを上回っていますか? – Jon

+0

正確な元の値を戻すだけです(クローンやキャッシュを必要としません)。基本的には、JVMスタックをバイパスして直接値を取得する方法です。 –

1

documentationは言う:Classオブジェクトがenum型を表す ていない場合

がenumクラスまたはnullの要素を返します。結果はすべての発信者によってクローン化されずにキャッシュされ、共有されます。

共有配列を提供することを目的としていない限り、その要素のいずれかをnullに設定するか、並べ替えるか、何かを行うことですべてを破ることができない限りvalues()メソッド)、私の推測では、前の開発者の無能さのためにこの行が存在するとも考えられます。

私は単体テストを書いた後、それをvalues()への呼び出しで置き換えて、単体テストが引き続き通過することを確認します。

関連する問題