使用traits增强java类,如何在java字段内部声明trait?

时间:2012-02-07 00:36:45

标签: scala traits

我的目标是使用特征混合来增强现有Java类的内部scala代码。例如,将java.awt.Rectangle.translate(dx,dy)等方法添加到java.awt.geom.Ellipse2D类中。为此,我创建了以下特征:

trait RectangleLike {
  var x: Double  // abstract vals to correspond to java class fields
  var y: Double  //   I need these vars to refer to them inside translate method
  def translate(dx: Double, dy: Double) {
    x = x + dx
    y = y + dy
  }
  // more concrete trait methods here
} // defines without errors in scala REPL 

然后在构造椭圆时使用特征:

val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike

但是当我在scala REPL中执行上面的脚本时,我得到以下输出:

<console>:8: error: overriding variable x in trait RectangleLike of type Double;
variable x in class Double of type Double has incompatible type;
other members with override errors are: y
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike

我怀疑这个错误是由于Scala实现变量的方式 - 作为私有字段和getter / setter方法对。我努力实现的目标是什么?是否有另一种方法可以在特征中定义java类字段,然后在具体的特征方法中引用它们?

提前致谢 杰克迪马斯

2 个答案:

答案 0 :(得分:8)

是的,它是可行的,但不是试图访问你想要混合的类的私有字段(这很可能是一个坏主意),你会想要声明{{1的自我类型成为RectangleLike,以便你可以使用你的特质java.awt.geom.RectangularShapeEllipse2D.Double一样。

以下是它的工作原理:

Rectangle2D.Double

通过说trait RectangleLike { self: java.awt.geom.RectangularShape => def translate(dx: Double, dy: Double) { setFrame(getX + dx, getY + dy, getX + getWidth, getY + getHeight) } } object Test { val foo = new java.awt.geom.Ellipse2D.Double with RectangleLike } 你声明你的特质的自我类型,它允许你访问所有相应的方法,如必要的getter和setter,允许你使用你的特征self: java.awt.geom.RectangularShape =>的所有后代,和也“限制”你的特性,使它只能作为一个混合使用,它们本身是RectangularShape的子类型。

上述方案的替代使用了RectangularShape的所谓视图,这也是一种常见的范例。为此,您可以例如声明一个类

RectangularShape

Scala有一种隐式查看一种类型的对象作为另一种类型的对象的方法。如果您碰巧在未在相应类型中声明的对象上调用方法,则编译器会尝试查找提供此方法的类型,特别是还可以尝试查找隐式转换,以便可以将原始对象视为后一种类型的实例。为此,您通常会将class RichRectangularShape(shape: java.awt.geom.RectangularShape) { def translate(dx: Double, dy: Double) { shape.setFrame(shape.getX + dx, shape.getY + dy, shape.getX + shape.getWidth, shape.getY + shape.getHeight) } } 的伴随对象声明为:

RichRectangularShape

然后:

object RichRectangularShape {
  implicit def mkRRS(shape: java.awt.geom.RectangularShape): RichRectangularShape =
    new RichRectangularShape(shape)
}

答案 1 :(得分:0)

确实令人印象深刻的解释和例子!

我对这种方法有一个小问题,translate方法包括我想避免的实际计算。是的,在这种情况下它很简单,但一般来说这种方法可能很复杂并导致严重的发展。因此,我建议采用以下方法:

trait RectangleLike extends java.awt.geom.RectangularShape {
    def translate(dx: Int, dy: Int): Unit = {
        val rect = new java.awt.Rectangle
        rect.setRect(getX, getY, getWidth, getHeight)
        rect.translate(dx,dy)
        setFrame(rect.getX, rect.getY, rect.getWidth, rect.getHeight)
      }
}

通过这种方式,我使用原始的translate计算。