我相信 1 和 2 被编译成相同的字节码(除了在案例 2 中生成的类名)。如果 Fooable 的存在只是为了让您能够将 A 隐式转换为 Fooable(并且您永远不会直接创建和使用 Fooable),那么我会选择选项 2。
但是,如果您控制 A(意味着 A 不是您不能子类化的 java 库类),我会考虑使用 trait 而不是隐式转换来向 A 添加行为。
更新:我必须重新考虑我的答案。我会使用您的代码的变体 1,因为变体 2 原来是使用反射(Linux 上的 scala 2.8.1)。
我编译了这两个版本的相同代码,使用 jd-gui 将它们反编译为 java,结果如下:
具有命名类的源代码
class NamedClass { def Foo : String = "foo" }
object test {
implicit def StrToFooable(a: String) = new NamedClass
def main(args: Array[String]) { println("bar".Foo) }
}
匿名类的源代码
object test {
implicit def StrToFooable(a: String) = new { def Foo : String = "foo" }
def main(args: Array[String]) { println("bar".Foo) }
}
使用 java-gui 编译和反编译为 java。“命名”版本生成一个 NamedClass.class,它被反编译成这个 java:
public class NamedClass
implements ScalaObject
{
public String Foo()
{
return "foo";
}
}
匿名生成一个 test$$anon$1 类,该类被反编译为以下 java
public final class test$$anon$1
{
public String Foo()
{
return "foo";
}
}
几乎相同,除了匿名是“最终的”(他们显然想额外确保你不会不顾一切地尝试和子类化一个匿名类......)
但是在呼叫站点上,我得到了“命名”版本的这个java
public void main(String[] args)
{
Predef..MODULE$.println(StrToFooable("bar").Foo());
}
这是匿名的
public void main(String[] args) {
Object qual1 = StrToFooable("bar"); Object exceptionResult1 = null;
try {
exceptionResult1 = reflMethod$Method1(qual1.getClass()).invoke(qual1, new Object[0]);
Predef..MODULE$.println((String)exceptionResult1);
return;
} catch (InvocationTargetException localInvocationTargetException) {
throw localInvocationTargetException.getCause();
}
}
我用谷歌搜索了一下,发现其他人也报告了同样的事情,但我没有找到更多关于为什么会这样的见解。