当前位置:   article > 正文

Kotlin与Java的混合开发_java kotlin混编

java kotlin混编

包括基本的互操作行为、SAM转换、正则表达式、集合框架、IO操作:[实际上用到i的还是 java的api,只不过要注意kotlin为我们提供了很多扩展方法]、装箱和拆箱、注解处理器。

下面一一介绍:

1.基本的互操作行为:

1.属性读写:

Kotlin自动识别 Java Getter/Setter

Java操作Kotlin属性通过Getter/Setter

 2. 空安全类型:

Kotlin 空安全类型的原理(java没这个。原理是Kotlin在编译的时候会增加一个函数调用,对参数类型或返回值类型进行为空的检查)

但是因为java没这个,所以kotlin想操作java的代码的话,就会遇到一个平台类型(Platform Type)的问题,这时候就需要我们自己明确

传入的参数或者返回值的类型是不是为空的。

当然开发Java代码的时候也可以使用注解@Nullable 和@NotNull来解决这个问题。

3.几类函数的调用:

包级函数:静态方法(Java没有。)【它在编译的时候会为kotlin生成一个类,这个类包含了所有的高级函数,在Java看来这些都是静态方法。所以在调用的时候只需要按照调用静态方法的方式去调用即可】

扩展方法: 带Receiver的静态方法。【只是增加了一个Receiver参数】

运算符重载: 带Receiver的对应名称的静态方法。

4.几个常见的注解的使用:

@JvmField: 将属性编译为Java变量。【如果我们希望kotlin里面的属性无论是看起来还是编译后都是像Java变量那样,就可以加该注解】

@JvmStatic: 将对象的方法编译成Java静态方法【对于Kotlin的伴生对象或者对象里面的方法,如果我们希望看起来真的像Java里面的静态方法的话,就可加该注解】

@JvmOverloads: 默认参数生成重载方法。【主要i是针对Kotlin中的默认参数。如果一个方法定义了一个默认参数,Java是不能看到它的,Java中并没有默认参数这个概念。如果想让Java享受到这个特性,就可以加该注解来标注这个方法。这样编译器就会为我们生成很多的重载方法,在Java中就可以方便的使用了】

@file: JvmName: 指定Kotlin文件编译后的类名。【像高级函数以及 在某一个文件中为类定义的扩展方法等等,他们在编译之后实际上都会被包含到一个类当中。在Java我们都会通过这个类来访问他们,这个类的名字默认是”Kotlin文件名Kt“,可以通过JVM类来指定这个文件编译后的名字】

5.NoArg 与AllOpen:

这2个插件。dataclass 因为它本身的属性导致它并没有一个默认的无参构造方法,这对于某些ORM框架或者像json这样的需要序列化和反序列化的框架来说是一个障碍。所以官方推出了NoArg插件,它可以在编译的时候为这些类生成一个默认无参构造方法。

其中,NoArg还支持Jpa注解,如 @Entity

而AllOpen插件 是为标注的类去掉final,允许被继承。因为在Kotlin中,所有的类默认是final,无法被继承。这对于像spring他们在编译的时候会为某些类生成它的子类,如果这个类是final的话,这个行为就不会被允许了。因此,官方推出了AllOpen这个插件。

其中,其支持Spring注解,如@Component

还可以支持自定义注解类型,例如@PoKo

6.泛型:【Koltin里面的泛型和Java里的泛型没有太大的差别】

不同之处:

通配符Kotlin的*对应于Java的?     _____这是因为?在Kotion的作用太大了

协变和逆变 out/in  _____由java中的extends和super变成了out/in

例如:ArrayList<out String >

没有Raw类型:_____在Java中Raw类型 的产生主要源于java 1.5之前根本没有泛型这个特性。【Kotlin没有这样的包袱了,所以没有Raw类型】

例如:像Java中的list这种不带泛型参数的写法就称之为Raw类型,对应于Kotlin里面就要写成List<*>


2.SAM转换

实例化Runnable的过程,反编译后会发现一个实例,这个实例实际上就是lambda表达式。

  1. val samInJava = SAMInJava()
  2. samInJava.addTask {
  3. }

说明对于像Runnable这样的Java接口,它只有一个接口方法,那么我们可以在Kotlin中用一个lambda表达式来替代它。在编译的时候,编译器会帮我们把这个lambda表达式变成它。

例如:

  1. Executors.newCachedThreadPool().submit {
  2. }

SAM转换:

Single Abstract Method

SAM转换的条件:

 java接口,单一接口方法。

注意转换后的实例变化。每次用lamda转换成runnable之后,runnable的实例都是不同的。


3.正则表达式

在Kotlin中用Raw字符串定义正则表达式。【比Java方便很多,少了很多的转义】

Java的Pattern在kotlin中也可以直接使用。

或者直接使用Kotlin中的Regex写出更符合kotlin风格的代码。

