百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

超干货详解:kotlin(4) java转kotlin潜规则

liuian 2025-03-25 15:18 30 浏览

前言

以一个java老鸟的角度,如何去看 kotlin。 Java源代码应该如何用Kotlin重构。 如何正确学习kotlin并且应用到实际开发中。本文将会探究。

本文分两大块,重难点和潜规则。

重难点:Kotlin中可以独立出来讲解的大块知识点。提供单独Demo。这部分大多数是Kotlin开创的新概念(相比于Java)。

潜规则:Kotlin是谷歌用来替换Java的,它和java百分百完全兼容,但是实际上java转成kotlin之后,需要我们手动修改很多东西,甚至某些部分必须打散重构来达到最优编码。其中,kotlin的某些特性和java不同,甚至完全反转。这部分知识点比较零碎,单独Demo不方便提供,就以小例子的形式来写。

  • 重难点lambda以及操作符高阶函数以及操作符Kotlin泛型集合操作协程操作符重载
  • 潜规则Kotlin文件和类不存在一对一关系共生体继承修饰符空指针问题

潜规则

从Java转到kotlin,基本上都会存在java代码与kotlin共存的问题。而且为了快速转型,可能会直接把java类转成kotlin类,而这个过程中,涉及到java和kotlin的交互,往往会磕磕碰碰,以下总结了一部分 java kotlin交互方面的问题.

Kotlin文件和类不存在一对一关系

kotlin的文件,可以和类名一致,也可以不一致。这种特性,和c++有点像,毕竟c++的.h 和 .cpp文件是分开的。只要最终编译的时候对的上,文件名其实无所谓的。Java中,一个类文件的类名和文件名不一致,如果是public类,就会报异常。

在kotlin中,可以写成一致,如:


不一致:


这样做的意义在于:

如果有很多个行数很短的类:在java中可能要占用大量的文件个数(Java中可以用内部类的形式解决),kotlin中则可以把这些类都放到同一个kt文件中,不用内部类也能解决。

共生体

Java中的静态 static关键字,在kotlin中不复存在,作为替换,Kotlin提出了共生体的概念。如果是kt文件去调用kt类的“静态”方法(不依赖对象),则要求后者的类结构中增加一个 companion object 成员变量。并且可以在 成员中写上 你想要定义的"静态"成员变量和成员方法

class Test001(_name: String) : Person(_name) {
    companion object {
        const val s: String = ""
        const val s2: String = ""

        fun t1(){

        }
    }
}

fun main(){
    Test001.s
    Test001.t1()
}

注:每一个kotlin类中,只能有一个共生体对象.

但是在java调用kt的"静态"成员方法时,必须带上共生体,但是,访问"静态"成员变量,则不能带:

public static void main(String[] args) {
        Test001.Companion.t1();//Java访问kt的t1()共生体方法,必须带上Companion
        String s2 = Test001.s;// 而访问共生体成员变量,不能带Companion
 }

好纠结。为什么要这么设计。算了。查了一下kt反编译之后的Java源码:

共生体变成了Java类中的静态内部类,包含t1()方法。而s,s2 则是普通的静态变量。

修饰符

修饰符指的是 类 和 成员变量,成员方法 前面的 权限访问关键字。原 Java拥有 private ,protected,default ,public ,访问权限分别为: 本类内部,同包名或子类,同包名,全局。

然而,kotlin新增了一个概念,internal ,表示,相同Module内可访问,跨Module则不行。

并且,java和kotlin的 private ,protected,default ,public 的访问权限还有区别,但是我这里就不详述了,因为我觉得意义不大。能不能访问,写代码的时候编译器会告诉你,当场警告你,你就会修改代码。如果有问题。可以把kotlin Decompile成Java代码自己去对比试试。如有需要,后期再说吧。

空指针问题

通常要快速的将 旧java代码转化成kotlin代码,是拷贝java代码粘贴到kotlin文件内,让as自动转化,但是这种方式,容易造成很多空指针问题,有一些是很直白的报了编译错误,而有一些则是隐藏起来,等到程序运行时才会报错。直接报错的就不提了,下面演示隐藏的空指针问题:

Kotlin类:

class Student(name:String) {
    var name: String = name

    fun showName(tag: String) {
        println("$tag : $name")
    }
}

Java调用kt:

public class Main {
    public static void main(String[] args) {
        Student s = new Student("zhou");
        s.showName(null);
    }
}

此时,如果运行main函数,就会报出:

告诉我们参数tag不可为null。但是奇怪的是,在java代码中,居然不会报编译错误。贼特么诡异。

解决方案:

在方法参数后面加上问号,变成这样:

没有基本数据类型

