11.1 在Scala里使用Scala类
在谈论Java和Scala互操作之前,先来看看在Scala里使用Scala类。如果在单独的文件里创建Scala类,就可以轻松地使用它们,就像(无需显式编译)在Scala脚本里使用一样。①不过,如果想在编译过的Scala或Java代码里使用Scala类,那就必须编译了。
①参见2.4节,“命令行上的Scala”,了解把Scala代码当作脚本运行的详细内容。
假定有两个Scala类,分别叫做Person
和Dog
。总的来说,把每个类放到各自的文件里是个好的实践。我把它们都放到Person.scala
只是为了阐明观点:
WorkingWithScriptsAndClasses/Person.scala
class Person(val firstName: String, val lastName: String) {
override def toString() : String = firstName + "" + lastName
}
class Dog(name: String) {
override def toString() :String = name
}
下面是使用上面两个类的脚本:
WorkingWithScriptsAndClasses/usePerson.scala
val george = new Person("George", "Washington")
val georgesDogs = List(new Dog("Captain"), new Dog("Clode"),
new Dog("Forester"), new Dog("Searcher"))
printf("%s had several dogs %s...", george, georgesDogs mkString ", ")
脚本会产生如下输出:
George Washington had several dogs Captain, Clode, Forester, Searcher...
不必编译上面的代码,引用Person
类时,Scala会找一个叫Person.scala
的文件去加载。这个文件里包含了Dog
,所以,这个类也得到了解析。相反,如果Dog
类在一个单独的文件Dog.scala
里,或是有一个编译过的字节码文件叫Dog.class
,Scala也会从中找到Dog
类。不过,如果Dog
类在其他一些任意的文件里,Scala就很难找到了。
在上面的例子里,Person.scala
和usePerson.scala
两个文件在同一个目录下。假定文件Person.scala
在不同的目录下,比如在entities目录中,可以在scala的sourcepath
选项里指定这个目录,如下:
scala -sourcepath entities:. usePerson.scala
如果类是以编译过的形式存在不同的目录下,就要使用classpath
选项,或者把sourcepath
跟classpath
一起用。
我们掌握了如何在脚本里使用Scala类。不过,为了在其他Scala类里使用它们,需要先编译。
假定想在下面的Scala代码里使用上面的Person
类:
WorkingWithScriptsAndClasses/UsePersonClass.scala
object UsePersonClass {
def main(args: Array[String]) {
val ben = new Person("Ben", "Franklin")
println(ben + " was a great inventor.")
}
}
如果Person
已经编译过,单独编译UsePersonClass.scala
即可。如果Person.class
不在当前目录下,可以用classpath
选项——用-d
选项可以说明字节码的存放地点:
scalac -d . -classpath LocationOfPersonClassFile UsePersonClass.scala
另一方面,如果Person
类还没编译过,可以同UsePersonClass
一起编译它。指定sourcepath
,让编译器可以找到其需要一起编译的文件。因此,用下面的命令:
scalac -sourcepath LocationOfPersonScalaFile:. UsePersonClass.scala
其中,LocationOfPersonScalaFile
是Person.scala
文件的位置。另外,如果所有相关文件都在当前目录下,也可以用scalac -sourcepath . UsePersonClass.scala
。当然,既可以用sourcepath
也可以用classpath
——这样就既可以用Scala源文件,也可以用从任意JVM语言(Java、Groovy、JRuby和Scala等)编译而来的字节码。
可以用scala或传统的java运行编译过的字节码。下面是一个例子,使用scala②运行UsePersonClass.class
文件:
②可以使用scala运行Scala编译过的代码和用javac编译过的代码。
// FIXME: scala UsePersonClass,会报找不到文件的错,
因为没有指定classpath。应该写成scala -classpath . UsePersonClass③。
scalac -sourcepath . UsePersonClass.scala
scala UsePersonClass
③我试过了,没有报错,确实可以直接写
scala UsePersonClass
。我在Ubuntu下试了,确实不能用,尝试了2.7和2.8两个版本。
另一方面,如果想用java运行它,只要在classpath
里指定scala-library.jar
文件即可(请确保使用了scala-library.jar
在机器上的正确路径):
scalac -sourcepath . UsePersonClass.scala
java -classpath /opt/scala/scala-2.7.4.final/lib/scala-library.jar:.
UsePersonClass
这里会看到上面两种方式产生相同的结果:
Ben Franklin was a great inventor.