Kotlin,简直是 Java 的 Pro Max!(笔记2)

2024-03-20 13:28
文章标签 java 笔记 kotlin pro max 简直

本文主要是介绍Kotlin,简直是 Java 的 Pro Max!(笔记2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

as - 类型转化

静态方法的声明

object 修饰类中所有方法类似 “静态”

companion object 修饰个别方法类似 “静态”

@JvmStatic 修饰一个方法为静态方法

顶层方法为静态

静态变量的声明

object 类中定义

companion object 定义静态变量

顶层定义静态变量

标准函数

let

with

run

apply

inner - 非静态内部类声明

lateinit 懒加载

sealed 密封类


as - 类型转化

例如 List 从 可变到不可变.

    val a = mutableListOf(1, 2, 3)val b = a as List<Int>

静态方法的声明

object 修饰类中所有方法类似 “静态”

和 Java 一样通过类名就可进行对方法的调用,但其并非是真正的静态方法.

object Test {fun test() {println("我并非是真的静态方法~")}
}fun main() {Test.test()
}

对应的 Java 文件如下:

实际上,这只是 Kotlin 提供的语法糖,通过静态代码块初始化内部持有的静态 Test 对象.

companion object 修饰个别方法类似 “静态”

如果我们只想让某些方法变成类似静态方法,就可以通过 companion object 实现

class Test {companion object {fun test1() {println("我是静态的")}}fun test2() {println("我是非静态的")}
}fun main() {Test.test1()
}

Java 如下:

public final class Test {@NotNullpublic static final Companion Companion = new Companion((DefaultConstructorMarker)null);public final void test2() {String var1 = "我是非静态的";System.out.println(var1);}public static final class Companion {public final void test1() {String var1 = "我是静态的";System.out.println(var1);}private Companion() {}// $FF: synthetic methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}
}public final class TestKt {public static final void main() {Test.Companion.test1();}// $FF: synthetic methodpublic static void main(String[] var0) {main();}
}

实际上是 Test 类内部存在一个 Companion 的静态内部类,而在 Test 中又 new 了一个 Companion 对象,并修饰为 static.

因此调用的时候是通过 Test 类名调用其中的静态对象 Companion,在该对象调用内部的非静态方法 test1().

@JvmStatic 修饰一个方法为静态方法

要想使用真正的静态方法,必须要通过 @JvmStatic,并且其注解只能在 companion object 内部的方法上.

public final class Test {@NotNullpublic static final Companion Companion = new Companion((DefaultConstructorMarker)null);public final void test2() {String var1 = "我是非静态的";System.out.println(var1);}@JvmStaticpublic static final void test1() {Companion.test1();}public static final class Companion {@JvmStaticpublic final void test1() {String var1 = "我是静态的";System.out.println(var1);}private Companion() {}// $FF: synthetic methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}
}

可以发现有两个 test1() 方法,一个是 Test 类的 test1 静态方法,一个是静态内部类中的非静态方法,调用时是通过调用 Test 中的静态方法,进而在静态方法内部继续调用静态内部类中的非静态方法.

这样设计主要是为了兼容 Java 的调用.  如果 Java 和 Kotlin 混写,需要在 Java 代码中调用到真正的静态方法,才需要使用该注解,否则没必要.

顶层方法为静态

在 Kotlin 文件中的类外直接写变量会变成静态的,方法也是如此.

创建 kt 文件,命名为 Solution,然后直接写一个 test 方法,如下:

fun test() {}

对应的 Java 代码如下:

public final class SolutionKt {public static final void test() {}
}

静态变量的声明

object 类中定义

Kotlin 如下

object Solution {val aaa = 1}

对应 Java 如下: 

public final class Solution {private static final int aaa;@NotNullpublic static final Solution INSTANCE;public final int getAaa() {return aaa;}private Solution() {}static {Solution var0 = new Solution();INSTANCE = var0;aaa = 1;}
}

可以看到,这里的 aaa 也是通过静态代码块初始化的.

如果 Java 想要调用该类中的静态变量 aaa,需要通过 public 的 instance 实例才能调用到,如果在 Java 中想直接调用,可以通过 const 来解决.

object Solution {const val aaa = 1
}

对应的 Java 如下:

public final class Solution {public static final int aaa = 1;@NotNullpublic static final Solution INSTANCE;private Solution() {}static {Solution var0 = new Solution();INSTANCE = var0;}
}

可以看出,通过 const 直接将 aaa 修饰成  public.

companion object 定义静态变量

和上面的 object 定义几乎没区别.

class Solution {companion object {val aaa = 1}
}

对应的 Java 代码:

public final class Solution {private static final int aaa = 1;@NotNullpublic static final Companion Companion = new Companion((DefaultConstructorMarker)null);public static final class Companion {public final int getAaa() {return Solution.aaa;}private Companion() {}// $FF: synthetic methodpublic Companion(DefaultConstructorMarker $constructor_marker) {this();}}
}

另外 const 修饰后可在 Java 中直接调用,没有 const 在 Java 中需要借助静态对象获取.

 

顶层定义静态变量

在 Solution.kt 中直接定义全局变量

val aaa = "hello"

对应 Java 如下:

public final class SolutionKt {@NotNullprivate static final String aaa = "hello";@NotNullpublic static final String getAaa() {return aaa;}
}

标准函数

let

let 是一个函数,提供了函数式 API 接口,会将调用者作为参数传递到 Lambda 表达式,调用之后会立马执行 Lambda 表达式的逻辑.

aaa.let { it ->  // it 就是 aaa(调用者)//执行业务逻辑
}

作用:主要用于对象辅助判空操作

fun test(name: String?) {//不为空才执行内部逻辑name?.let {println("name: $it") //it 就是 name}}fun main() {test(null)
}

with

with 用来接收两个参数,一个是任意类型,另一个是 Lambda 表达式,第一个参数会传给 Lambda 使用. 

Lambda 内部执行的方法都是 with 的第一个参数所提供的.

Lambda 的最后一行代码会当成返回值返回.

class Test {fun test1() {println("test1")}fun test2() {println("test2")}
}fun main() {val result = with(Test()) {//this 就表示 obj,一般省略 thistest1()test2()"ok"}println(result)
}

作用:主要用于简化对一个对象中多个方法的调用,避免在每次调用方法时都重复写对象名. 使用场景通常是需要对一个对象进行多个操作,

例如如下场景可读性提高了不少

data class Student(val name: String,val age: Int,val gender: Int
)fun main() {val student = Student("cyk", 18, 1)val result = with(student) {println("name: $name, age: $age, gender: $gender")"ok"}
}

run

run 与 with 的使用场景类似,唯一不同的是 run 是在对象上调用,且需要一个 Lambda 参数

data class Student(val name: String,val age: Int,val gender: Int
)fun main() {val student = Student("cyk", 18, 1)val result = student.run {println("name: $name, age: $age, gender: $gender")"ok"}
}

如果说 with 和 run 到底有什么使用场景上的区别,那么就是:

  • with 更强调对对象的属性方法的带入一个代码块中,使得代码可读性提高
  • run 常常用于创建一个临时的作用域,并在这个作用域中执行一些操作,然后返回结果,提高代码可读性.

run 实际上也经常这样玩(和 with 就区别开了):

    val result = run {val a = 1val b = 2a + b}

apply

apply 和 run 相似.  不同的是必须要要在对象上调用,并且返回值是调用对象本身.

    val list = listOf("beef", "fish", "egg")//吃东西val result = StringBuilder().apply {append("开始吃")list.forEach { str ->append(str)}append("吃完了")}

inner - 非静态内部类声明

inner 用于修饰内部类为非静态的

Kotlin 中内部类默认是静态的,这意味在着他们没有外部类实例的隐式调用,减少了内存泄露的可能性.  然而,如果一定要在内部类中访问外部类的成员,就可以使用 inner 关键字来声明内部类,使其变为非静态的.

Ps:为什么静态内部类可以减少内存泄露的可能?因为静态内部类无法持有外部类的隐式调用.  换言之,如果一个内部类不是静态的,那么他会持有外部类的隐式调用,也就意味着,只要内部类实例存在,外部类的实例就不会被垃圾回收器回收.

例如如下示例,Student 中调用就可以拿到 name,而 Teacher 中则不可以.

class Human {private val name = 1inner class Student {fun test () {println("name: $name") //正确}}class Teacher {fun test() {println("name: $name") //报错}}}

Kotlin 示例如下:

class Human {inner class Student {}class Teacher {}}

对应的 Java 如下:

public final class Human {public final class Student {}public static final class Teacher {}
}

lateinit 懒加载

a)写 Kotlin 的时候可能会常常遇到一个问题:“ 就是有时候我们并不想给某个变量在声明的时候就进行初始化,此时只能给这个对象赋值为 null,又由于 Kotlin 的空检查,类型必须加上 才能编译通过,很不方便.

如下代码:

fun test(): String {var result: String? = nullif(true) {result = "yes"} else {result = "no"}return result
}

想要解决上述问题,就需要使用 lateinit 关键字:

fun test(): String {lateinit var result: Stringif(true) {result = "yes"} else {result = "no"}return result
}

Ps:上述代码中,若函数结束还未初始化 result,就会抛出 UninitializedPropertyAccessException 异常 

b)另外,Kotlin 提供了语法检查此对象是否有初始化


lateinit var result: String
fun test(): String {if(!::result.isInitialized) { //未初始化result = "yes"} else { //已初始化result = "no"}return result
}

此处的 :: 为固定写法,记住就行.

sealed 密封类

a)先来看一个栗子:

定义 result 接口

interface Result
class Success(val code: Int): Result
class Failure(val code: Int): Result

方法如下:

fun getResultCode(result: Result) = when(result) {is Success -> {println("ok")result.code}is Failure -> {println("非法 code: ${result.code}")result.code}else -> throw IllegalArgumentException()
}

由于 Kotlin 的 when 特性,else 必须写,但是上述有些情况 else 纯属多余.

想要解决上述问题,需要借助 sealed,密封类以及子类只能定义在同一个文件的顶层位置,不可嵌套在其他类中.

b)使用密封类修改上述代码:

sealed class Result
class Success(val code: Int): Result()
class Failure(val code: Int): Result()fun getResultCode(result: Result) = when(result) {is Success -> {println("ok")result.code}is Failure -> {println("非法 code: ${result.code}")result.code}
}

此时就可以去掉 else,当 when 传入参数为密封类时,则分支必须包含其全部子类,否则编译不通过.

这篇关于Kotlin,简直是 Java 的 Pro Max!(笔记2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829587

相关文章

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

Java中的密码加密方式

《Java中的密码加密方式》文章介绍了Java中使用MD5算法对密码进行加密的方法,以及如何通过加盐和多重加密来提高密码的安全性,MD5是一种不可逆的哈希算法,适合用于存储密码,因为其输出的摘要长度固... 目录Java的密码加密方式密码加密一般的应用方式是总结Java的密码加密方式密码加密【这里采用的

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题

《解决mybatis-plus-boot-starter与mybatis-spring-boot-starter的错误问题》本文主要讲述了在使用MyBatis和MyBatis-Plus时遇到的绑定异常... 目录myBATis-plus-boot-starpythonter与mybatis-spring-b