Kotlin学习手记——单例、内部类、数据类、枚举类、密封类、内联类

Singleton.y()

}

@JvmStatic@JvmField

object Singleton {

@JvmField var x: Int = 2 //生成java的静态成员 不会生成getter和setter方法

@JvmStatic fun y(){ } //生成java的静态方法

}

在这里插入图片描述

在这里插入图片描述

普通kotlin类(非单例)中使用使用JvmFieldJvmStatic

class Foo {

//普通类中使用JvmField和JvmStatic

companion object {

@JvmField var x: Int = 2

@JvmStatic fun y(){ }

}

}

注意,加的注解@JvmField@JvmStatic只针对java平台的可用,其他平台并不可行。

单例的object类仍可以继承类:

object Singleton: Runnable{

override fun run() {

}

}

内部类:

在这里插入图片描述

在kotlin中类内部的class前面不写修饰符默认就是静态内部类,class前面写 inner修饰符才是java中的普通内部类,与java一样,普通内部类会持有外部类的对象引用。

class Outer {

//普通内部类 与java一样会持有外部类的引用

inner class Inner

//默认静态内部类

class StaticInner

}

fun main() {

val inner = Outer().Inner()

val staticInner = Outer.StaticInner()

}

object类内部的object类默认是静态的 不存在非静态的情况 不能定义成inner

object OuterObject {

//内部object默认是静态的 不存在非静态的情况 不能定义成inner

object StaticInnerObject

}

匿名内部类:

fun main() {

//匿名内部类

object : Cloneable {

}

}

其实就是object 省略类名直接实现接口。

匿名内部类 可用继承多个接口,java不行:

fun main() {

// 类型是混合类型:Cloneable & Runnable

val runnableCloneable = object : Cloneable, Runnable {

override fun run() {

}

}

}

实现多个接口时,它的类型是多个接口类型的混合类型。

Local class :

fun main() {

//本地函数

fun localFunc(){

println(“Hello”)

}

//对应Java的local class

class LocalClass: Cloneable, Runnable{

override fun run() {}

}

}

可以对比java的local class实现,其实就是在静态函数的内部定义一个类:

public class JavaInnerClasses {

public static void main(String… args) {

class LocalClass implements Cloneable, Runnable {

@Override

public void run() { }

}

}

}

说实话,写了这么多年代码,未曾这么干过。。

数据类:

kotlin中提供一个data关键字,data修饰的类就是一个数据类,对标java的bean类:

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

data class Person(val id: Long, val name: String, val age: Int)

与java的bean类相比,kotlin的data类不能被继承,并且属性要全部写到构造函数当中,没有无参的构造函数。确实简便了许多!

在这里插入图片描述

并且编译器会为data类生成了一些好用的方法:

val book = Book(0, “Kotlin in Action”, Person(1, “Dmitry”, 40))

//编译器生成的方法 copy component1

book.copy()

val id = book.component1()

val name = book.component2()

val author = book.component3()

其中copy()component1()等都是编译器自动生成的,component方法的意义是方便解构赋值的使用:

//解构赋值,对应的字段是通过component方法获取的

val (id, name, author) = book

关于解构:

//解构

val pair = “Hello” to “World”

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())

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

架构师筑基包括哪些内容

我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!



这份资料就包含了所有Android初级架构师所需的所有知识!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

[外链图片转存中…(img-4aZ2Fd0I-1711865187416)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

架构师筑基包括哪些内容

我花了将近半个月时间将:深入 Java 泛型.、注解深入浅出、并发编程.、数据传输与序列化、Java 虚拟机原理、反射与类加载、高效 IO、Kotlin项目实战等等Android架构师筑基必备技能整合成了一套系统知识笔记PDF,相信看完这份文档,你将会对这些Android架构师筑基必备技能有着更深入、更系统的理解。

由于文档内容过多,为了避免影响到大家的阅读体验,在此只以截图展示部分内容

注:资料与上面思维导图一起看会更容易学习哦!每个点每个细节分支,都有对应的目录内容与知识点!

[外链图片转存中…(img-jjAZrUpq-1711865187417)]
[外链图片转存中…(img-DXzPO5F5-1711865187417)]
这份资料就包含了所有Android初级架构师所需的所有知识!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值