微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我不能在没有丑陋的匿名类的情况下在Scala中实现这个Java接口

我在 Java中有以下界面

public interface IProperty<T extends Comparable<T>> {
    String getName();

    Collection<T> getAllowedValues();

    Class<T> getValueClass();

    String getName(T value);
}

并试图在scala中实现它,但无法让它工作

第一次尝试:

class EnumerationProperty1[T <: Enumeration](val enum: T,val name: String) extends IProperty[enum.Value] {
  override def getName = name
  override def getValueClass = classOf[enum.Value]
  override def getName(value: enum.Value): String = value.toString
  override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList
}

不编译时出错:找不到:值枚举

第二次尝试:

class EnumerationProperty2[T <: Enumeration](val enum: T,val name: String) extends IProperty[T#Value] {
  override def getName = name
  override def getValueClass = classOf[T#Value]
  override def getName(value: T#Value): String = value.toString
  override def getAllowedValues: java.util.Collection[T#Value] = enum.values.toList
}

不使用Error编译:类型参数[T#Value]不符合特征IProperty的类型参数bounds [T<:Comparable [T]] 最后我找到了一种方法,但它对我来说看起来很难看:

object EnumerationPropertyAnonymous {
  def create[T <: Enumeration](enum: T,name: String) = {
    new IProperty[enum.Value] {
      override def getName = name
      override def getValueClass = classOf[enum.Value]
      override def getName(value: enum.Value): String = value.toString
      override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList
    }
  }
}

问题:

>这样做的正确方法是什么?
>为什么enum.Value在我的第一次尝试中不起作用,但在匿名类中使用时是否有效?
>为什么enum.Value和T#Value不一样?
>为什么编译器会抱怨T#Value与Comparable [T]不匹配,因为Value扩展了Ordered [Value],它扩展了Comparable [Value]?

解决方法

啊,使用路径依赖类型的乐趣……

枚举#Value是路径依赖类型.
这是Value的实际类型取决于Enumeration实现的当前实例.

因此,如果你有两个枚举

object A extends Enumeration {
  val first = Value(0,"first")
}

object B extends Enumeration {
  val first = Value(0,"first")
}

以下条件返回false.

A.first == B.first
A.first.isinstanceOf[B.first.type]

但这是事实

A.first.isinstanceOf[Enumeration#Value]

有关路径相关类型的更多信息,请参阅此article

对于问题:

@ 1)这取决于你想要完成的事情.一个快速方法是与工厂.有点类似于你的“匿名”示例,但有点像scala-ish:

// it is recommended to use converters instead of conversions.
import scala.collection.JavaConverters._

case class EnumPropertyFactory[T <: Enumeration](val enum: T) {
  def apply(name: String) = new EnumerationProperty(name)

  class EnumerationProperty(val name: String) extends IProperty[enum.Value] {
    override def getName = name
    override def getValueClass = classOf[enum.Value]
    override def getName(value: enum.Value): String = value.toString
    override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList.asJavaCollection
  }
}

// can be used with something like
val enum1PropertyFactory = EnumPropertyFactory(EnumOne)
val foo = enum1PropertyFactory("foo")
val bar = enum1PropertyFactory("bar")

@ 2)因为在第一个例子中,enum是一个构造函数参数,在第二个例子中它是一个本地val.记住java中类定义的样子:

class EnumerationProperty1<T extends Enumeration> extends IProperty<enum.Value> {
    public EnumerationProperty1(T enum,String name) { ... }
}

这里很清楚,为什么在调用构造函数之前无法知道枚举.

@ 3)见上文:路径依赖类型

@ 4)我害怕,这有点高于我.但我敢打赌,它与Enumeration#Value有关,因为路径依赖,而voodoo用#;)完成

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