Использование универсального класса Java с необработанными типами в Scala

Я хочу использовать библиотеку Java в своей программе Scala. Библиотека содержит общий класс, который является частью других классов:

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] для хранения идентификаторов со счетчиком:

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)})
  )
}

Я не знаю, какой тип передать конструктору хэш-карты (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?


person Alex    schedule 02.03.2015    source источник
comment
Какие бывают типы r.getItemsets и itemset.getItems? Каковы параметры метода, в котором находится ваш код Scala?   -  person Dan Getz    schedule 02.03.2015
comment
T недоступен из моего объекта Scala - звучит как проблема с дженериками, а не проблема конкретно в Scala. Сможете ли вы написать рабочий метод на Java?   -  person user253751    schedule 02.03.2015
comment
r.getItemsets — это список наборов элементов, а itemset.getItems — список элементов.   -  person Alex    schedule 02.03.2015
comment
@Alex, мы говорим о полиморфизме и дженериках, поэтому важным будет фактический тип возвращаемого значения (включая дженерики) этих методов. В любом случае, я вижу, что вы используете необработанные типы в своем Java-коде. Вы никогда не должны делать это в новом коде. См. stackoverflow.com/q/2770321/3004881.   -  person Dan Getz    schedule 03.03.2015
comment
@Dan, я добавил код методов, как вы можете видеть, нет параметра типа для возвращаемого типа этих методов (последовательность классов, набор элементов). Должен ли я иметь параметр типа для класса последовательности и набора элементов? Кстати, код Java не мой, он взят из внешней библиотеки, поэтому я бы предпочел не менять его.   -  person Alex    schedule 03.03.2015
comment
@Alex Алекс, вопрос, который я связал, объясняет, почему вы не должны использовать необработанные типы и каковы альтернативы. Кстати, ошибка, которую вы опубликовали, и код, который вы разместили, не совпадают: в коде вы называете itemCounts.getOrElse(item.getId.toString, 0), а в вашей ошибке это itemCounts.getOrElse(item.getId, 0).   -  person Dan Getz    schedule 03.03.2015
comment
Какой тип вызывается sortBy и/или каким должен быть возвращаемый тип sortBy?   -  person Dan Getz    schedule 03.03.2015
comment
@Dan: Плохо, я смешал c / p между двумя попытками, я отредактировал свой код и добавил кое-что. Результатом моей функции является набор кортежей, которые я транслирую по своему кластеру. По сути, это список моих элементов, проиндексированных по рангу их частоты в каждой последовательности (ItemId, Rank). .sortBy выполняется для ленивой распределенной коллекции кортежей (RDD) и выводит тот же тип.   -  person Alex    schedule 03.03.2015


Ответы (2)


Я закодировал базовый сценарий, связанный с вашей проблемой, такой проблемы не было. Без дополнительной информации с вашей стороны трудно сказать, что именно идет не так, в частности, весь объект, в котором встречается код scala. Как минимум заголовок метода, в котором встречается ваш опубликованный код, поэтому мы можем проверить все типы. Но вот то, что я написал, кажется, работает, может быть, что-то здесь решит вашу проблему:

Класс Java с дженериками:

package javaCompat;

public class Item<T> {

    public final T id;

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

Код Scala, использующий общий класс Java:

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
  }
}
person Mshnik    schedule 02.03.2015

Частичное решение (без возможности сортировки идентификаторов)

Если у вас есть хоть какой-то контроль над кодом Java, вам не следует никогда использовать необработанные типы, такие как Item в List<Item>, если их можно избежать. См. ответ на этот вопрос для получения дополнительной информации.

Если вы не можете исправить код Java, то item.getId вернет объект неизвестного типа, что приведет к ошибке, которую вы видели. Вы почти нашли решение этой проблемы, когда попытались рассматривать ее как AnyRef. Дело в том, что AnyRef не является базовым типом всех типов в Scala. Any есть. AnyRef — это базовый тип всех типов, которые могут быть null, но есть типы, которые не могут быть null, например, Int. Так что часть вашего кода должна работать, если вы определите itemCounts следующим образом:

val itemCounts = new HashMap[Any, Int]

Если вы хотите, чтобы тип ключа itemCounts был чем-то конкретным, что, как вы знаете, является супертипом всех идентификаторов элементов, вам нужно будет привести с asInstanceOf либо элементы:

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

или идентификаторы:

val castedId = item.getId.asInstanceOf[Integer]
val castedId = item.getId.asInstanceOf[AnyRef]
person Dan Getz    schedule 03.03.2015
comment
О верно. Начнем с того, что класс Java расширил Comparable неправильным образом. Вы уверены, что библиотека Java не с открытым исходным кодом или не от людей, которых вы знаете? Вы уверены, что тип идентификаторов не может быть известен при вызове функции? - person Dan Getz; 03.03.2015
comment
библиотека gpl, поэтому я могу в конечном итоге изменить ее (если это так), поэтому, если у вас есть какие-то рекомендации по улучшению кода... id должен быть строковым или Int, но я хотел не беспокоиться о типе. Я не понимаю, что вы, мужчины, с помощью Java-класса неправильно расширили Comparable? - person Alex; 03.03.2015
comment
Я имел в виду неправильное использование дженериков: Item<T extends Comparable> implements Comparable<Item> должно было быть Item<T extends Comparable<T>> implements Comparable<Item<T>> - person Dan Getz; 03.03.2015