与Java相比,Scala对泛型和通配符有什么机制?

时间:2012-01-18 16:57:55

标签: java generics scala guice type-erasure

我经常通过使用Guice,TypeLiteral,泛型和通配符来推动Java类型系统的限制。我经常遇到需要执行未经检查的强制转换的情况,这几乎破坏了类型安全 - 换句话说,“泛型地狱。”

这是我的一些有问题的Java代码的简化示例。

class SquareDrawer implements ShapeDrawer<Row<Square>> {}
class Client {
   Key<SquareDrawer> SQUARE_DRAWER_KEY = 
      Key.get(SquareDrawer.class, randomAnnotation());
   void bindShapeDrawer(
      Key<? extends ShapeDrawer<Row<? extends Shape>>> shapeDrawer) {}

   Client() {
      // Note Unchecked cast required below
      bindShapeDrawer( 
         (Key<? extends ShapeDrawer<Row<? extends Shape>>>) SQUARE_DRAWER_KEY);
   }
}

我一直在学习Scala,并且一直认为它比Java更能支持泛型。以上代码是否可以用Scala编写以避免未经检查的强制转换?

Scala中仍然需要Guice的TypeLiteral吗?

3 个答案:

答案 0 :(得分:3)

Scala提供了一些东西。

  • 更高级的类型(我希望我正确地使用这个术语)允许你定义诸如“任何类型具有另一种类型作为类型参数”之类的东西afaik没有办法在java中表达

    < / LI>
  • Co和Contravariant类型参数。在java中,您可以通过在使用它们的每个位置使用通配符来创建参数。在Scala中你只需要声明它们。

  • 类型见证(再次:这是正确的术语吗?)是隐式函数,它们演示了类型参数的某些属性,从而定义了对类型的约束。如果存在与见证声明匹配的隐式转换,则调用将编译条件成立。

  • 路径依赖类型。您可以拥有作为实例元素的类型,因此每个实例都有自己的类型。再一次,你不能在java afaik中做到这一点。

答案 1 :(得分:2)

Scala的形式为reified types,称为Manifest。由于类型擦除,它们允许你做一些在Java中非常笨重的事情。在这里阅读所有相关信息:http://www.scala-blogs.org/2008/10/manifests-reified-types.html

答案 2 :(得分:2)

以下(希望)等效的Scala代码编译时没有错误。也许我需要声明它不包含动态转换。请注意,我必须在其类型参数中设置Key协变,因为SquareDrawer只是ShapeDrawer[Row[Square]]的子类型。

trait ShapeDrawer[A]
trait Row[A]
trait Shape
trait Square extends Shape
trait Key[+A]

//your code starts here
trait SquareDrawer extends ShapeDrawer[Row[Square]]

class Client{
  val SDK = new Key[SquareDrawer]{}

  bindShapeDrawer(SDK)

  def bindShapeDrawer[SD[A] <: ShapeDrawer[A],S <: Shape](shapeDrawer: Key[SD[Row[S]]]) {}
}