3

为什么我能够序列化这个:

// Serialize: OK
case class ClassWithType2[T:TypeTag](x:T)  {
  val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}

...但不是这个

class TypeAware[T:TypeTag]() {
  val tpe:java.lang.reflect.Type = Util.toJavaClass[T]
}

// Serialize: FAIL.
// No valid constructor for ClassWithType1
// in: java.io.ObjectStreamClass.checkDeserialize
case class ClassWithType1[T:TypeTag](x:T) extends TypeAware[T] 

两者似乎都有相同的构造函数类型原型:

[T:TypeTag](x:T)

并且都扩展了 scala.Serializable 和 java.io.Serializable

val s1:Serializable = ClassWithType1(x=123)
val s2:Serializable = ClassWithType2(x=123)
val s3:java.io.Serializable = ClassWithType1(x=123)
val s4:java.io.Serializable = ClassWithType2(x=123)

它有一种实现 TypeAware 子类的方法:

  • 避免必须在每个子类中声明 tpe(就像 ClassWithType2 一样)?
  • 允许对象被序列化

这是测试工具

class TypesTest {

  @Test
  def serializeTypeTest(): Unit = {
    val obj2:Object = ClassWithType2(x=123)
    Util.copyBySerialization(obj2)  // Success!

    val obj1:Object = ClassWithType1(x=123)
    Util.copyBySerialization(obj1) // Fail
  }
}

object Util {
  def toJavaClass[T:TypeTag]: Class[_] = {
    val tpe = typeOf[T]
    runtimeMirror(tpe.getClass.getClassLoader).runtimeClass(tpe.typeSymbol.asClass)
  }

  def copyBySerialization[T](obj: T): T = deserialize(serialize(obj))

  def serialize[T](obj: T): Array[Byte] = {
    val byteOut = new ByteArrayOutputStream()
    val objOut = new ObjectOutputStream(byteOut)
    objOut.writeObject(obj)
    objOut.close()
    byteOut.close()
    byteOut.toByteArray
  }

  def deserialize[T](bytes: Array[Byte]): T = {
    val byteIn = new ByteArrayInputStream(bytes)
    val objIn = new ObjectInputStream(byteIn)
    val obj = objIn.readObject().asInstanceOf[T]
    byteIn.close()
    objIn.close()
    obj
  }

}
4

1 回答 1

3

只是引用Javadoc:

为了允许序列化不可序列化类的子类型,子类型可以负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态。仅当它扩展的类具有可访问的无参数构造函数来初始化类的状态时,子类型才可以承担此责任。如果不是这种情况,则声明类 Serializable 是错误的。将在运行时检测到错误。

TypeAware 的 ctor 包含隐式参数。

编辑:一个想法是使类型标签成为成员。或类似的。它没有节省太多的语法。

abstract class TypeAware {
  protected def tt: TypeTag[_]
  def tpe:java.lang.reflect.Type = Util.toJavaClass(tt)
}

case class ClassWithType1[T](x:T)(implicit val tt: TypeTag[T]) extends TypeAware

编辑,更多 linx:

技术页面

常问问题

你的问题

于 2016-08-18T22:50:24.793 回答