Kotlin之中没有基本数据类型,它只有:Int,Short,Long,Float,Double,Byte ,Char,Boolean 这样的包装类型。为什么没有?没有必要去纠结,但是只提供包装类型有一个好处,那就是 方便扩展函数的定义。我们可以很轻松地对 Int,类型去扩展函数。比如: Kotlin自带了很多扩展函数:

这是系统定的,我们也可以自己来定义:

fun Int.plus100(): Int {//自定义扩展
    return this + 100
}
fun main() {
    val a: Int = 20
    println("${a.plus100()}")
}

继承

在用kt重构部分模块的过程中,我发现频繁出现下面的问题:

Kotlin基类:

abstract class Person(name: String) {
    var name: String? = name
}

Java子类:

由于我是从基础类开始重构,所以,在原先的Java代码中频繁出现了类似这种 访问权限不足的问题。一个一个去改成setName函数,工作量巨大。后来找到一个办法:

在kotin中加入 @JvmField 变成这样:

abstract class Person(name: String) {
    @JvmField
    var name: String? = name
}

@JvmField可以让 kotlin的成员属性变成公有的,kt转化成java时,会是如下这样:

public abstract class Person {
   @JvmField
   @Nullable
   public String name;

   public Person(@NotNull String name) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.name = name;
   }
}

兼容原先的Java代码。不用大面积修改了。

默认支持可选命名参数

了解高级语言语法的同学肯定知道 可选命名参数可选位置参数,经测试: Kotlin的任何方法(包括构造方法和普通和方法),可以这么写:

fun test001(s: String, s1: String) {
    println("$s -  $s1")
}

fun main() {
    test001(s = "1111", s1 = "2222") //卧槽,Kotlin默认支持 可选命名参数
}

这种特性可以很好的避免了Java中出现的一个方法包含N个参数 把人眼睛看花的情况:

private void test(String s1, String s2, String s3, String s5, String s6, String s7, String s8, String s9, String s10, String s11, String s12) {
        //...
    }

比如如上面所示,一个方法,有12个String参数,看多了会骂娘,谁特么写的。然而,用kotlin:

fun test(s1: String, s2: String, s3: String, s4: String, s5: String, s6: String, s7: String, s8: String, s9: String, s10: String, s11: String, s12: String) {}
fun main() {
    test(s1 = "",s2 = "",s3 = "",s4 = "",s5 = "",s6 = "",s7 = "",s8 = "",s9 = "",s10 = "",s11 = "",s12 = "")
}

直觉上这种语法,融入了 建造者设计模式。让同一个函数的多个参数不再混乱。当然如果你怀旧的话,你也可以用原始方法,12个string依次摆下去。反正我不会这么做。

类,成员方法 默认封闭

和Java相反,kotlin给类,成员方法 都采用了默认封闭原则。具体体现为:类,默认不可继承,成员方法默认不可重写(继承时)。如果要继承类,或者重写父类方法,必须在父类中手动加入 open 关键字,子类中重写方法必须加上override关键字 :

kotlin父类:

open class Student(name:String) {
    var name: String = name

    open fun showName(tag: String?) {
        println("$tag : $name")
    }
}

kotlin子类:

class StudentExt(name: String) : Student(name) {
    override fun showName(tag: String?) {
        super.showName(tag)
        println("xxxxx")
    }
}

Kotlin中方法和函数的区别

函数,是c/c++的词汇,而方法,则是Java里面。现在kotlin中同时存在了方法和函数,那么区别在哪里?

通常我们人为:在Kotlin类内部,称为成员方法。而在类外部定义的,则成为全局函数(这里就不用去讨论kotlin变成java之后长什么样)。

应用到具体场景,一句话解释清楚:

A.kt 中有一个A类,它有a()成员方法。 同时我们可以在 B.kt中给A类扩展一个函数。创建一个A类对象之后,我们既可以调用a()成员方法,又可以调用它的扩展函数。

A.kt

class A {
    fun a() {}
}

B.kt

fun A.foo(){}// 扩展A的一个函数

fun main() {
    val a = A()//创建对象
    a.a() //调用成员方法
    a.foo() //调用扩展函数
}

结语

Java转kotlin,给我的感觉就是:

  1. kotlin对于一个function内部的管理更加有条理,它引入了 scope 作用域的概念,利用基于lambda表达式的高阶函数,把function内部的代码块管理起来,让代码可读性更高
  2. kotlin的代码行数会大大减少,因为kotlin设计了很多顶层函数,高阶函数,使用大量的链式调用,把可以占用行数的代码都浓缩在一行。这样做的结果是,一行代码的信息量大大增加,对于新手是噩梦,但是对于kotlin熟手,会感觉很美妙。
  3. 关于协程,本文只做了最简单的管中窥豹描述,未曾详细说到的东西还有很多。但是可以肯定一点,协程的出现,颠覆了 android开发的异步编程思维,原本很多不敢想的,原本很多java实现起来要绕很多路的,在kotlin上都可以很优雅地实现。

