8

class内部メソッドとしていくつかのオブジェクトを持っています。

私も少し前にこの質問をして良い答えを得ましたが、それはサーブレットコンテナで致命的なエラーにつながります。Scala は、 がクラスを要求するTypeTagときに一貫して を生成できません。URLClassLoader

問題のプロジェクトはオープンソースで、ここにあります。

現在のアプローチはこちらにありますが、順序は保持されません。オブジェクト メンバーは正しく初期化されますが、順序はランダムです。

質問: どうすればクラス メンバーを集めることができますか :

  • 定義されている順序で
  • スレッドセーフな方法で
  • それらをスーパータイプでフィルタリングします
  • オブジェクトを貪欲に初期化します(参照module.instance)?

更新

  • ここのリンクに基づいて回答を提案しないでください。これらはテスト済みで、失敗することがわかっています。
  • 文体上の理由から、val代わりにa を使用することはできません。object
  • getMethodsまたはgetDeclaredFields順序を保証しないことが知られています。これが何らかの方法で可能である場合、Scala リフレクションを使用している可能性があります。
4

4 に答える 4

5

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getDeclaredFields()から:

public Field[] getDeclaredFields() は SecurityException をスローします

この Class オブジェクトによって表されるクラスまたはインターフェイスによって宣言されたすべてのフィールドを反映する Field オブジェクトの配列を返します。これには、パブリック、保護、デフォルト (パッケージ) アクセス、およびプライベート フィールドが含まれますが、継承されたフィールドは除外されます。返される配列の要素はソートされておらず、特定の順序でもありません。クラスまたはインターフェイスがフィールドを宣言しない場合、またはこの Class オブジェクトがプリミティブ型、配列クラス、または void を表す場合、このメソッドは長さ 0 の配列を返します。Java 言語仕様のセクション 8.2 および 8.3 を参照してください。

(私の強調)。同様の言語は、getDeclaredMethods() のドキュメントに明示的に記載されていますが、getDeclaredClasses() のドキュメントには明示的に記載されていません (ただし、IMO はそこで暗黙的であると見なすことができます)。

いいえ、JVM 上の Java リフレクションからの順序付けに依存することはできません。実際には、実行中の JVM のアーキテクチャ (32 ビット対 64 ビット) によって順序が異なることがわかりました。

特定の順序でオブジェクトを初期化する必要がある場合 (なぜですか?)、命名規則を使用して手動で並べ替えることができます。ただし、コードを順序に依存しないように変更した方がよいでしょう。

アップデート

Scala リフレクション API から何かを取得できるようです。

trait EarlyInit {
  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val reflection  = mirror.reflect(this)

  mirror
    .classSymbol(this.getClass)
    .toType
    .members
    .sorted    /// This method is documented to return members "in declaration order"
    .filter(_.isModule)
    .foreach(m => reflection.reflectModule(m.asModule).instance)
  }
}

API ドキュメントを参照してください。

このスコープに含まれるシンボルを次のように並べ替えます。1) シンボルは所有者の線形化順に表示されます。2) 所有者が同じシンボルは、同じ宣言順序で表示されます。3) 合成メンバー (vals/vars の getter/setter など) は、任意の順序で表示される場合があります。

ただし、これは一般的に、特に Java/Scala が混在するプロジェクトでは機能するとは限りません (Java クラスのメンバーを宣言順に取得する方法は実際には存在しないため)。また、Scala のランタイム リフレクションはスレッド セーフではなく、一般に本番環境に対応しているとは見なされないことに注意してください。

おそらく依存関係を別の方法でエンコードすることにより、順序に依存しないように設計を変更することで、より良いサービスが提供されると私はまだ感じています。

于 2014-03-18T11:46:51.243 に答える
0

objectいくつかの内部sを持つクラスがあります。あなたが示すように、内部オブジェクトは、他のコードがそれらを参照/呼び出すときに遅延初期化lazy valされます(同様に)。

問題: (a) 前述の遅延初期化と、(b)オブジェクト定義間の暗黙の相互依存。これは、依存チェーンの順序で初期化する必要があることを意味しますが、相互に明示的に参照しないため、正しく順序付けされた遅延初期化は自動的には行われません。

試行された解決策:構築/初期化フェーズでリフレクションを使用して、プログラムでこれらのオブジェクトを正しい順序で事前に初期化します。これは、scala または Java リフレクションが機能する場合に機能しますが、「穀物に反する」-内部オブジェクトの定義そのものに反して機能します。それらを遅延初期化したくない場合、そもそもなぜそれらを内部オブジェクトとして宣言するのでしょうか?

私の提案する解決策: 宣言を inner objects からvals に変更します。必要な初期化シーケンスに従って、これらの宣言を並べ替えます。反省は不要です。

(余談: この Q と関連するものでは、人為的な制約や s を使用する必要がある理由について言及していませんobject。ただし、オブジェクトを使用する必要がある何らかの奇妙な理由がある場合でも、リフレクションを回避できます。単純にそれぞれを使用しますオブジェクトのコンストラクターは、forceInitそれが依存する各オブジェクトのメソッドを呼び出します。各forceInitメソッドは単に 1 を返すことができます。これにより、正しい順序で遅延初期化がトリガーされます。)

:-)

于 2014-03-20T06:36:48.987 に答える
0

私は同様の問題に遭遇し、何らかの値を持つ注釈を使用して順序を強制しました。特に、私のオブジェクト モデルは SWT テーブルを駆動するため、以下を作成しました。

public @interface DefaultColumnPosition {
    int value();
}

@DefaultColumnPosition(0)次に、フィールドにまたは番号が何であれ注釈を付けます。値で並べ替えます。少しのオーバーヘッドがあり、別のメソッド、または順序を強制するクラス レベルの注釈があった方がよいでしょうが、そのようには見えません。

Scala ソリューションを試したことはありませんが、これも面白そうです。試してみるかもしれません。

于 2016-03-09T18:46:19.263 に答える