我正在尝试使用Scala中的java jcommander库。 java JCommander类有多个构造函数:
public JCommander(Object object)
public JCommander(Object object, ResourceBundle bundle, String... args)
public JCommander(Object object, String... args)
我想调用第一个带 no varargs的构造函数。我试过了:
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我想调用不接受varargs的构造函数?
我正在使用Scala 2.8.0。
答案 0 :(得分:18)
抱歉,我现在意识到这是Java的已知互操作性问题。请参阅this question和the ticket。我所知道的唯一工作就是创建一个小型Java类来消除这些调用的歧义。
答案 1 :(得分: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)
答案 2 :(得分: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。
实际上我有example of using JewelCLI with Scala here on Stack Overflow。
答案 3 :(得分:1)
The way to avoid this ambiguity is to force the compiler to pick the overload that takes more than one argument, using Scala's collection explosion syntax to pass in a singleton collection:
import java.util.stream.Stream
val stream = Stream.of(List(1):_*)
答案 4 :(得分:0)
您可以使用varags调用构造函数,但传递一个空的varags列表。
(当然,如果您知道用空varags构建JCommander会产生与调用不带变量的重载构造函数(或方法)相同的结果)
jCommander = new JCommander(cmdLineArgs, Nil: _*)