24

Scala の Java jcommander ライブラリを使用しようとしています。Java JCommander クラスには複数のコンストラクタがあります。

 public JCommander(Object object)  
 public JCommander(Object object, ResourceBundle bundle, String... args)   
 public JCommander(Object object, String... args)   

可変引数を取らない最初のコンストラクターを呼び出したいです。私は試した:

jCommander = new JCommander(cmdLineArgs)

エラーが発生します:

error: ambiguous reference to overloaded definition,
both constructor JCommander in class JCommander of type (x$1: Any,x$2: <repeated...>[java.lang.String])com.beust.jcommander.JCommander
and  constructor JCommander in class JCommander of type (x$1: Any)com.beust.jcommander.JCommander
match argument types (com.lasic.CommandLineArgs) and expected result type com.beust.jcommander.JCommander
jCommander = new JCommander(cmdLineArgs)

名前付きパラメーターも使用してみましたが、同じ結果が得られました。

jCommander = new JCommander(`object` = cmdLineArgs)

可変引数を取らないコンストラクターを呼び出したいことを Scala に伝えるにはどうすればよいですか?

Scala 2.8.0 を使用しています。

4

5 に答える 5

18

申し訳ありませんが、これは Java の既知の相互運用性の問題であることがわかりました。この質問チケットを参照してください。私が知っている唯一の回避策は、これらの呼び出しを明確にするためだけに小さな Java クラスを作成することです。

于 2010-07-22T22:50:48.497 に答える
11

私が知っているこの問題の唯一の Scala ソリューションはリフレクションです。

あいまいな方法

Java テスト クラスがあるとします。

public class Ambig {
  public Ambig() {}
  public String say(Object o) { return o.toString(); }
  public String say(Object o, String... ss) { return o.toString()+ss.length; }
}

リフレクションを介してメソッドに直接アクセスできます。

val ambig = new Ambig
val methods = ambig.getClass.getMethods.filter(_.getName == "say")
val wanted = methods.find(_.getParameterTypes.length == 1).get
wanted.invoke(ambig, Some(5)).asInstanceOf[String]

または、構造型 (ボンネットの下で反射を使用する) を使用して、ボイラープレートを減らして同じことを実現できます。

def sayer(speaker: { def say(o: Object): String }, o: Object) = speaker.say(o)
sayer(new Ambig, Some(5))

あいまいなコンストラクター

私たちの戦略は、実際にはそもそもオブジェクトを持っていないため、異なる必要があります。Javaクラスがあるとしましょう

public class Ambig2 {
  public final String say;
  public Ambig2(Object o) { say = o.toString(); }
  public Ambig2(Object o, String... ss) { say = o.toString()+ss.length; }
}

構造型のアプローチは機能しなくなりましたが、リフレクションは引き続き使用できます。

val mkAmbig2 = classOf[Ambig2].getConstructors.filter(_.getParameterTypes.length==1)
val ambig = mkAmbig2.head.newInstance(Some(5)).asInstanceOf[Ambig2]
ambig.say   // Some(5)
于 2011-06-02T17:51:06.680 に答える
5

あなたの最も簡単なオプションは、問題を橋渡しするファクトリメソッドを持つJavaクラスを持つことだと思います:

package com.beust.jcommander;

public class JCommanderFactory {
    public static createWithArgs(Object cmdLineArgs) {
        return new JCommander(cmdLineArgs);
    }
}

または、代わりにhttp://jewelcli.sourceforge.net/usage.htmlを使用することもできます。JewelCli には、同じ目的のための明確なファクトリ メソッドがあり、PICA (注釈を使用して構成されたプロキシ インターフェイス) 手法も使用しています http://www.devx.com/Java/Article/42492/1954

実際、Scala で JewelCLI を使用する例が Stack Overflow にあります。

于 2010-07-23T00:06:15.420 に答える
2

このあいまいさを回避する方法は、Scala のコレクション展開構文を使用してシングルトン コレクションを渡すことで、複数の引数を取るオーバーロードをコンパイラに強制的に選択させることです。

import java.util.stream.Stream
val stream = Stream.of(List(1):_*)
于 2018-05-14T17:35:46.843 に答える