在Scala中使用Java泛型类和原始类型

时间:2015-03-02 18:17:48

标签: java scala generics raw-types

我想在我的Scala程序中使用Java库。该库包含一个泛型类,它是其他类的一部分:

package java.items;

public class Item<T extends Comparable> implements Comparable<Item> {  
  private T id;
 ...
}

public final class Itemset{
  private List<Item> items = new ArrayList<Item>();
  public List<Item> getItems() { return items; }
 ...
}

public class Sequence {
  private final List<Itemset> itemsets = new ArrayList<Itemset>();
  public List<Itemset> getItemsets() { return itemsets; }
 ...
}

在我的Scala代码中,我遍历不同的对象,需要实例化类型为[T, Int]的散列图,以便用计数器存储ID:

import java.items._

object ConvertSequence {

  def ConvertSequence (dataset: RDD[(Sequence)], sc: SparkContext) {

    sc.broadcast(dataset.flatMap(r => {
      val itemCounts = new HashMap[AnyRef, Int]

      for (itemset <- r.getItemsets) {
        for (item <- itemset.getItems) {
          val i = itemCounts.getOrElse(item.getId, 0)
          itemCounts.update(item.getId, i + 1)
        }
      }
      itemCounts
    }).
    map(r => (r._1, (r._2, 1))).
    reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2)).
    sortBy(r => (r._2._1, r._1))
    zipWithIndex().
    collect({ case (k, v) => (k._1, v)})
  )
}

我不知道要传递给hashmap构造函数的哪个类型(T不能从我的Scala对象获得,因为只键入了Item。 我试过AnyRef但是我在编译时遇到错误:

[ERROR]  error: type mismatch;
[INFO]  found   : ?0
[INFO]  required: AnyRef
[INFO] Note that ?0 is unbounded, which means AnyRef is not a known parent.
[INFO] Such types can participate in value classes, but instances
[INFO] cannot appear in singleton types or in reference comparisons.
[INFO]           val i = itemCounts.getOrElse(item.getId, 0)
[INFO]                                             ^
[ERROR] one error found

如何管理Java和Scala代码之间的多态?

2 个答案:

答案 0 :(得分:0)

我编写了一个涉及您问题的基本方案,没有这样的问题。如果没有关于你的结果的更多信息,很难说出究竟是什么问题 - 特别是scala代码出现的整个对象。至少你发布的代码出现的方法标题,所以我们可以检查所有类型。但这是我写的似乎有用的东西,也许这里的东西会解决你的问题:

带有泛型的Java类:

package javaCompat;

public class Item<T> {

    public final T id;

    public Item(T id){
        this.id = id;
    }
}

使用通用Java类的Scala代码:

import javaCompat.Item
import scala.collection.mutable.HashMap

object Compat {
  def main(args : Array[String]){
    val items = 
          List("A","B","C","D","E","A","B","A","C","E","F","D").map {x => new Item(x)}
    print(labelCount(items))
  }

  def labelCount[T](items : List[Item[T]]) : HashMap[T, Int] = {
    val itemCounts = new HashMap[T, Int]()
    for (item <- items) {
      val i = itemCounts.getOrElse(item.id, 0)
      itemCounts.update(item.id, i + 1)
    }
    itemCounts
  }
}

答案 1 :(得分:0)

部分解决方案(无法对ID进行排序)

如果您对Java代码有任何控制权,那么永远不会使用原始类型,例如Item中的List<Item>,如果它们可以避免的话。有关详细信息,请参阅this question的答案。

如果您无法修复Java代码,那么item.getId将返回未知类型的对象,这会导致您看到的错误。当您尝试将其视为AnyRef时,您几乎找到了解决方案。问题是,AnyRef 不是 Scala中所有类型的基本类型。 Any是。 AnyRef是可以null的所有类型的基本类型,但有些类型不能null,例如Int。因此,如果您按如下方式定义itemCounts,则部分代码应该有效:

val itemCounts = new HashMap[Any, Int]

如果您希望密钥类型itemCounts是特定的,您知道的是所有项目的超类型&#39; ids,您必须使用asInstanceOf投射项目:

val castedItem = item.asInstanceOf[Item[String]]
val castedItem = item.asInstanceOf[Item[AnyRef]]

或ids:

val castedId = item.getId.asInstanceOf[Integer]
val castedId = item.getId.asInstanceOf[AnyRef]