0

JavaとScalaが混在する環境では、パラメーター化されたクラスがあり、equalsとhashCodeを適切にオーバーライドするためにその型パラメーターが必要です。このブログのおかげで、ClassTagを使用して、このメソッドをコーディングし、これが当てはまるかどうかを確認しました。

 class SomeClass[KeyType, ValueType] (arg1: Converter[KeyType], arg2:Converter[ValueType]) {
 // concrete values of KeyType/ValueType not available at construction time

 enforceEqualsHashImpl
 // enforceEqualsHashImpl[KeyType, ValueType] : "error: No ClassTag available for KeyType "

 def enforceEqualsHashImpl[KeyType : ClassTag, ValueType : ClassTag]= {

  def checkEqualsEqualsHash[T](c:Class[T]): Boolean = {

    def checkequals[T](c:Class[T]):Class[_] ={
      val equalsDeclaringClass = c.getMethod( "equals", classOf[Object]).getDeclaringClass();
      if ( classOf[Object].equals( equalsDeclaringClass ) )
        throw new Exception( "HazelIndex7 parametrized by key class" + c + " which does not override equals")
      equalsDeclaringClass
    }

    def checkHash[T](c:Class[T]):Class[_] ={
      val hashCodeDeclaringClass = c.getMethod( "hashCode").getDeclaringClass();
      if ( classOf[Object].equals( hashCodeDeclaringClass ) )
        throw new Exception( "HazelIndex7 parametrized by key class" + c + " which does not override hashCode")
      hashCodeDeclaringClass
    }

    val equalsDeclaringClass = checkequals(c)
    val hashDeclaringClass = checkHash(c)
    val equals = equalsDeclaringClass.equals(hashDeclaringClass)
    if (!equals)
      throw new Exception("Equals in class " + c + " is implemented by "+ equalsDeclaringClass + " but hashCode is implemented by: " + hashDeclaringClass );
    equals
  }

  checkEqualsEqualsHash(classTag[KeyType].runtimeClass)
  checkEqualsEqualsHash(classTag[ValueType].runtimeClass)
}

ただし、この例外が発生します。

 java.lang.NoSuchMethodException:     scala.runtime.Nothing$.equals(scala.runtime.Nothing$)
at java.lang.Class.getMethod(Class.java:1624)

何らかの理由で型パラメーターをClassTag.runtimeClassで解決できないように思われますか?このコードに何か問題がありますか?この例外の原因は何ですか?

また、次のようなことを試しました:

enforceEqualsHashImpl[KeyType, ValueType](classTag[KeyType], classTag[ValueType])
def enforceEqualsHashImpl[KeyType , ValueType ](implicit kc:ClassTag[KeyType],vc:ClassTag[ValueType])= ...

その結果、次のようになりました。

error: No ClassTag available for KeyType
enforceEqualsHashImpl[KeyType, ValueType](classTag[KeyType], classTag[ValueType])    

error: No ClassTag available for ValueType ....

関連する可能性があります:型パラメーターは、型パラメーターの具体的な値ではないコンストラクター引数(arg1 / arg2)によって間接的に推測される必要があることに注意してください。

equals / hashCodeをチェックするためのより良い方法はありますか?

4

1 に答える 1

1

編集:まず第一に、メソッドenforceEqualsHashImplで型パラメーターを宣言するべきではありません。なぜなら、それらはクラスで宣言されたシャドウKeyTypeValueTypeパラメーターであり、これはあなたの意図ではなかったと思います。したがって、メソッドの宣言は次のようになります。

def enforceEqualsHashImpl {
  ...
}

また、内部メソッドのtypeパラメーターTも、私には少し冗長に思えます。

さて、ClassTagsについて:

ClassTagScalaコンパイラーに型パラメーターのsを提供させたい場合は、ある時点で具体的な型パラメーターを指定する必要があります。これは、型パラメーターに関する情報がコンパイル時(型消去)でのみ利用可能であるためです。

例を機能させたい場合はClassTag、クラスにsを渡す必要があります。

class SomeClass[KeyType : ClassTag, ValueType : ClassTag]

そうしないと、メソッド、、enforceEqualsHashImplは、実際のタイプが背後に隠れているかどうかを知ることができない可能性がKeyTypeありValueTypeます。

そしてもちろん、この変更後、クラスはClassTagその型パラメーターにsを必要とするため、次の2つの方法のいずれかでクラスを構築する必要があります。

  • 具体的な型パラメータを渡すことによって(例new SomeClass[String,Integer](keyConv, valueConv)
  • ClassTagがすでに利用可能な場所でそれを行います。たとえば、次のような方法で行います。

    def constructSomeClass[KeyType: ClassTag, ValueType: ClassTag] = 
      new SomeClass[KeyType,ValueType](keyConv, valueConv)
    

    もちろん、この場合constructSomeClassも、具象型パラメーターまたはどこかで、ClassTagsすでに使用可能な場所などで呼び出す必要があります...

したがって、要約すると、型に対して自動的にを使用できるようにする場合は、あるレベルで具体的な型パラメータを指定する必要ClassTagがあります。

もちろん、次のようなオブジェクトClassTagから手動でを作成することもできます。Class

val classTag = ClassTag(classOf[String])

したがって、構築時にのランタイムクラスがKeyTypeあり、利用可能である場合は、次のようなことができます。ValueTypeSomeClass

def constructSomeClass[KeyType,ValueType](keyClass: Class[KeyType], valueClass: Class[ValueType]) = 
  new SomeClass[KeyType,ValueType](keyConv, valueConv)(ClassTag(keyClass), ClassTag(valueClass))

Classもちろん、これはsの代わりにオブジェクト自体を渡すこととほぼ同じClassTagです。

于 2013-03-02T13:20:42.950 に答える