Java & Groovy & Scala & Kotlin - 29.與 Java 交互

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í)需要注意 classobject 的區(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é)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市劣欢,隨后出現(xiàn)的幾起案子棕诵,更是在濱河造成了極大的恐慌裁良,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件校套,死亡現(xiàn)場(chǎng)離奇詭異趴久,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)搔确,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)灭忠,“玉大人膳算,你說(shuō)我怎么就攤上這事〕谧鳎” “怎么了涕蜂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)映琳。 經(jīng)常有香客問(wèn)我机隙,道長(zhǎng),這世上最難降的妖魔是什么萨西? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任有鹿,我火速辦了婚禮,結(jié)果婚禮上谎脯,老公的妹妹穿的比我還像新娘葱跋。我一直安慰自己,他們只是感情好源梭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布娱俺。 她就那樣靜靜地躺著,像睡著了一般废麻。 火紅的嫁衣襯著肌膚如雪荠卷。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天烛愧,我揣著相機(jī)與錄音油宜,去河邊找鬼。 笑死屑彻,一個(gè)胖子當(dāng)著我的面吹牛验庙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播社牲,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼粪薛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了搏恤?” 一聲冷哼從身側(cè)響起违寿,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤湃交,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后藤巢,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搞莺,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年掂咒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了才沧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绍刮,死狀恐怖温圆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孩革,我是刑警寧澤岁歉,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站膝蜈,受9級(jí)特大地震影響锅移,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜饱搏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一非剃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窍帝,春花似錦努潘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至深浮,卻和暖如春压怠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背飞苇。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工菌瘫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布卡。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓雨让,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親忿等。 傳聞我的和親對(duì)象是個(gè)殘疾皇子栖忠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容