参考资料

Kotlin in Action 下载pdf书籍:(
https://www.7down.com/soft/209822.html)

菜鸟教程:
https://www.runoob.com/kotlin/kotlin-tutorial.htmlkotlin

中文站: https://www.kotlincn.net

最后,今天的分享到这里就结束了,小编这里也给大家整理了一份阿里的资源文档,算是当做福利送给大家吧。

免费领取方式,本文转发+关注私信资料 即可

这里小on 祝大家学业昌隆哦!!!

相关推荐

搭建一个20人的办公网络(适用于20多人的小型办公网络环境)

楼主有5台机上网,则需要一个8口路由器,组网方法如下:设备:1、8口路由器一台,其中8口为LAN(局域网)端口,一个WAN(广域网)端口,价格100--400元2、网线N米,这个你自己会看了:)...

笔记本电脑各种参数介绍(笔记本电脑各项参数新手普及知识)

1、CPU:这个主要取决于频率和二级缓存,频率越高、二级缓存越大,速度越快,现在的CPU有三级缓存、四级缓存等,都影响相应速度。2、内存:内存的存取速度取决于接口、颗粒数量多少与储存大小,一般来说,内...

汉字上面带拼音输入法下载(字上面带拼音的输入法是哪个)

使用手机上的拼音输入法打成汉字的方法如下:1.打开手机上的拼音输入法,在输入框中输入汉字的拼音,例如“nihao”。2.根据输入法提示的候选词,选择正确的汉字。例如,如果输入“nihao”,输...

xpsp3安装版系统下载(windowsxpsp3安装教程)

xpsp3纯净版在采用微软封装部署技术的基础上,结合作者的实际工作经验,融合了许多实用的功能。它通过一键分区、一键装系统、自动装驱动、一键设定分辨率,一键填IP,一键Ghost备份(恢复)等一系列...

没有备份的手机数据怎么恢复

手机没有备份恢复数据方法如下1、使用数据线将手机与电脑连接好,在“我的电脑”中可以看到手机的盘符。  2、将手机开启USB调试模式。在手机设置中找到开发者选项,然后点击“开启USB调试模式”。  3、...

电脑怎么激活windows11专业版

win11专业版激活方法有多种,以下提供两种常用的激活方式:方法一:使用激活密钥激活。在win11桌面上右键点击“此电脑”,选择“属性”选项。进入属性页面后,点击“更改产品密钥或升级windows”。...

华为手机助手下载官网(华为手机助手app下载专区)

华为手机助手策略调整,已不支持从应用市场下载手机助手,目前华为手机助手是需要在电脑上下载或更新手机助手到最新版本,https://consumer.huawei.com/cn/support/his...

光纤线断了怎么接(宽带光纤线断了怎么接)

宽带光纤线断了可以重接,具体操作方法如下:1、光纤连接的时候要根据束管内,同色相连,同芯相连,按顺序进行连接,由大到小。一般有三种连接方法,分别是熔接、活动连接和机械连接。2、连接的时候要开剥光缆,抛...

深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
  • 深度操作系统安装教程(深度操作系统安装教程图解)
win7旗舰版和专业版区别(win7旗舰版跟专业版)

1、功能区别:Win7旗舰版比专业版多了三个功能,分别是Bitlocker、BitlockerToGo和多语言界面; 2、用途区别:旗舰版的功能是所有版本中最全最强大的,占用的系统资源,...

万能连接钥匙(万能wifi连接钥匙下载)

1、首先打开wifi万能钥匙软件,若手机没有开启WLAN,就根据软件提示打开WLAN开关;2、打开WLAN开关后,会显示附近的WiFi,如果知道密码,可点击相应WiFi后点击‘输入密码’连接;3、若不...

雨林木风音乐叫什么(雨林木风是啥)

雨林木风的创始人是陈年鑫先生。陈年鑫先生于1999年创立了雨林木风公司,其初衷是为满足中国市场对高品质、高性能电脑的需求。在陈年鑫先生的领导下,雨林木风以技术创新、产品质量和客户服务为核心价值,不断推...

aics6序列号永久序列号(aics6破解序列号)

关于AICS6这个版本,虽然是比较久远的版本,但是在功能上也是十分全面和强大的,作为一名平面设计师的话,AICS6的现有的功能已经能够应付几乎所有的设计工作了……到底AICC2019的功能是不是...

win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
  • win7正在启动windows 卡住(win7正在启动windows卡住了 进入安全模式)
手机可以装电脑系统吗(手机可以装电脑系统吗怎么装)

答题公式1:手机可以通过数据线或无线连接的方式给电脑装系统。手机安装系统需要一定的技巧和软件支持,一般需要通过数据线或无线连接的方式与电脑连接,并下载相应的软件和系统文件进行安装。对于大部分手机用户来...