Scala:如何在为SuperClass声明的Map中插入SubClass而不是Superclass

时间:2016-01-19 12:15:09

标签: scala class

我需要在HashMap中使用已为SuperClass声明的子类。 例如:我创建了一个超类和一个子类。 现在我创建一个抽象类A和一个扩展A的具体类B. A有一个变量myMap,声明为java.util.Map[_ <: Superclass, String]。在B类中,我需要使用myMap,但我需要在myMap中插入SubClass的实例而不是Superclass。下面是解释的代码

abstract class Superclass {
    def foo(value:String): Boolean
}



class Subclass extends Superclass {
    def foo(value:String) = {
        true // or random boolean expression
    }
}

abstract class A {
    var myMap: java.util.Map[_ <: Superclass, String]
    def addToMap(value:String)
}

class B extends A {
    myMap = new java.util.HashMap[Subclass, String]()

    def addToMap(value:String) { 
        val subclass = new SubClass()
        myMap.put(subclass, value) // getting compilation error here
    }
}

如果我尝试在myMap中插入Subclass实例,我会收到以下错误: 类型不匹配; found:需要Subclass.type(带底层类型Subclass):_ $ 2其中type _ $ 2&lt ;:SuperClass

1 个答案:

答案 0 :(得分:2)

如果您可以在此处使用SubClass,则会违反Liskov替换原则:类B应该能够执行A所能完成的所有操作,但在您的示例中,您无法在其SuperClass中填充Map个密钥。

有几种方法,例如您可以参数化AB

abstract class A[S <: Superclass] {
  var myMap: java.util.Map[S, String]

  def addToMap(value: String)
}

class B extends A[Subclass] {

  var myMap:java.util.Map[Subclass, String] = new java.util.HashMap[Subclass, String]()

  def myMap(map: java.util.Map[Subclass, String]) { myMap = map }

  def addToMap(value: String) {
    val subclass = new Subclass()
    myMap.put(subclass, value)
  }
}

类似的解决方案可以使用抽象类型成员:

abstract class A {

  type S <: Superclass

  var myMap: java.util.Map[S, String]

  def addToMap(value: String)
}

class B extends A {

  type S = Subclass

  var myMap: java.util.Map[Subclass, String] = new java.util.HashMap[Subclass, String]()

  def myMap(map: java.util.Map[Subclass, String]) {
    myMap = map
  }

  def addToMap(value: String) {
    val subclass = new Subclass()
    myMap.put(subclass, value)
  }
} 

我不确定,为什么还需要额外的设定器。

一般来说,我认为将var放在抽象类中并不是一个好主意。一个实现细节应该像这样漏出来吗?可能不是。即使需要,你真的必须替换完整的地图吗?如果没有,您可以使用val。或者,您可以使用def构建一个用于添加,删除,查询元素的外观,而不在A中提及地图。