Kotlin学习手记——单例,211本硕如何通过字节跳动、百度、美团Android面试

本文介绍了Kotlin中数据类的特性,包括其生成的Java代码、不可继承性及如何通过插件破除这一限制。同时,探讨了枚举类的使用,包括定义、构造函数、接口实现和扩展函数。接着,讨论了密封类的概念和应用场景,并给出实际示例。最后,提到了内联类的特点和作为枚举类替代方案的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

val (hello, world) = pair

data不能被继承,那么为啥不能有子类呢?

可以先看一下kotlin为data类生成的对应的java类是什么样的,查看方式,doule shift键,然后Actions中输入kotlin Bytecode显示:

在这里插入图片描述

点击Decompile即可查看对应生成的java代码

在这里插入图片描述

以下是Book的数据类对应生成的java代码

public final class Book {

private final long id;

@NotNull

private final String name;

@NotNull

private final Person author;

public final long getId() {

return this.id;

}

@NotNull

public final String getName() {

return this.name;

}

@NotNull

public final Person getAuthor() {

return this.author;

}

public Book(long id, @NotNull String name, @NotNull Person author) {

Intrinsics.checkNotNullParameter(name, “name”);

Intrinsics.checkNotNullParameter(author, “author”);

super();

this.id = id;

this.name = name;

this.author = author;

}

public final long component1() {

return this.id;

}

@NotNull

public final String component2() {

return this.name;

}

@NotNull

public final Person component3() {

return this.author;

}

@NotNull

public final Book copy(long id, @NotNull String name, @NotNull Person author) {

Intrinsics.checkNotNullParameter(name, “name”);

Intrinsics.checkNotNullParameter(author, “author”);

return new Book(id, name, author);

}

// $FF: synthetic method

public static Book copy$default(Book var0, long var1, String var3, Person var4, int var5, Object var6) {

if ((var5 & 1) != 0) {

var1 = var0.id;

}

if ((var5 & 2) != 0) {

var3 = var0.name;

}

if ((var5 & 4) != 0) {

var4 = var0.author;

}

return var0.copy(var1, var3, var4);

}

@NotNull

public String toString() {

return “Book(id=” + this.id + “, name=” + this.name + “, author=” + this.author + “)”;

}

public int hashCode() {

long var10000 = this.id;

int var1 = (int)(var10000 ^ var10000 >>> 32) * 31;

String var10001 = this.name;

var1 = (var1 + (var10001 != null ? var10001.hashCode() : 0)) * 31;

Person var2 = this.author;

return var1 + (var2 != null ? var2.hashCode() : 0);

}

public boolean equals(@Nullable Object var1) {

if (this != var1) {

if (var1 instanceof Book) {

Book var2 = (Book)var1;

if (this.id == var2.id && Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.author, var2.author)) {

return true;

}

}

return false;

} else {

return true;

}

}

}

除了类名方法名前面添加了final关键字以外,生成了许多方法,其中有重写hashCode()equals()方法,所以如果有一个类继承了data类,可能导致属性变化,从而导致hashCode()equals()方法的结果不一致。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

data类的属性最好全部为基本类型或者其他data类型,保持它的纯净性。

另外,有方法可以破除data类的不可继承性,也有网友在吐槽kotlin的这个设计,觉得它不好,其实如果你想用一个可以继承到类,只需要把data关键字去掉,建一个普通类就好了。kotlin这样设计肯定是想保持它的纯洁性,如果可继承,只会变的更复杂。

破除data类的不可继承性需要额外添加两个插件:

plugins {

id ‘org.jetbrains.kotlin.plugin.noarg’ version ‘1.4.20’

id ‘org.jetbrains.kotlin.plugin.allopen’ version ‘1.4.20’

}

noArg {

invokeInitializers = true

annotations “com.bennyhuo.kotlin.advancedtypes.dataclasses.PoKo”

}

allOpen {

annotations “com.bennyhuo.kotlin.advancedtypes.dataclasses.PoKo”

}

上面是参考学习资料当中的代码工程中的配置,然后在data类上加注解即可

@PoKo

data class Book(val id: Long, val name: String, val author: Person)

这时同样去查看Book的数据类对应生成的java代码会发现,之前的类名和get方法名前面的final关键字被移除了,也就是可以被继承使用了,同时会生成一个无参的构造函数。可见比较麻烦,非有必要,还是不要这么干。。

枚举类:

kotlin里面的枚举类跟java差不多

enum class State {

Idle, Busy

}

//枚举定义构造函数 同java

enum class State1(val id: Int) {

Idle(0), Busy(1)

}

enum class Color {

White, Red, Green, Blue, Yellow, Black

}

fun main() {

State.Idle.name // Idle

State.Idle.ordinal // 0

val state = State.Idle

//枚举全部值

val value = when (state) {

State.Idle -> { 0 }

State.Busy -> { 1 }

}

//枚举创建区间

val colorRange = Color.White … Color.Green

val color = Color.Blue //Blue不在区间内

println(color in colorRange)

}

枚举类不可继承其他类,因为枚举类有父类是enum,但是可以实现接口:

enum class State: Runnable{

Idle, Busy{

override fun run() {

println(“For Busy State.”)

}

};

override fun run() {

println(“For Every State.”)

}

}

fun main() {

State.Idle.run()

State.Busy.run()

}

