第14章——和Java进行互操作
现已存在许多强大的 Scala 库,并与日俱增。开发人员不仅可以在 Scala 中使用这些库, 也可以在 Java 中使用它们。但是要做到这一点,必须要学习一些技巧。 ①
- 因为某些库可能没有针对潜在的 Java 用户设计友好的 API,所以可能需要一些潜在适配工作。——译者注
14.1 在 Scala 中使用 Scala 类
Intermixing/Person.scala
class Person(val firstName: String, val lastName: String) {
override def toString: String = firstName + " " + lastName
}
Intermixing/Dog.scala
class Dog(val name: String) {
override def toString: String = name
}
执行命令
scalac Person.scala Dog.scala
jar cf /tmp/example.jar Person.class Dog.class
Intermixing/UsePerson.scala
val george = new Person("George", "Washington")
val georgesDogs = List(new Dog("Captain"), new Dog("Clode"), new Dog("Forester"), new Dog("Searcher"))
println(s"$george had several dogs ${georgesDogs.mkString(", ")}...")
执行命令
scala -classpath /tmp/example.jar usePerson.scala
运行结果
George Washington had several dogs Captain, Clode, Forester, Searcher...
Intermixing/UsePersonClass.scala
object UsePersonClass extends App {
val ben = new Person("Ben", "Franklin")
println(s"$ben was a great inventor.")
}
执行命令1
mkdir -p classes
scalac -d classes -classpath /tmp/example.jar UsePersonClass.scala
执行命令2
scala -classpath classes:/tmp/example.jar UsePersonClass
执行命令3
java -classpath $SCALA_HOME/lib/scala-library.jar:classes:/tmp/example.jar \
UsePersonClass
运行结果
Ben Franklin was a great inventor.
14.2 在 Scala 中使用 Java 类
Intermixing/UseJDKClass.scala
import java.util.Currency
val currencies = Currency.getAvailableCurrencies
println(s"${currencies.size} currencies are available.")
执行命令
scala UseJDKClass.scala
运行结果
220 currencies are available.
Intermixing/java/InvestmentType.java
//Java code
package chapter14.usingjava;
public enum InvestmentType {
BOND, STOCK, REAL_ESTATE, COMMODITIES, COLLECTIBLES, MUTUAL_FUNDS
}
运行结果
class investments.Investment
Intermixing/java/Investment.java
//Java code
package chapter14.usingjava;
public class Investment {
private String investmentName;
private InvestmentType investmentType;
public Investment(String name, InvestmentType type) {
investmentName = name;
investmentType = type;
}
public int yield() { return 0; }
}
Intermixing/UseInvestment.scala
import chapter14.usingjava.{ Investment, InvestmentType }
object UseInvestment extends App {
val investment = new Investment("XYZ Corporation", InvestmentType.STOCK)
println(investment.getClass)
}
执行命令1
mkdir -p classes
javac -d classes java/InvestmentType.java java/Investment.java
scalac -classpath classes UseInvestment.scala
scala -classpath classes:. UseInvestment
执行命令2
java -classpath $SCALA_HOME/lib/scala-library.jar:classes:. UseInvestment
Intermixing/UseInvestmentError.scala
val theYield1 = investment.yield //ERROR
val theYield2 = investment.yield() //ERROR
Intermixing/UseInvestmentYield.scala
val investment = new Investment("XYZ Corporation", InvestmentType.STOCK)
val theYield1 = investment.`yield`
val theYield2 = investment.`yield`()
14.3 在 Java 中使用 Scala 方法
Intermixing/Car.scala
package chapter14
class Car(val year: Int) {
private[this] var miles: Int = 0
def drive(distance: Int): Unit = { miles += distance }
override def toString: String = s"year: $year miles: $miles"
}
Intermixing/UseCar.java
//Java code
package chapter14;
public class UseCar {
public static void main(String[] args) {
Car car = new Car(2009);
System.out.println(car);
car.drive(10);
System.out.println(car);
}
}
执行命令
mkdir -p classes
scalac -d classes Car.scala
javac -d classes -classpath $SCALA_HOME/lib/scala-library.jar:classes \
UseCar.java
java -classpath $SCALA_HOME/lib/scala-library.jar:classes \
automobiles.users.UseCar
14.4 在 Java 中使用特质
Intermixing/Writable.scala
trait Writable {
def write(message: String): Unit
}
Intermixing/AWritableJavaClass.java
//Java code
public class AWritableJavaClass implements Writable {
public void write(String message) {
//...code...
}
}
Intermixing/Printable.scala
trait Printable {
def print(): Unit = {
println("running printable...")
}
}
执行命令1
mkdir -p classes
scalac -d classes Printable.scala
执行命令2
javap classes/Printable.class classes/Printable\$class.class
运行结果
Compiled from "Printable.scala"
public abstract class Printable$class {
public static void print(Printable);
public static void $init$(Printable);
}
Compiled from "Printable.scala"
public abstract class Printable$class {
public static void print(Printable);
public static void $init$(Printable);
}
Intermixing/APrintable.java
public class APrintable implements Printable {
public void print() {
System.out.println("We can reuse the trait here if we like...");
//Printable$class.print(this); // for 2.11.x
Printable.super.print(); // for 2.12.x
}
public static void use(Printable printable) {
printable.print();
}
public static void main(String[] args) {
APrintable aPrintable = new APrintable();
use(aPrintable);
}
}
执行命令
javac -d classes -classpath $SCALA_HOME/lib/scala-library.jar:classes \
APrintable.java
java -classpath $SCALA_HOME/lib/scala-library.jar:classes APrintable
运行结果
We can reuse the trait here if we like...
running printable...
14.5 在 Java 中使用单例对象和伴生对象
Intermixing/Single.scala
package chapter14
object Single {
def greet(): Unit = { println("Hello from Single") }
}
Intermixing/SingleUser.java
//Java code
public class SingleUser {
public static void main(String[] args) {
Single.greet();
}
}
运行结果
Hello from Single
Intermixing/Buddy.scala
class Buddy {
def greet(): Unit = { println("Hello from Buddy class") }
}
object Buddy {
def greet(): Unit = { println("Hello from Buddy object") }
}
Intermixing/BuddyUser.scala
//Java code
public class BuddyUser {
public static void main(String[] args) {
new Buddy().greet();
Buddy$.MODULE$.greet();
}
}
运行结果
Hello from Buddy class
Hello from Buddy object
14.6 扩展类
Intermixing/BirdWithProblem.scala
abstract class BirdWithProblem {
def fly(): Unit
//...
}
Intermixing/Ostrich.scala
class Ostrich extends BirdWithProblem {
override def fly(): Unit = {
throw new NoFlyException
}
//...
}
Intermixing/NoFlyException.scala
class NoFlyException extends Exception {}
Intermixing/Penguin.java
//Java code
class Penguin extends Bird {
public void fly() throws NoFlyException {
throw new NoFlyException();
}
//...
}
Penguin.java:3: error: fly() in Penguin cannot override fly() in Bird
public void fly() throws NoFlyException {
^
overridden method does not throw NoFlyException
1 error
Intermixing/Bird.scala
abstract class Bird {
@throws(classOf[NoFlyException]) def fly(): Unit
//...
}