3.1 在Java中这么用正则表达式写一个例子:

  1. public class Main {
  2. public static void main(String... args) {
  3. String source = "Hello, This my phone number: 010-12345678. ";
  4. String pattern = ".*(\\d{3}-\\d{8}).*";
  5. Matcher matcher = Pattern.compile(pattern).matcher(source);
  6. while(matcher.find()){
  7. System.out.println(matcher.group());
  8. System.out.println(matcher.group(1));
  9. }
  10. }
  11. }

3.2 在Kotlin中的等效的写法:(照抄的java)

  1. fun main(args: Array<String>) {
  2. val source = "Hello, This my phone number: 010-12345678. "
  3. val pattern = """.*(\d{3}-\d{8}).*"""
  4. val matcher = Pattern.compile(pattern).matcher(source)
  5. while (matcher.find()) {
  6. println(matcher.group())
  7. println(matcher.group(1))
  8. }
  9. }

3.3 kotlin也有自己的方式处理正则表达式:[kotlin自身的正则表达式]

  1. fun main(args: Array<String>) {
  2. val source = "Hello, This my phone number: 010-12345678. "
  3. val pattern = """.*(\d{3}-\d{8}).*"""
  4. Regex(pattern).findAll(source).toList().flatMap(MatchResult::groupValues).forEach(::println)
  5. }

findAll()返回的是一个软序列。flatMap(MatchResult::groupValues)相当拿到了一个groupvalues的集合。Kotlin对上面的转义的支持,比如java中需要把\d中的斜杠转移正正则表达式中的斜杠,即写为//d。但是kotlin中有RawString,所以上面的代码不用考虑转义斜杠了。


4.集合框架

kotlin没有自己造轮子,所以它可以用java里面中的所有东西。

比如:java中的一个问题,我们remove(0),假设这个list存放的是整型,那我们到到底是remove索引为0的元素还是remove掉list中0这个整型对象呢。

针对此,kotlin改善了下。通过索引remove掉,就写为lsit.removeAt(int index).;list.remove(obejct)

 【::println是针对println函数的引用。其他的以次类推。】

集合注意可变和不可变。【不可变的集合返回的是kotlin内部它自定义的一个集合。因此我们无权对它进行put等操作。但是Java调用不可变的时候它统一可变的,假设此时在java中调用它并add等操作就会报错,因为它返回的List根本就没实现add和put等操作】

这些可变和不可变的集合都会被映射成java中对应的集合。

需要注意的细节:

Kotlin到Java的类型映射。

不可变与可变集合接口。

kotlin对这些集合框架部分接口做了优化。比如remove和removeAt


5.IO操作

File、Stream、Reader、Writer的扩展方法.

使用use扩展自动关闭资源。

小文件readLines()、readText()、readBytes()一次性读写操作。

