11

Java はオブジェクト指向でタイプセーフであると主張しており、Scala はそれ以上です。

内部クラス フィールドは、Reflection API を介して参照を取得できる Field と呼ばれるクラスによって表されます。

私の質問: これらの言語は、その Field 参照をタイプセーフな方法で取得する方法を提供していますか? (そして、もしそうでなければ、なぜ地球上ではないのですか? 明らかな欠陥のようです)

Object を何らかの外部表現 (テンプレートの html フィールドやデータベースの列名など) にマッピングして、参照名を自動的に同期させる場合に非常に便利です。

理想的には、次のようなことを言いたいです。

&(SomeClass.someField).name() 

フィールド宣言の名前を取得するには、Java 列挙型で次のように言います。

MyEnum.SOME_INSTANCE.name()

[更新:] この機能が Reflection API の意図に何らかの形で違反するというフィードバックを読んだ後、Reflection はコンパイル時に未知のもののために設計されていることに同意します。コンパイル時にわかっていること、つまりコンパイルしているまさにそのクラスのフィールドを学びます!

コンパイラはこれを列挙型に提供するため、コンパイラが列挙型フィールドの参照にアクセスして MyEnum.SOME_INSTANCE.name() を許可できる場合、これと同じ機能を通常のクラスにも提供できない論理的な理由はありません。 .

この機能が通常のクラスに存在しない技術的な理由はありますか? なぜそうしないのかわかりませんが、この機能が物事を「複雑にする」ことに同意しません...逆に、現在の面倒なReflection APIテクニックを大幅に簡素化します。開発者に、コンパイル時にわかっていることを見つけるために、なぜ Reflection を強制するのでしょうか?

[更新 #2] この機能の有用性についてですが、JPA または Hibernate で Criteria API を使用してクエリを動的に構築しようとしたことがありますか? クエリ対象のフィールドの安全でない文字列表現を渡さなくて済むようにするために人々が思いついたばかげた回避策を見たことがありますか?

[更新 #3] 最後に、Ceylon と呼ばれる新しい JVM 言語がこの要求に注意を払い、これを簡単に実行できるようにしました。

4

6 に答える 6

6

私の質問: これらの言語は、その Field 参照をタイプセーフな方法で取得する方法を提供していますか?

コンパイル時のタイプセーフ? 少なくともJavaでは、私が知っているわけではありません。Java でのリフレクションの通常の目的は、コードが事前に認識していない型を処理できるようにすることです。(私の経験では)フィールドを参照できるようにしたい状況になることはめったにありません。既知のタイプ。それ起こりますが、あまり一般的ではありません。

(そして、もしそうでなければ、なぜ地球上ではないのですか? 明らかな欠陥のようです)

すべての機能は、設計、実装、テストする必要があり、言語の複雑さを超える価値を提供するバランスを満たす必要があります。

個人的には、これよりも Java で見たいと思う機能を思いつくことができます。

于 2012-03-24T21:36:03.090 に答える
5

残念なことに、Java にはまだこの機能がありません。この機能は、言語の他の側面に干渉するため、複雑さを増すことはありません。さらに、めったに使用されない機能であることは言い訳にはなりません。すべての言語には機能が満載で、ほとんどのプロジェクトはそれらの小さなサブセットを利用しています。

言語でこれができる理由が本当にわかりません:

フィールド field = MyClass.class.getField("myField"); // 詳細な構文、実行時に評価、タイプ セーフではない、リフレクティブ操作の例外を処理する必要がある

しかし、それは私にこれをさせません(次のようなこと):

フィールド field = MyClass::myField; // コンパクトな構文、コンパイル時に評価、タイプ セーフ、例外なし!

(「::」演算子は単なる提案であり、Java 8 または C++ から借用したものです)

于 2016-11-10T09:58:44.873 に答える
3

Scala 2.11 では、これを使用できます。

object R_ {
  def apply[T](x: (T) => AnyRef): (Class[T], Method) = macro impl
  def impl(c: whitebox.Context)(x: c.Tree) = { import c.universe._
    val q"((${_: TermName}:${a: Type}) => ${_: TermName}.${p: TermName})" = x

    val typeDef = a.typeSymbol
    val propertyDef = p.toString

    q"(classOf[$typeDef], classOf[$typeDef].getMethod($propertyDef))"
  }
}

使用法:

class User(val name: String)

object Test extends App {
  println(R_((a: User) => a.name))
}

結果は次のようになります。

(class mref.User,public java.lang.String mref.User.name())

于 2014-12-23T20:16:59.480 に答える
1

リフレクションを使用する場合、コンパイル時にフィールドのタイプがわからないためです。実行時にクラス情報にアクセスできるようにすることです。もちろん、間違った型を使用すると実行時エラーが発生しますが、それはあまり役に立ちません。

残念ながら、名前を同じに保つのは難しいことですが、通常、型を同じに保つのはさらに難しいため、考えているアプリケーションにとってはおそらく価値がありません。

今のところ、Scala でも Java でも、合理的な努力でやりたいことを実行する方法はありません。Scalaはこの情報をマニフェスト (または別の場所) に追加できますが、現時点ではそうではなく、努力する価値があるかどうかはわかりません。

于 2012-03-24T21:52:05.463 に答える