kotlin杂谈系列十二(Kotlin和Java的互操作)

13 篇文章 0 订阅
13 篇文章 0 订阅

Kotlin杂谈系列十二

  • 这次就主要来谈谈kotlin和java互操作的问题

  • kotlin出来的使命就是为了解决java的模板问题和一些冗长的问题所以kotlin天生就很好的支持了java 所以我们在java代码中可以很好的引用java的类库和代码 但是在java中调用kotlin的代码就没那么容易了

  • 首先讲讲编译过程,如果一个项目里有kotlin代码和java代码那么编译时 kotlin编译器会先为java代码存根来支持他们之间的依赖 然后在使用java编译器这样就能运行了 因为kotlin代码和java代码在字节码层面上是没有差异的

  • 首先是静态方法

    我们知道在kotlin中是没有静态的方法的 在kotlin来表示类级别的是伴生对象 所以我们可以在伴生对象的方法上加上注解 @JvmStatic 这样的意义在于可以让java以静态代码的格式来调用伴生队象的方法 但是实质一个实例方法

//java文件
public class Test {
    public static void main(String[] args) {
        Book.Companion.hi();//这里
    }

}

//kotlin文件
class Book {
    companion object{
        fun hi(){
            println("I am a book")
        }
    }
}
  • 可以看见如果不用**@JvmStatic** 修饰的话就会多一个中间变量来桥接Companion 这个是当伴生对象没有名字的时候 有名字的时候就是那个名字
//java文件
public class Test {
    public static void main(String[] args) {
        Book.show.hi();//这里
    }

}

//kotlin文件
class Book {
    companion object show /*这里哦 指定了名字*/{
        fun hi(){
            println("I am a book")
        }
    }
}
  • 现在来看看 @JVMStatic的威力吧
//java文件
public class Test {
    public static void main(String[] args) {
        Book.hi();/*这里*/
    }
}

//kotlin文件
class Book {
    companion object show{
        @JvmStatic/*这里*/
        fun hi(){
            println("I am a book")
        }
    }
}
  • 就这样就可以让java调用kotlin的伴生对象方法象静态方法一样但是实质不一样 来看看反编译的源码吧

public final class Book {
   @NotNull//单例模式
   public static final Book.show show = new Book.show((DefaultConstructorMarker)null);
/*-----------------------重点-----------------------------------*/
   @JvmStatic /*外部类的桥接方法*/
   public static final void hi() {
      show.hi();
   }

   public static final class show {
      @JvmStatic/*真正的实现逻辑*/
/*-----------------------重点-----------------------------------*/
      public final void hi() {
         String var1 = "I am a book";
         System.out.println(var1);
      }

       //构造器私有化
      private show() {
      }

      // $FF: synthetic method
      public show(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}
  • 可以看见hi()方法并为变成真正的静态方法而是在外部类又包装了一个静态的方法 但是具体的逻辑还是在内部类的hi()方法

  • Kotlin 重载运算符

相信用过都说好 ,但是java并不支持所以怎么办呢 如果kotlin实现了运算符重载,那java只能调用对应方法了 例如 + --> plus()

//java 代码
public class Test {
    public static void main(String[] args) {
        new Book().plus(new Book());
    }
}

//kotlin代码
class Book {
    operator fun plus(book : Book){
        println("add a book price")
    }
}
  • 访问属性

kotlin当我们访问属性的时候 实际上是访问了我们的getter / setter 但是java没有这么智能就只能手动调用getter / setter

//java代码
public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        System.out.println(book.getName());
    }
}

//kotlin代码
class Book {
    val name = "Kotlin VS Java"
}
  • 因为他是val变量所以只有getter方法

  • 传递lambda

java中的lambda必须是个接口 而kotlin的lambda实质上是一个匿名函数

所以传递时 就的导kotlin中的Function<T>等类似的包

//java代码
public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        book.ok(/*传入的lambda表达式*/() -> {
            System.out.println("加油");
            return null;
        });
    }

}