5.1 用java读写一个文件的例子:

  1. public class IO {
  2. public static void main(String... args) {
  3. BufferedReader bufferedReader = null;
  4. try {
  5. bufferedReader = new BufferedReader(new FileReader(new File("build.gradle")));
  6. String line;
  7. while((line = bufferedReader.readLine()) != null){
  8. System.out.println(line);
  9. }
  10. } catch (FileNotFoundException e) {
  11. e.printStackTrace();
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. } finally {
  15. try {
  16. bufferedReader.close();
  17. } catch (IOException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. }
  22. }

5.2 Kotlin照抄上面的代码:

  1. fun main(args: Array<String>) {
  2. val file = File("build.gradle")
  3. val bufferedReader = BufferedReader(FileReader(file))
  4. var line: String
  5. while(true){
  6. line = bufferedReader.readLine()?:break
  7. println(line)
  8. }
  9. bufferedReader.close()
  10. }

注意line = bufferedReader.readLine()?:break中的line = bufferedReader.readLine()它实际上是一个赋值语句,它并没有把line的值作为返回值。这个和java不一样。所以不能在while中直接写 while((line = bufferedReader.readLine()) != null),所以上面的代码直接写为while(true)了。

5.3 Kotlin中的先进写法:【传统写法常常忘记close】

          解决这个问题,Closeable可以为 我们自动关闭,use实际上就是这个东西的扩展方法了。它可以为我们closeable接口的实例来提供自动关闭的操作。

  1. fun main(args: Array<String>) {
  2. val file = File("build.gradle")
  3. BufferedReader(FileReader(file)).use {
  4. var line: String
  5. while(true){
  6. line = it.readLine()?:break
  7. println(line)
  8. }
  9. }
  10. }

所以写在use里面的不用我们去手动关闭:

对于一些小文件,kotlin提供了一些更简单的方法,例如:

  1. fun main(args: Array<String>) {
  2.     File("build.gradle").readLines().forEach(::println)
  3. }

6.装箱和拆箱

了解kotlin基本类型到java的映射关系。【映射是编译器自动帮我们去做的】

注意规避基本类型相关的的问题【因为kotlin不再区分java中的基本类型和装箱类型】

kotlin中的int 类型和Integer装箱类型 合二为一变为 ”Int“(float、 double也是)

  1. .java:
  2. public interface BoxIf1 {
  3. String get(int key);
  4. String get(Integer key);
  5. }

在kotlin中去实现它:

  1. class BoxImpl1: BoxIf1 {
  2.     override fun get(key: Int): String {
  3.         return "Hello"
  4.     }
  5. //    override fun get(key: Int?): String {
  6. //        return "Hello"
  7. //    }
  8. }

看上去没什么问题。

 

再看另外一个接口:

  1. public interface BoxIf2 extends Map<Integer, String> {
  2. String get(int key);
  3. String get(Integer key);
  4. }

然后kotlin中去实现它:

  1. class BoxImpl2: BoxIf2 {
  2. override val size: Int
  3. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  4. override fun containsKey(key: Int?): Boolean {
  5. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  6. }
  7. override fun containsValue(value: String?): Boolean {
  8. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  9. }
  10. override fun get(key: Int): String? {
  11. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  12. }
  13. override operator fun get(key: Int): String? {
  14. return "Hello"
  15. }
  16. override fun isEmpty(): Boolean {
  17. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  18. }
  19. override val entries: MutableSet<MutableMap.MutableEntry<Int, String>>
  20. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  21. override val keys: MutableSet<Int>
  22. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  23. override val values: MutableCollection<String>
  24. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  25. override fun clear() {
  26. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  27. }
  28. override fun put(key: Int?, value: String?): String? {
  29. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  30. }
  31. override fun putAll(from: Map<out Int, String>) {
  32. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  33. }
  34. override fun remove(key: Int?): String? {
  35. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  36. }
  37. }

发现会爆红。

因为kotlin中的Map把get()_方法变成了operator方法,并且参数Key和java中有不同之处。java中的get()的参数是object。这实际上是kotlin编译器为我们做的一个优化。所以在此处没办法写出一个合适的方法满足这个接口。

  1. override fun get(key: Int): String? {
  2. // TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  3. // }
  4. //
  5. // override operator fun get(key: Int): String? {
  6. // return "Hello"
  7. // }
  8. //

这2个get方法冲突。所以用koitlin不能直接去实现这个接口。

这个时候只能写一个中间的java类(复写get方法,那么kotlin就不会去访问它了)。让kotlin直接去继承这个类来解决这个问题:

  1. public abstract class AbsBox implements Map<Integer, String> {
  2. public String get(Object key) {
  3. return null;
  4. }
  5. }

kotlin去继承这个中间类:

  1. class BoxImpl3: AbsBox() {
  2. override fun get(key: Int): String {
  3. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  4. }
  5. override val size: Int
  6. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  7. override fun containsKey(key: Int?): Boolean {
  8. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  9. }
  10. override fun containsValue(value: String?): Boolean {
  11. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  12. }
  13. override fun isEmpty(): Boolean {
  14. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  15. }
  16. override val entries: MutableSet<MutableMap.MutableEntry<Int, String>>
  17. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  18. override val keys: MutableSet<Int>
  19. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  20. override val values: MutableCollection<String>
  21. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
  22. override fun clear() {
  23. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  24. }
  25. override fun put(key: Int?, value: String?): String? {
  26. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  27. }
  28. override fun putAll(from: Map<out Int, String>) {
  29. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  30. }
  31. override fun remove(key: Int?): String? {
  32. TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
  33. }
  34. }

7.注解处理器

apply plugin: "kotlin-kapt"

注意添加生成的代码到SourceSets、

注意IntelliJ有些还不支持注解处理器的编译,需要在右侧的gradle手动点击build。

  1. interface GitHubService{
  2. @GET("/repos/enbandari/Kotlin-Tutorials/stargazers")
  3. fun getStarGazers(@Query("page") page: Int = 1, @Query("per_page") pageSize: Int = 20): Call<List<User>>
  4. }
  5. object Service {
  6. val api: GitHubService by lazy {
  7. DaggerRESTFulComponent
  8. .builder()
  9. .build()
  10. .retrofit()
  11. .create(GitHubService::class.java)
  12. }
  13. }
  14. fun main(args: Array<String>) {
  15. Service.api.getStarGazers().execute().body().map(::println)
  16. }

上述代码Dagger要i使用到注解处理器:

在build.gradle中添加:apply plugin: "kotlin-kapt"

然后build,可以在build文件夹下为我i们生成了很多文件。

并在build.gradle中添加这些文件的路径:

sourceSets{    main.kotlin.srcDirs += "build/generated/source/kapt/main"}

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/580848
推荐阅读
相关标签
  

闽ICP备14008679号