scala で java のクラスを継承するときに気をつけること
- package と import, コンパイル時のクラスパス
- java 側のクラスと scala 側のクラスのコンストラクタ引数の一致
以下のようなディレクトリ構造,ファイルで検証
tree
# => 現在のディレクトリ構造
# .
# ├── class
# ├── lib
# │ ├── java
# │ │ └── Super.java
# │ └── scala
# │ └── Sub.scala
# └── src
# └── Main.scala
#
# 5 directories, 3 files
/lib/java/Super.java
package lib.java;
public class Super {
private String name;
public Super(final String name) { this.name = name; }
public String getName() { return this.name; }
public String greet() { return "Hello from " + this.getName() + " in Super"; }
}
/lib/scala/Sub.scala
package lib.scala
import lib.java.Super
final class Sub(val name :String) extends Super(name :String) {
override def greet() :String = "Hello form " + this.getName + " in Sub"
}
/src/Main.scala
import lib.java.Super
import lib.scala.Sub
object Main {
def main(args: Array[String]) {
val a :Super = new Super("A")
val b :Sub = new Sub("B")
println(a.greet)
println(b.greet)
}
}
package と import, コンパイル時のクラスパス
コンパイルすると package に記述したディレクトリ構造でクラスファイルが生成される.
また,import するクラスが存在するソースをコンパイルする時は,適切にクラスパスを指定する必要がある.
libファイルやsrcファイルなど存在するディレクトリが異なる依存関係の時は,javac, scalac のコマンドオプションを使えばきれいに解決.
-classpath <path> : ユーザのクラスファイルを <path> から探索
-d <directory> : 生成したクラスファイルを置くディレクトリを <directory> に設定
java 側のクラスと scala 側のクラスのコンストラクタ引数の一致
引数が上記の ./lib/scala/Sub.scala
のように一致していないとコンパイル時にエラー
# scalac ./lib/scala/Sub.scala
# final class Sub extends Super の時
<path>/lib/scala/Sub.scala:5: error: not enough arguments for constructor Super: (x$1: String)lib.java.Super.
Unspecified value parameter x$1.
final class Sub(val name :String) extends Super {
^
one error found
# final class Sub extends Super(name :String) の時
<path>/lib/scala/Sub.scala:5: error: not found: value name
final class Sub extends Super(name :String) {
^
one error found
コンパイル&実行
root=`pwd`
# 依存順にコンパイル
javac -d ${root}/class ${root}/lib/java/Super.java &&
scalac -classpath ${root}/class -d ${root}/class ${root}/lib/scala/Sub.scala &&
scalac -classpath ${root}/class -d ${root}/class ${root}/src/Main.scala
tree
# .
# ├── class
# │ ├── Main$.class
# │ ├── Main.class
# │ └── lib
# │ ├── java
# │ │ └── Super.class
# │ └── scala
# │ └── Sub.class
# ├── lib
# │ ├── java
# │ │ └── Super.java
# │ └── scala
# │ └── Sub.scala
# └── src
# └── Main.scala
#
# 8 directories, 7 files
scala -classpath ${root}/class Main
# Hello from A in Super
# Hello form B in Sub
余談
手動ビルドだったので,sbt やら typesafe-activator を用いてやる方法もそのうち.
java のクラスを scala で継承 (typesafe-activator編) をあげました