//kotlin代码
class Book {
    fun ok (arg : () -> Unit){
        arg()
    }
}
  • 可以看到不能取消括号 参数写在外面

  • 异常

  • kotlin中全部都是未检查的异常(运行时异常) 而java中有已检查异常(编译时异常) 和 未检查异常 如果是已检查的异常就必须处理 (抛出 / 捕获)

看下面的代码

//java
public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        try {
            book.getContent();
        } catch (java.io.FileNotFoundException ex) {
            System.out.println("not found");
        }
    }
}

//kotlin
class Book {
	//这里
    @Throws(java.io.FileNotFoundException::class)
    fun getContent(){
        val bytes = java.io.File("aha").readLines()
    }
}
  • 在java中java.io.FileNotFoundException 是一个编译时异常 所以如果我们在kotlin中可以不处理但是java用的时候必须处理 所以利用注解 @Throws(java.io.FileNotFoundException::class) 抛出这个异常 这样java才能捕获到 否则就捕获不到 会在编译时抛异常 Exception ‘java.io.FileNotFoundException’ is never thrown in the corresponding try block

  • 带默认参数的函数

java中是没有带默认参数的函数这个特性的 那该怎么实现呢 哈哈 当然是重载

public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        book.getPrice();// 'getPrice(int)' in 'Book' cannot be applied to '()'
    }
}

//kotlin 代码
class Book {
    fun getPrice(price : Int = 1){
        println(price*2)
    }
}
  • 可以看到说没有找到这个方法签名但是加上一个注解就可以了 @JvmOverloads
//java 代码
public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        book.getPrice();// 'getPrice(int)' in 'Book' cannot be applied to '()'
    }
}

//kotlin 代码
class Book {
    @JvmOverloads
    fun getPrice(price : Int = 1){
        println(price*2)
    }
}
  • 但是是有弊端的,我们知道java的重载是有以方法签名识别不同的重载的方法的

    看下面的代码

class Book {
    @JvmOverloads
    fun getPrice(price : Int = 1,factor : Int = 2){
        println(price*factor)
    }
}


//看看反编译的代码
public final class Book {
    //1.重载方法
   @JvmOverloads
   public final void getPrice(int price, int factor) {
      int var3 = price * factor;
      System.out.println(var3);
   }
	//2.重载方法
   @JvmOverloads
   public final void getPrice(int price) {
      getPrice$default(this, price, 0, 2, (Object)null);
   }
	//3.重载方法
   @JvmOverloads
   public final void getPrice() {
      getPrice$default(this, 0, 0, 3, (Object)null);
   }
    
    // $FF: synthetic method
   public static void getPrice$default(Book var0, int var1, int var2, int var3, Object var4) {
      if ((var3 & 1) != 0) {
         var1 = 1;
      }

      if ((var3 & 2) != 0) {
         var2 = 2;
      }

      var0.getPrice(var1, var2);
   }
}
  • 这里重载的的一个参数的函数的参数 是 price 但是我们可以在kotlin中为factor利用命名参数的方式调用 但是java就肯定不行了 不能只想更改factor的值而不动price的值 这就是有点不完美性

  • 访问顶级的函数

    在字节码的层面 顶级函数会被封装在一个类里 这个类是文件名KT

//kotlin代码
//文件名 : Async01.kt
fun getPop(){
    println("hello")
}

//反编译后
public final class Async01Kt {
   public static final void getPop() {
      String var0 = "hello";
      System.out.println(var0);
   }
}

  • 但是可以利用注解来指定类名 @file : JvmName()
@file:JvmName("async02")//这里
fun getPop(){
    println("hello")
}

@JvmName(
   name = "async02"
)
public final class async02/*这里*/ {
   public static final void getPop() {
      String var0 = "hello";
      System.out.println(var0);
   }
}

  • 当然还有在Kotlin中还有很多的注解都是为了解决java和Kotlin的互操作的问题

  • 可以使用 Synchronized 来注解一个方法变成一个synchronized 标记的方法

  • 更多的注解可以看官方的文档

今天就是简单的了解一下kotlin和java的互操作

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值