Overview
Groovy肖粮,Scala 和 Kotlin 都是 JVM 上的語(yǔ)言滑黔,在設(shè)計(jì)之初就考慮到了與 Java 的兼容性擦俐,所以這三門(mén)語(yǔ)言幾乎都能無(wú)縫調(diào)用 Java 代碼该园,因此也能很簡(jiǎn)單地使用現(xiàn)在眾多成熟的 Java 類庫(kù)披摄。而 Java 調(diào)用這三門(mén)語(yǔ)言也不是太麻煩,所以可以根據(jù)實(shí)用場(chǎng)景在這四門(mén)語(yǔ)言中進(jìn)行便捷地切換跑揉。
Groovy
Groovy 調(diào)用 Java
Groovy 調(diào)用 Java 就像 Java 調(diào)用 Java 一樣沒(méi)有任何其它操作锅睛。
例:
定義一個(gè) Java 類 JavaBean.java
public class JavaBean {
private String name;
public JavaBean(String name) {
this.name = name;
}
public int calc(int x, int y) {
return x + y;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static void hello(JavaBean bean) {
System.out.println("Hello, this is " + bean.name);
}
}
編寫(xiě)一個(gè) Groovy 類調(diào)用以上的 Java Bean
class GroovyCallJava {
static void main(args) {
JavaBean javaBean = new JavaBean("JavaBean")
println javaBean.getName() // JavaBean
println javaBean.calc(2, 3) // 5
JavaBean.hello(javaBean) // Hello, this is JavaBean
}
}
Java 調(diào)用 Groovy
例:
編寫(xiě)一個(gè) Groovy 類 GroovyBean.groovy
class GroovyBean {
def name
GroovyBean(name) {
this.name = name
}
def calc(x, y) {
x + y
}
static def hello(GroovyBean bean) {
println("Hello, this is ${bean.name}")
}
}
編寫(xiě)調(diào)用以上 Groovy 代碼的 Java 類
public class JavaCallGroovy {
public static void main(String[] args) {
GroovyBean groovyBean = new GroovyBean("GroovyBean");
System.out.println(groovyBean.getName()); // GroovyBean
System.out.println(groovyBean.calc(2, 3)); // 5
GroovyBean.hello(groovyBean); // Hello, this is GroovyBean
}
}
Scala
Scala 調(diào)用 Java
Scala 調(diào)用 Java 也非常簡(jiǎn)單
例:
定義一個(gè) Java 類 JavaBean.java
public class JavaBean {
private String name;
public JavaBean(String name) {
this.name = name;
}
public int calc(int x, int y) {
return x + y;
}
public String getName() {
return name;
}
public static void hello(JavaBean bean) {
System.out.println("Hello, this is " + bean.name);
}
}
編寫(xiě)一個(gè) Scala 類調(diào)用以上的 Java Bean
object ScalaCallJava extends App {
val javaBean = new JavaBean("JavaBean")
println(javaBean.getName) // JavaBean
println(javaBean.calc(2, 3)) // 5
JavaBean.hello(javaBean) // Hello, this is JavaBean
}
Java 調(diào)用 Scala
Java 調(diào)用 Scala 時(shí)需要注意 class
和 object
的區(qū)別。此外在 Scala 對(duì)象中如果屬性沒(méi)有聲明為 @BeanProperty
的話历谍,調(diào)用時(shí)需要使用 對(duì)象.屬性名()
來(lái)調(diào)用现拒,聲明后才可以使用 Java 風(fēng)格的 對(duì)象.get屬性名()
來(lái)調(diào)用。
例:
編寫(xiě)一個(gè) Scala 類 ScalaBean.scala
class ScalaBean(@BeanProperty val name: String) {
val age: Int = 10
def calc(x: Int, y: Int) = x + y
}
object ScalaBean {
def hello(bean: ScalaBean): Unit = println(s"Hello, this is ${bean.name}")
}
object ScalaUtils {
def foo = println("Foo...")
}
編寫(xiě)調(diào)用以上 Scala 代碼的 Java 類
public class JavaCallScala {
public static void main(String[] args) {
ScalaBean scalaBean = new ScalaBean("ScalaBean");
// Scala 屬性的默認(rèn)調(diào)用方式
System.out.println(scalaBean.name()); // ScalaBean
// 聲明為 @BeanProperty 后提供的調(diào)用方式
System.out.println(scalaBean.getName()); // ScalaBean
System.out.println(scalaBean.age()); // 10
System.out.println(scalaBean.calc(2, 3)); // 5
// 調(diào)用 Scala的單例對(duì)象望侈,本質(zhì)上調(diào)用的是下面一行
ScalaBean.hello(scalaBean); // Hello, this is ScalaBean
ScalaBean$.MODULE$.hello(scalaBean); // Hello, this is ScalaBean
ScalaUtils.foo(); // Foo...
}
}
Kotlin
Kotlin 調(diào)用 Java
Kotlin 調(diào)用 Java 也非常簡(jiǎn)單印蔬,但是如果 Java 的方法名是類似 is
這種在 Kotlin 是關(guān)鍵字,在 Java 中只是普通字符的場(chǎng)合甜无,Kotlin 中調(diào)用時(shí)需要使用 "``" 括起來(lái)扛点。
例:
定義一個(gè) Java 類 JavaBean.java
public class JavaBean {
private String name;
public JavaBean(String name) {
this.name = name;
}
public int calc(int x, int y) {
return x + y;
}
public boolean is(String name) {
return this.name.equals(name);
}
public String getName() {
return name;
}
public static void hello(JavaBean bean) {
System.out.println("Hello, this is " + bean.name);
}
}
編寫(xiě)一個(gè) Kotlin 類調(diào)用以上的 Java Bean
fun main(args: Array<String>) {
val javaBean = JavaBean("JavaBean")
println(javaBean.name) // JavaBean
println(javaBean.calc(2, 3)) // 5
JavaBean.hello(javaBean) // Hello, this is Peter
// Escaping for Java identifiers that are keywords in Kotlin
println(javaBean.`is`("Peter")) // true
}
這種使用方式可以讓 Java 享受到 Kotlin 優(yōu)雅的空值處理方式
val list = ArrayList<JavaBean>()
list.add(javaBean)
val nullable: JavaBean? = list[0]
val notNull: JavaBean = list[0]
nullable?.name
notNull.name
Java 調(diào)用 Kotlin
Java 調(diào)用 Kotlin 不像其它幾種有一些比較特殊的情況,接下來(lái)一一說(shuō)明岂丘。
Class 與 Object
例:
編寫(xiě)一個(gè) Kotlin 類 ScalaBean.scala
class KotlinBean(val name: String) {
fun calc(x: Int, y: Int): Int {
return x + y
}
companion object {
@JvmStatic fun hello(bean: KotlinBean) {
println("Hello, this is ${bean.name}")
}
fun echo(msg: String, bean: KotlinBean) {
println("$msg, this is ${bean.name}")
}
}
}
object KotlinUtils {
@JvmStatic fun foo() {
println("Foo...")
}
fun bar() {
println("Bar...")
}
}
編寫(xiě)調(diào)用以上 Kotlin 代碼的 Java 類
public class JavaCallKotlin {
public static void main(String[] args) {
// Class
KotlinBean kotlinBean = new KotlinBean("Peter");
System.out.printf(kotlinBean.getName()); // Peter
System.out.println(kotlinBean.calc(2, 3)); // 5
KotlinBean.hello(kotlinBean); // Hello, this is Peter
KotlinBean.Companion.echo("GoodBye", kotlinBean); // GoodBye, this is Peter
// Object
KotlinUtils.foo();
KotlinUtils.INSTANCE.bar();
}
}
以上示例中使用了 JvmStatic
注解陵究,該注解用于生成靜態(tài)方法,如果沒(méi)有使用該注解的話就必須使用隱式的單例對(duì)象 INSTANCE$
來(lái)調(diào)用 object
中的方法奥帘。這種處理方式與 Scala 非常相似铜邮,只是 Scala 是自動(dòng)生成的罷了。
fun
Kotlin 中方法是可以脫離類而存在的寨蹋,而在 Java 中這種方式是不允許的松蒜。定義這種方法時(shí)實(shí)際上 Kotlin 是產(chǎn)生了一個(gè)與包名相同的類來(lái)存儲(chǔ)這些方法,所以 Java 中也需要使用包名調(diào)用這些方法已旧。
例:
定義一個(gè)脫離類的 Kotlin 的方法
package com.bookislife.jgsk.kotlin._29_java
fun foobar() {
println("A function without class.")
}
在 Java 中調(diào)用以上方法
_29_javaPackage.foobar();
檢查異常
Kotlin 不存在檢查異常秸苗,但是 Java 中卻到處都是檢查異常,如果想拋出檢查異常需要使用 @throws(exceptionClassName::class)
的語(yǔ)法运褪。
例:
Kotlin 代碼
@Throws(IOException::class) fun declaredThrowAnException() {
throw IOException()
}
Java 代碼
try {
_29_javaPackage.declaredThrowAnException();
} catch (IOException ignored) {
}
重載
Kotlin 擁有方法默認(rèn)值和帶名參數(shù)的特點(diǎn)惊楼,所以只需要定義一個(gè)包含所有參數(shù)的方法就可以滿足需求。而 Java 沒(méi)有這一特性秸讹,所以需要定義多個(gè)參數(shù)列表不同的同名方法檀咙,即重載才能滿足需求。在 Kotlin 中可以直接使用 jvmOverloads
注解自動(dòng)生成這些重載方法來(lái)讓 Java 進(jìn)行調(diào)用璃诀。
例:
Kotlin 代碼
@JvmOverloads fun f(a: String, b: Int = 0, c: String = "c") {
println("a=$a b=$b c=$c")
}
Java 代碼
_29_javaPackage.f("x"); // a=x b=0 c=c
_29_javaPackage.f("x", 10); // a=x b=10 c=c
_29_javaPackage.f("x", 10, "z"); // a=x b=10 c=z
Summary
- 三種語(yǔ)言都能比較簡(jiǎn)單地與 Java 互相調(diào)用弧可。
文章源碼見(jiàn) https://github.com/SidneyXu/JGSK 倉(cāng)庫(kù)的 _29_java
小節(jié)