2012-04-13
众所周知,Scala可以使用Java编写的所有类和方法。这是Scala的一个非常重大的优点。由于Scala编写的代码最终也会编译成.class文件,因此理论上Java也可以使用Scala的编写的类和方法。但是因为Scala拥有Java所没有的一些特质,并且在实际编译器处理之后会出现独特的变化,所以Java直接使用Scala编写出来的东西会需要一点额外工作。
1. 变量
我们定义一个简单的Scala类。
class AClass {
val a: Int =1
var b: String ="abc"
}
编译成class文件之后,我们用javap命令查看,如图1所示:
图1 编译后的scala类
我们发现变量消失了,而且还多了几个方法。那我们应该怎么对类里的变量赋值呢?其实很简单,可以赋值的var变量会生成一个新的方法。其命名规则是:void 变量名_$eq(变量类型 参数)。这个就是赋值的方法。而取值的方法就是与变量名同名的函数了(本例的a()和b())。简而言之,scala编译器为我们自动生成了getter和setter。
2. Option类
有时候我们会用到Option打包的对象比如Option[Int]的Some(1)。在Scala中我们可以Some(1)来表示,但如果在Java中我们就不能这样了。本质上Some(1)其实调用的是Option.apply()方法。因此,我们只要使用scala.Option.apply(1)就能得到Some(1)的效果。同样的道理,我们也可以Option.apply("abc")得到Some("abc")的效果。
不过,有一点需要注意的是Option.apply(new Integer(1))可是不能通过编译的。因为Scala并不能将java.lang.Integer直接转化成Int。
3. 参数是函数
Scala是第一类函数语言,对于Scala而言,任何东西都有值,即便是函数也能作为变量进行传递。
我们又定义一个类:
class BClass { def method(i:Int)(param: =>Double)={ val value = param println(i+":"+value) } }
编译成class文件之后,我们用javap命令查看,如图2所示:
图2 BClass转成class的实现
我们可以看到不带参数的函数参数param被转化成了一个scala.Function0类型的参数。因此,如果我们要使用BClass的method方法,我们只要把一个Fucntion0类型的参数传递进去即可。
本例的解决方法:
scala.Function0<Double> func = new scala.runtime.AbstractFunction0<Double>(){ public Double apply(){ //此处写你的具体实现吧 double d = 2.2d; return new Double(d); } }; BClass bClass = new BClass(); bClass.method(1, func);
在Scala中,作为参数的函数会变成FunctionN类型的对象(N是该函数的参数个数),具体更高级的应用请参考scala的API。
4. 心得
以上的方法其实不是很好玩,而且看上去代码易读性很差。如果非要用Scala的代码,不如多写几个能利于Java直接调用的封装类,而让Java直接调用这些封装类。是叫适配器设计模式(Adapter Pattern)吗?