How to extend an abstract class in scala and use the abstract constructor

不问归期 提交于 2021-01-29 04:04:52

问题


I have abstract class A

abstract class A{

def this(obj:Object){
  this()
  obj match{
    case s:String => stringMethod(s)
    case n:Int => intMethod(n)
  }

  def stringMethod(s:String)

  def intMethod(n:Int)
}

and I have a class that extends this class

class B(obj:Object) extends A(obj){
  var s:String = null

  def stringMethod(s:String){
    this.s = s
  }

  def intMethod(n:Int){
    this.s = n.toString
  }
}

The point of this class is to instantiate an object and its variables depending on the class type of the object used to instantiate it but the problem is that when the abstract constructor is called, the default constructor of object which is extending the abstract object is somehow being called after. This alters the value of var s back to null.

This a really simple implementation of my classes and I have more variables in class B and more logic inside intMethod and stringMethod.

I realize this might be a completely wrong way of doing this, so if there is a better way please let me know.


回答1:


The body of a super class is always executed before the body of a sub class. In your case A calls stringMethod or intMethod first, then finally B's body is executed, assign null to s. If you remove that assignment, it should work:

abstract class A{
  def this(obj:Object){
    this()
    obj match{
      case s:String => stringMethod(s)
      case n:Int => intMethod(n)
    }
  }

  def stringMethod(s:String)

  def intMethod(n:Int)
}

class B(obj:Object) extends A(obj){
  var s:String = _ // !

  def stringMethod(s:String){
    this.s = s
  }

  def intMethod(n:Int){
    this.s = n.toString
  }
}

val b = new B("foo")
b.s

Neverless, the style is problematic. Here are two alternatives:

trait A {
  def obj: Any
  def s: String
}

class B(val obj: Any) extends A {
  val s = obj match {
    case i: Int    => i.toString
    case x: String => x
    case x         => throw new IllegalArgumentException(x.toString)
  }
}

Or better statically checked:

object B {
  def apply(i: Int   ): B = new B(i, i.toString)
  def apply(s: String): B = new B(s, s)
}
class B private(val obj: Any, val s: String) extends A

B(1.0) // not allowed


来源:https://stackoverflow.com/questions/22363381/how-to-extend-an-abstract-class-in-scala-and-use-the-abstract-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!