为什么具有相同构造函数参数类型的case类的scala可序列化性不同



为什么我能序列化这个:

// 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子类的方法:

  • 避免在每个子类中声明类型(如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
  }
}

只是引用Javadoc:

要允许序列化不可序列化类的子类型子类型可能负责保存和恢复状态超类型的public、protected和(如果可访问)包的字段。子类型只有在类它扩展有一个可访问的无参数构造函数来初始化类的状态。声明可序列化的类是错误的事实并非如此。该错误将在运行时检测到。

TypeAware的函数包含隐式形参。

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

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

编辑,更多链接:

科技页面

常见问题解答你的问题

相关内容

  • 没有找到相关文章

最新更新