13

プログラムをプラグインしようとしたときにポップアップしたものがわからないという奇妙な問題があります。追加の問題は、試してみるたびに機能するため、簡単なテストケースを作成できないことです。私が見逃しているいくつかの合併症があるに違いありません。ただし、誰かに馴染みがあるように思われる場合に備えて、状況をできるだけ明確に説明するようにします。

メインアプリケーションの一部であり、システムクラスローダーによってロードされるSeedという基本クラスがあります。SeedのサブクラスであるクラスRoadを含むプラグインがあります。実行時に別のjarファイルからロードされます。クラスRoadは、次のように定義されているフィールドSeed.gardenを参照します。

保護された最終的な庭の庭;

コンパイルエラーが発生しないことに注意してください。プラグインjarがシステムクラスパスに含まれている場合も、ランタイムエラーは発生しません。メインアプリケーションが新しいクラスローダー(親としてシステムクラスローダーを持つ)を使用してプラグインをロードした場合にのみ、エラーが発生します。エラーは次のとおりです。

java.lang.IllegalAccessError:クラスpackage.Road$4からフィールドpackage.Seed.gardenにアクセスしようとしました

サブクラスがスーパークラスとは異なるクラスローダーによってロードされているという事実と関係があるはずですが、それが機能しない公式の理由は見つかりません。また、私が言ったように、単純なテストケース(個別のjar、別のクラスローダーでのサブクラスのロードなどを含む)で問題を再現しようとしても、エラーは発生しません。

また、クラスが同じクラスローダーによってロードされたときに機能し、コンパイルエラーが発生しないため、アクセスルールに違反している可能性は低いようです。

アイデアが足りません!誰かがこの問題を認識していますか、または私が見るべき方向へのいくつかの指針を持っていますか?ヘルプ!

4

4 に答える 4

8

OK、それで axtavt と他の回答者の助けを借りて、私は問題が何であるかを理解しました. 他の回答は役に立ちましたが、正確には理解できませんでした。そのため、私は自分の質問に答えています。問題は、 Java 仮想マシン仕様で次のように定義されている「ランタイム パッケージ」の概念であることが判明しました。

5.3 作成とロード

... 実行時に、クラスまたはインターフェースは、その名前だけではなく、その完全修飾名とその定義クラス・ローダーのペアによって決定されます。このような各クラスまたはインターフェイスは、1 つのランタイム パッケージに属します。クラスまたはインターフェースの実行時パッケージは、パッケージ名とクラスまたはインターフェースの定義クラス・ローダーによって決まります。...

5.4.4 アクセス制御

... フィールドまたはメソッド R は、次の条件のいずれかが真である場合にのみ、クラスまたはインターフェイス D からアクセスできます: ...

  • R は保護され、クラス C で宣言されており、D は C のサブクラスまたは C 自体のいずれかです。
  • R は、保護またはパッケージ プライベート (つまり、パブリック、プロテクト、またはプライベートのいずれでもない) のいずれかであり、D と同じランタイム パッケージ内のクラスによって宣言されます。

最初の節は、Road が Seed.garden へのアクセスを許可される理由を説明します。なぜなら、Road は Seed のサブクラスであるためです。別のクラスローダーによってロードされた、同じランタイムパッケージ内。この制限は実際には Java 言語の制限ではなく、Java VM の制限です。

したがって、私の状況の結論は、Java VM の正当な制限が原因で例外が発生するということです。おそらくフィールドをパブリックにすることで、この問題を回避する必要があります。最終的なものであり、秘密ではありません。または、アクセス権を持つ Road を介して Seed.garden を Road$4 にエクスポートすることもできます。

皆さんの提案と回答に感謝します!

于 2012-05-06T11:45:58.907 に答える
4

2 つの異なるクラス ローダーがクラス階層などで同じクラスをロードしているという、クラス アイデンティティの危機があるようです。Java クラスローダーについていくつか読んでください。「クラスアイデンティティの危機」については、図2を参照してください。 http://www.ibm.com/developerworks/java/library/j-dyn0429/

于 2012-05-05T20:48:33.600 に答える
1

Road$4 は Road の匿名内部クラスであることを付け加えておきます...

1998 年には、他の誰かがこれもバグだと考えていました。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4116802

内部クラスは、最上位クラスよりも別のクラスのメンバーにアクセスできません。ただし、囲んでいる、囲まれている、または兄弟クラス内で宣言されているメンバーは除きます。内部クラスが、それを囲むクラスの継承されたメンバーに無制限にアクセスできるというのはよくある誤解です。本当じゃない。

これはもともと Java 1.2 に対して報告されたものであるため、おそらくその事実をもう少し調査したいと思いますが、私の読書から、これは今日も真実であることを覚えているようです。

編集:

私はこれが真実であることを確認しました:

http://docs.oracle.com/javase/tutorial/java/javaOO/summarynested.html

匿名内部クラスのスコープは、それが定義されているポイントのみです。したがって、外部クラスがアクセスしたとしても、継承されたメンバーにアクセスすることはできません。

于 2012-05-05T21:48:15.240 に答える
0

これはパーミッション エラーであるため、ランタイムの実行に使用するフレームワークによって異なります。これが実際にこれであることを明確にするために、親メンバーを公開してから実行してみてください。すべてが問題ない場合は、コードを復元します。使用するランタイムに応じて、正しいセキュリティ アクセスを構成する必要があります。

于 2012-05-05T21:33:36.993 に答える