Интеграция scala с java

Я новичок в Scala. Мне нужна помощь в решении этой проблемы.
Я создал проект, написанный на Scala, и я Я пытаюсь интегрировать его с проектом Java. Я взял зависимость от сборки scala jar в своем проекте Java в eclipse. Однако, когда я вызываю метод в банке Scala, я получаю ClassCastException при запуске приложения:

Ниже приведено исключение, которое я получаю

Исключение в потоке "main" java.lang.ClassCastException: com.rockymadden.stringmetric.phonetic.MetaphoneAlgorithm не может быть приведен к com.rockymadden.stringmetric.StringFilter в com.rockymadden.stringmetric.phonetic.MetaphoneAlgorithm.compute(MetaphoneAlgorithm.scala:10 ) на org.gobe.search.dictionary.test.PhoneticTest.main(PhoneticTest.java:16)

Что я могу сделать, чтобы исправить это?

public static void main(String[] args) {
    MetaphoneMetric metric = new MetaphoneMetric();
    DummyImplicit di = new DummyImplicit();
    MetaphoneAlgorithm algo = new MetaphoneAlgorithm();
    char[] rr = {'h', 'e', 'l', 'l', 'o'};
    System.out.println(algo.compute(rr, di));
}

В приведенном выше коде «MetaphoneMetric», «DummyImplicit» являются частью сгенерированного мной Scala Jar.
Логику алгоритма Metaphone можно найти по адресу http://pastebin.com/d7CXjDtx


person Bourne    schedule 29.07.2013    source источник
comment
Что я могу сделать, чтобы исправить это?   -  person Bourne    schedule 29.07.2013
comment
Покажите нам логику метода MetaphoneAlgorithm.compute (особенно строку 10). Вы там неправильно выполняете приведение, видимо.   -  person Andrzej Doyle    schedule 29.07.2013
comment
Пожалуйста, ознакомьтесь с логикой MetaphoneAlgorithm.compute() по ссылке pastebin pastebin.com/Dgkb7rQz.   -  person Bourne    schedule 29.07.2013
comment
Между прочим, работа с полнофункциональными scala-классами из java — это не то же самое, что и наоборот. Также в вставляемом коде нет класса MetaphoneAlgorithm, это object.   -  person dmitry    schedule 29.07.2013
comment
Моя вина. Я вставил неправильный код. Вот ссылка на правильный код pastebin.com/d7CXjDtx. Что я могу сделать, чтобы решить эту проблему?   -  person Bourne    schedule 29.07.2013


Ответы (3)


Пожалуйста, проверьте это:

Predef.DummyImplicit di = new Predef.DummyImplicit();
MetaphoneAlgorithm algo = MetaphoneAlgorithm.apply();
char[] rr = {'h', 'e', 'l', 'l', 'o'};
System.out.println(Arrays.toString(algo.compute(rr, di).get()));
person aim    schedule 29.07.2013
comment
Это работает. Благодаря тонну. не могли бы вы объяснить, почему приведенный выше код работает и что я делал неправильно? - person Bourne; 29.07.2013
comment
Мы просто создаем реализацию по умолчанию MetaphoneAlgorithm with StringFilter, как описано выше. См. это. - person aim; 29.07.2013

Глядя на код, ваш MetaphoneAlgorithm определяется как:

class MetaphoneAlgorithm extends StringAlgorithm[...] { this: StringFilter =>
 ...
}

Важно this: StringFilter =>. Поскольку StringAlgorithm еще не реализует StringFilter, необходимо смешать этот собственный тип для создания MetaphoneAlgorithm.

В scala вы бы сделали:

val algo = new MetaphoneAlgorithm with StringFilter

Изменить: как ответил @aim, это именно то, что возвращает MetaphoneAlgorithm.apply(). Это, вероятно, то, что вы хотите.

Или вы должны создать новый класс:

class MyAlgo extends MetaphoneAlgorithm with StringFilter

// and then
val algo = new MyAlgo

Если вы хотите иметь возможность создать MetaphoneAlgorithm with StringFilter на стороне Java:

