val led = OutPin(0)
代替:
val led = new OutPin(0)
我在我的Java代码中天真地实现了一个附加的应用方法,如下所示:
public class OutPin { public OutPin(int pinNumber) { } public OutPin apply(int pinNumber) { return new OutPin(pinNumber); } }
这不会使我的Scala代码(上面的第一行)编译,而是给我一个错误:
Object OutPin不是一个值
解决方法
我认为(但不确定)这是非常困难的,甚至是不可能的设计.
考虑一个非常非常简单的情况:
object Obj;
这编译为两个JVM字节码文件Obj $.class和Obj.class.在理论上,应该很容易检查这两个类的字节码,并在Java中重写相同的东西. Scala单身对象的基本结构非常简单:
>对于一个单例对象Obj,必须生成一个Obj.class和Obj $.class
> Obj $类必须有一个类型为Obj $的公共final静态域,称为MODULE $,它将在类初始化时初始化,参考单例对象.在Scala中,调用Obj.foo()被映射到Obj $.MODULE $.foo()[…如果Obj有一个名为foo()的方法,那就是!
> Java编译器不知道这些Scala生成的类对,所以对于Java interop,Obj类包含静态函数,它们只是转发到一个名为Obj $.MODULE $的同名和签名方法的调用.
这听起来很复杂,但实际上并不是那么多.编写一对Java类很简单.但Scala编译器(2.10.3)仍然不会将该对识别为构成Scala单例.潜入到Scala编译器生成的单例的字节码,您将看到有一些在法律Java中难以表达的细节. [提示:javap -c -p -s -v< fully-qualified-class-name>]
例如,最终的静态MODULE $字段由静态初始化程序间接初始化.静态初始化器只是构造一个Obj $对象,而不需要直接赋值.分配发生在私有构造函数内.这在Java中是非法的:空白静态决赛必须在静态初始化程序中进行初始化,并且不能在可能从初始化程序外部多次调用的代码(如私有构造函数)中分配. Scala编译器生成符合空白最终语义的字节码(因为私有构造函数只调用一次),但超出了Java编译器验证这些语义的能力.所以如果用Java表达,这个代码将被拒绝.
此外,Obj类(没有终端美元符号的版本)包含一个类型为ScalaSig的注释,它看起来很复杂,手工难以重现(在Java或Scala中),至少对于我们这些此注释工作.
在决定将一对类视为“价值”之前,我不知道Scala编译器正在寻找什么,这是一个有效的Scala单例对象,但Scala的设计人员选择不使其变得容易,尽管简单基本方案他们可能希望保留重组scala singleton对象如何转换为字节码的能力.让Java程序员合成scala单例对象将有效地使当前的方案成为Scala公共API的永久部分.
注意,编写一个普通的非单例类,其实例具有apply(…)方法等等,可以像Java一样简单的调用函数,并且工作正常.这是一个Java猫:
public class Cat { public String apply( int i ) { return "Meow: " + i; } }
以下是Scala’s sugared的用法:
Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM,Java 1.7.0_45). Type in expressions to have them evaluated. Type :help for more information. scala> val Morris = new Cat; Morris: Cat = Cat@6b4feafa scala> Morris(8) res0: String = Meow: 8