11.1 在Scala里使用Scala类

在谈论Java和Scala互操作之前,先来看看在Scala里使用Scala类。如果在单独的文件里创建Scala类,就可以轻松地使用它们,就像(无需显式编译)在Scala脚本里使用一样。①不过,如果想在编译过的Scala或Java代码里使用Scala类,那就必须编译了。

①参见2.4节,“命令行上的Scala”,了解把Scala代码当作脚本运行的详细内容。

假定有两个Scala类,分别叫做PersonDog。总的来说,把每个类放到各自的文件里是个好的实践。我把它们都放到Person.scala只是为了阐明观点:

WorkingWithScriptsAndClasses/Person.scala

  1. class Person(val firstName: String, val lastName: String) {
  2. override def toString() : String = firstName + "" + lastName
  3. }
  4. class Dog(name: String) {
  5. override def toString() :String = name
  6. }

下面是使用上面两个类的脚本:

WorkingWithScriptsAndClasses/usePerson.scala

  1. val george = new Person("George", "Washington")
  2. val georgesDogs = List(new Dog("Captain"), new Dog("Clode"),
  3. new Dog("Forester"), new Dog("Searcher"))
  4. printf("%s had several dogs %s...", george, georgesDogs mkString ", ")

脚本会产生如下输出:

  1. George Washington had several dogs Captain, Clode, Forester, Searcher...

不必编译上面的代码,引用Person类时,Scala会找一个叫Person.scala的文件去加载。这个文件里包含了Dog,所以,这个类也得到了解析。相反,如果Dog类在一个单独的文件Dog.scala里,或是有一个编译过的字节码文件叫Dog.class,Scala也会从中找到Dog类。不过,如果Dog类在其他一些任意的文件里,Scala就很难找到了。

在上面的例子里,Person.scalausePerson.scala两个文件在同一个目录下。假定文件Person.scala在不同的目录下,比如在entities目录中,可以在scala的sourcepath选项里指定这个目录,如下:

  1. scala -sourcepath entities:. usePerson.scala

如果类是以编译过的形式存在不同的目录下,就要使用classpath选项,或者把sourcepathclasspath一起用。

我们掌握了如何在脚本里使用Scala类。不过,为了在其他Scala类里使用它们,需要先编译。

假定想在下面的Scala代码里使用上面的Person类:

WorkingWithScriptsAndClasses/UsePersonClass.scala

  1. object UsePersonClass {
  2. def main(args: Array[String]) {
  3. val ben = new Person("Ben", "Franklin")
  4. println(ben + " was a great inventor.")
  5. }
  6. }

如果Person已经编译过,单独编译UsePersonClass.scala即可。如果Person.class不在当前目录下,可以用classpath选项——用-d选项可以说明字节码的存放地点:

  1. scalac -d . -classpath LocationOfPersonClassFile UsePersonClass.scala

另一方面,如果Person类还没编译过,可以同UsePersonClass一起编译它。指定sourcepath,让编译器可以找到其需要一起编译的文件。因此,用下面的命令:

  1. scalac -sourcepath LocationOfPersonScalaFile:. UsePersonClass.scala

其中,LocationOfPersonScalaFilePerson.scala文件的位置。另外,如果所有相关文件都在当前目录下,也可以用scalac -sourcepath . UsePersonClass.scala。当然,既可以用sourcepath也可以用classpath——这样就既可以用Scala源文件,也可以用从任意JVM语言(Java、Groovy、JRuby和Scala等)编译而来的字节码。

可以用scala或传统的java运行编译过的字节码。下面是一个例子,使用scala②运行UsePersonClass.class文件:

②可以使用scala运行Scala编译过的代码和用javac编译过的代码。

  1. // FIXME: scala UsePersonClass,会报找不到文件的错,
  2. 因为没有指定classpath。应该写成scala -classpath . UsePersonClass③。
  3. scalac -sourcepath . UsePersonClass.scala
  4. scala UsePersonClass

③我试过了,没有报错,确实可以直接写scala UsePersonClass。我在Ubuntu下试了,确实不能用,尝试了2.7和2.8两个版本。

另一方面,如果想用java运行它,只要在classpath里指定scala-library.jar文件即可(请确保使用了scala-library.jar在机器上的正确路径):

  1. scalac -sourcepath . UsePersonClass.scala
  2. java -classpath /opt/scala/scala-2.7.4.final/lib/scala-library.jar:.
  3. UsePersonClass

这里会看到上面两种方式产生相同的结果:

  1. Ben Franklin was a great inventor.