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

Overview

Groovy,Scala 和 Kotlin 都是 JVM 上的语言,在设计之初就考虑到了与 Java 的兼容性,所以这三门语言几乎都能无缝调用 Java 代码,因此也能很简单地使用现在众多成熟的 Java 类库。而 Java 调用这三门语言也不是太麻烦,所以可以根据实用场景在这四门语言中进行便捷地切换。

Groovy

Groovy 调用 Java

Groovy 调用 Java 就像 Java 调用 Java 一样没有任何其它操作。

例:

定义一个 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);
    }
}

编写一个 Groovy 类调用以上的 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 调用 Groovy

例:

编写一个 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}")
    }
}

编写调用以上 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 调用 Java

Scala 调用 Java 也非常简单

例:

定义一个 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);
    }

}

编写一个 Scala 类调用以上的 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 调用 Scala

Java 调用 Scala 时需要注意 classobject 的区别。此外在 Scala 对象中如果属性没有声明为 @BeanProperty 的话,调用时需要使用 对象.属性名() 来调用,声明后才可以使用 Java 风格的 对象.get属性名() 来调用。

例:

编写一个 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...")
}

编写调用以上 Scala 代码的 Java 类

public class JavaCallScala {

    public static void main(String[] args) {
        ScalaBean scalaBean = new ScalaBean("ScalaBean");
        // Scala 属性的默认调用方式
        System.out.println(scalaBean.name());       //  ScalaBean
        // 声明为 @BeanProperty 后提供的调用方式
        System.out.println(scalaBean.getName());    //  ScalaBean
        System.out.println(scalaBean.age());        //  10
        System.out.println(scalaBean.calc(2, 3));    //  5

        // 调用 Scala的单例对象,本质上调用的是下面一行
        ScalaBean.hello(scalaBean);                 //  Hello, this is ScalaBean
        ScalaBean$.MODULE$.hello(scalaBean);        //  Hello, this is ScalaBean

        ScalaUtils.foo();   //  Foo...
    }
}

Kotlin

Kotlin 调用 Java

Kotlin 调用 Java 也非常简单,但是如果 Java 的方法名是类似 is 这种在 Kotlin 是关键字,在 Java 中只是普通字符的场合,Kotlin 中调用时需要使用 "``" 括起来。

例:

定义一个 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);
    }
}

编写一个 Kotlin 类调用以上的 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 优雅的空值处理方式

val list = ArrayList<JavaBean>()
list.add(javaBean)
val nullable: JavaBean? = list[0]
val notNull: JavaBean = list[0]
nullable?.name
notNull.name

Java 调用 Kotlin

Java 调用 Kotlin 不像其它几种有一些比较特殊的情况,接下来一一说明。

Class 与 Object

例:

编写一个 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...")
    }
}

编写调用以上 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 注解,该注解用于生成静态方法,如果没有使用该注解的话就必须使用隐式的单例对象 INSTANCE$ 来调用 object 中的方法。这种处理方式与 Scala 非常相似,只是 Scala 是自动生成的罢了。

fun

Kotlin 中方法是可以脱离类而存在的,而在 Java 中这种方式是不允许的。定义这种方法时实际上 Kotlin 是产生了一个与包名相同的类来存储这些方法,所以 Java 中也需要使用包名调用这些方法。

例:

定义一个脱离类的 Kotlin 的方法

package com.bookislife.jgsk.kotlin._29_java
fun foobar() {
    println("A function without class.")
}

在 Java 中调用以上方法

_29_javaPackage.foobar();

检查异常

Kotlin 不存在检查异常,但是 Java 中却到处都是检查异常,如果想抛出检查异常需要使用 @throws(exceptionClassName::class) 的语法。

例:

Kotlin 代码

@Throws(IOException::class) fun declaredThrowAnException() {
    throw IOException()
}

Java 代码

try {
    _29_javaPackage.declaredThrowAnException();
} catch (IOException ignored) {
}

重载

Kotlin 拥有方法默认值和带名参数的特点,所以只需要定义一个包含所有参数的方法就可以满足需求。而 Java 没有这一特性,所以需要定义多个参数列表不同的同名方法,即重载才能满足需求。在 Kotlin 中可以直接使用 jvmOverloads 注解自动生成这些重载方法来让 Java 进行调用。

例:

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

  • 三种语言都能比较简单地与 Java 互相调用。

文章源码见 https://github.com/SidneyXu/JGSK 仓库的 _29_java 小节

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容