2016-09-17 6 views
1

私は最近、Jake Whartonによってthis articleを読んでいます。これはAndroidを対象にしていますが、Javaについても完全に有効です。我々は(これはAへの参照を有し、そのメンバーをacccessことができる)、単純なクラスAおよび内部クラスBを有するメソッドの可視性とそのコスト

public class A { 

    private String someField = "abc"; 

    class B { 

     public void doSomething() { 
      System.out.println(someField); 
     } 

    } 
} 

は、以下のコードを検討してください。プライベートであっても、クラスBはAのフィールドsomeFieldにアクセスしています。記事によると、これは内部クラスがフィールドにアクセスすることを可能にするsynthetic accessor methodsを生成するコンパイラによって行われます。
私のやり方は基本的な質問です。なぜコンパイラはコードをコンパイルするときに可視性について気にするのですか?この例で見てきたように、基本的にオーバーヘッドを導入する新しいメソッドが生成されます。
可視性は良いソフトウェアを構築する上では大変ですが、宣言されたvisibiliesに基づいてすべてが正しいことをコンパイラがチェックしていれば、それらのメソッドを最適化しないでください(例:すべてをpublicにして呼び出します)。
まず、これはセキュリティ上の理由によるものだと思っていましたが、反射ではすべてのフィールドへのアクセスが許可されています。

これは私の基本的な誤解かもしれません、もしそうなら、誰かが私にそれを説明することができれば嬉しいです。

+1

"コンパイラは、コードがコンパイルされていると、なぜ可視性について気にするのですか?"コードを検証する何かが気になる可能性があります。もちろん、JITコンパイラはメソッド呼び出しをインラインするのにはかなり良い場所にありますが、それは別の問題です。 (リフレクションはセキュリティマネージャーで無効にすることができます - これは*実行時に強制されますが、実際にはコンパイラがいくつかの環境では失敗するコードを生成したくない...) –

答えて

3

なぜコンパイラはコードをコンパイルするときに可視性について気にするのですか?

JVMでは、クラス外のprivateメソッド/コンストラクタ/フィールドにアクセスすることはできません。このルールの設計後に追加されたネストされたクラスには特別なルールはありません。その代わりに、コンパイラはアクセサメソッドを追加するので、言語はJVMにはないアクセス手段をサポートできます。

この例で見てきたように、基本的にオーバーヘッドを導入する新しいメソッドが生成されます。

メソッドがあまり呼び出されず、最適化されていない場合のみ。

最適化しない理由の任意の簡便な方法(ホットスポット、35バイト以下の任意の方法で)非常に迅速にインラインと(最大インラインレベルに達している場合を除く)の性能に影響を与えないであろう

追加それらのメソッドは離れています。

これは実行時にこれを実行するため、以前のルールが引き続き実行されます。

反射では、私が知る限り、視界を気にすることなく、すべてのフィールドにアクセスできます。

デフォルトではありませんが、これをオプションとして明示的に指定し、それを防ぐSecurityManagerは必要ありません。

0

コンパイラがコンパイル時にすべてのプライベートフィールドをパブリックフィールドに変換すると、プロジェクトがライブラリにコンパイルされ、他の人が再利用するときに問題が発生します。その場合、すべてのプライベートフィールドが公開されます。

これを最適化するためのツールがいくつかあります。 Androidには、ProGuardという名前のツールがあり、すべてのgetter/setterを直接フィールドアクセスに変換します。