Глядя на вашу черту StringFilter, это должен быть интерфейс на стороне Java.

Изменить. К сожалению, StringFilter будет преобразован в абстрактный класс. Способ обеспечить совместимость с java состоит в том, чтобы сделать StringFilter полностью абстрактным:

trait StringFilter extends Filter[String] with StringFilterable {
  override def filter(charArray: Array[Char]): Array[Char]
}

А также трейт Filter, а затем определить MetaphoneAlgorithm.apply() как возвращаемый:

def apply(): MetaphoneAlgorithm = new MetaphoneAlgorithm with StringFilter
  with DefaultStringFilter

при этом DefaultStringFilter является вашей реализацией по умолчанию StringFilter (та, что в настоящее время находится в StringFilter, которая также реализует метод, определенный в Filter).

С этим изменением это становится возможным на стороне Java:

public class MyAlgo extends MetaphoneAlgorithm implements StringFilter {
  /* implement StringFilter here */
}

А затем создайте его в своем методе main.

Это немного запутанно, но это позволяет вам определять собственные реализации StringFilter на стороне java.


Само сообщение об ошибке происходит от приведения (ненаписанного) this к StringFilter, поэтому я могу понять, почему эта ошибка удивительна.

В качестве примечания интересно, что он позволяет вам напрямую создавать экземпляр класса MetaphoneAlgorithm, учитывая, что он не может работать. Я не уверен, что это можно предотвратить, но это еще одна интересная проблема совместимости scala/java.

person gourlaysama    schedule 29.07.2013
comment
Мне было бы интересно посмотреть, работает ли это последнее предложение. Я согласен с тем, что StringFilter будет компилироваться в стандартный интерфейс, но я не знаю, предполагает ли самонабор что-то большее, чем просто приведение экземпляра this. - person Andrzej Doyle; 29.07.2013
comment
Я недостаточно внимательно посмотрел на StringFilter. У него есть реализация, и (что еще хуже) он наследуется от трейта, у которого есть реализация (Filter[A]). Так что это невозможно как есть, но это можно сделать возможным, см. редактирование. - person gourlaysama; 29.07.2013
comment
Снизится ли производительность, если я буду использовать библиотеку Scala вместо библиотеки Java? Под ударом производительности я подразумеваю пространство выполнения и временную сложность? - person Bourne; 29.07.2013
comment
@bourne: если вы имеете в виду какую-либо разницу между использованием этой библиотеки Scala из Scala и из Java, ответ - нет. В этом весь смысл работы на общей платформе (JVM). Если вы имеете в виду использование этой библиотеки Scala по сравнению с другой библиотекой Java, то я не могу сказать больше, чем это зависит. - person gourlaysama; 29.07.2013

Вы определили MetaphoneAlgorithm с аннотацией собственного типа:

class MetaphoneAlgorithm { this: StringFilter =>

Это означает, что класс нельзя использовать, если к нему не примешана черта StringFilter (например, new MetaphoneAlgorithm() with MyCoolStringFilter).

Поскольку вы не делаете этого в своем примере, где вы просто строите простой MetaphoneAlgorithm, код недействителен. Scalac позволил бы это скомпилировать, но компилятор Java не понимает аннотаций Scala, объясняющих, почему это не сработает, поэтому вы получаете ошибку во время выполнения.

И на самом деле я не думаю, что это вообще возможно сделать в чистом Java-коде, поскольку вы не можете создать анонимный класс, который смешивается с типажом*. Если вы собираетесь использовать классы Scala в Java, имеет смысл подумать о том, какой интерфейс вы хотите, чтобы пользователи Java вызывали, а затем убедиться, что вы не делаете с ним ничего слишком Scala-y.

*Ну, я полагаю, вы, вероятно, могли бы, если бы у вас действительно была мотивация, но вам нужно было бы посмотреть, как именно Scala компилирует примеси на уровне байт-кода, а затем попытаться имитировать это. Это было бы ужасно хрупким и не очень стоящим.

person Andrzej Doyle    schedule 29.07.2013