枚举类可以定义扩展函数:

fun State.successor(): State? {

return State.values().let {

if (ordinal + 1 >= it.size) null

else it[ordinal + 1]

}

}

fun State.predecessor(): State? {

return State.values().let {

if (ordinal - 1 < 0) null

else it[ordinal - 1]

}

}

fun main() {

println(State.Idle.successor())

println(State.Busy.successor())

}

密封类:

在这里插入图片描述

其实就是一个只能在同一个文件中定义子类的抽象类。不得不说kotlin玩的花样很多,会玩。。。

定义方式是在类的前面加sealed关键字

sealed class PlayerState

object Idle : PlayerState()

class Playing(val song: Song) : PlayerState() {

fun start() {}

fun stop() {}

}

class Error(val errorInfo: ErrorInfo) : PlayerState() {

fun recover() {}

}

完整的示例:控制播放器播放状态的例子

data class Song(val name: String, val url: String, var position: Int)

data class ErrorInfo(val code: Int, val message: String)

object Songs {

val StarSky = Song(“Star Sky”, “https://fakeurl.com/321144.mp3”, 0)

}

sealed class PlayerState

object Idle : PlayerState()

class Playing(val song: Song) : PlayerState() {

fun start() {}

fun stop() {}

}

class Error(val errorInfo: ErrorInfo) : PlayerState() {

fun recover() {}

}

class Player {

var state: PlayerState = Idle

fun play(song: Song) {

this.state = when (val state = this.state) {

Idle -> {

Playing(song).also(Playing::start)

}

is Playing -> {

state.stop()

Playing(song).also(Playing::start)

}

is Error -> {

state.recover()

Playing(song).also(Playing::start)

}

}

}

}

fun main() {

val player = Player()

player.play(Songs.StarSky)

}

注意其中的when表达式的使用,可见它可以用来替代枚举类做类似的功能,子类的个数也是全部可枚举的。跟枚举类有相似之处。

在这里插入图片描述

内联类:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

简而言之,内联类是一种类型的包装类,类前面加inline关键字,构造器只能有一个参数,不能继承类,不能被继承,不能作为内部类。类似于java的Integer、Double这种吧,但有不同。

内联类虽然不能继承类或被继承,但是可以实现接口。

//

//只能有方法不能有属性

inline class BoxInt(val value: Int): Comparable {

override fun compareTo(other: Int)

= value.compareTo(other)

operator fun inc(): BoxInt {

return BoxInt(value + 1)

}

}

BoxInt会做编译优化,只有在需要的时候才使用包装类 多数情况下直接使用Int,可以反编译字节码生成的java代码查看。另外,还有个特点就是它只能有方法不能有属性。

内联类也可以用来模拟枚举类,与枚举相比内存占用小,但使用方式类似

inline class State(val ordinal: Int) {

companion object {

val Idle = State(0)

val Busy = State(1)

}

fun values() = arrayOf(Idle, Busy)

val name: String

get() = when (this) {

State.Idle -> “Idle”

State.Busy -> “Busy”

else -> throw IllegalArgumentException()

}

}

inline class Color(val value: UInt) {

companion object {

val Red = Color(0xFFFF0000u)

val Green = Color(0xFF00FF00u)

val Blue = Color(0xFF0000FFu)

}

fun values() = arrayOf(Red, Green, Blue)

val name: String

get() = when (this) {

Red -> “Red”

Green -> “Green”

Blue -> “Blue”

else -> throw IllegalArgumentException()

}

}

fun main() {

State.Busy

Color.Blue

var boxInt = BoxInt(5)

if(boxInt < 10){

println(“value is less than 10”)

}

val newValue = boxInt.value * 200

println(newValue)

boxInt++

println(boxInt)

}

在这里插入图片描述

密封类的实例:递归整型列表的简单实现

sealed class IntList {

object Nil: IntList() {

override fun toString(): String {

return “Nil”

}

}

data class Cons(val head: Int, val tail: IntList): IntList(){

override fun toString(): String {

资源分享

  • 最新大厂面试专题

这个题库内容是比较多的,除了一些流行的热门技术面试题,如Kotlin,数据库,Java虚拟机面试题,数组,Framework ,混合跨平台开发,等

  • 对应导图的Android高级工程师进阶系统学习视频
    最近热门的,NDK,热修复,MVVM,源码等一系列系统学习视频都有!

boxInt++

println(boxInt)

}

在这里插入图片描述

密封类的实例:递归整型列表的简单实现

sealed class IntList {

object Nil: IntList() {

override fun toString(): String {

return “Nil”

}

}

data class Cons(val head: Int, val tail: IntList): IntList(){

override fun toString(): String {

资源分享

  • 最新大厂面试专题

这个题库内容是比较多的,除了一些流行的热门技术面试题,如Kotlin,数据库,Java虚拟机面试题,数组,Framework ,混合跨平台开发,等

[外链图片转存中…(img-ik5CgM3t-1646144036021)]

  • 对应导图的Android高级工程师进阶系统学习视频
    最近热门的,NDK,热修复,MVVM,源码等一系列系统学习视频都有!

[外链图片转存中…(img-PIgA3fAL-1646144036022)]

下载方法:点赞+关注后 点击【Android高级工程师进阶学习】即可领取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值