如何在scala中扩展抽象类并使用抽象构造函数

时间:2014-03-12 20:43:46

标签: scala constructor abstract-class default-constructor

我有抽象类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)
}

我有一个扩展这个类的类

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
  }
}

这个类的要点是根据用于实例化它的对象的类类型来实例化一个对象及其变量,但问题是当调用抽象构造函数时,是扩展抽象的对象的默认构造函数对象以某种方式被称为。这会将var s的值更改回null。

这是一个非常简单的类实现,我在B类中有更多变量,在intMethod和stringMethod中有更多逻辑。

我意识到这可能是一种完全错误的做法,所以如果有更好的方法请告诉我。

1 个答案:

答案 0 :(得分:1)

超类的主体总是在子类的主体之前执行。在您的情况下,A首先调用stringMethodintMethod,然后最终执行B的正文,将null分配给s 。如果删除该分配,则应该有效:

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

永远不会,风格有问题。以下是两种选择:

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)
  }
}

或者更好地静态检查:

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