}
@JvmStatic
和 @JvmField
object Singleton {
@JvmField var x: Int = 2 //生成java的静态成员 不会生成getter和setter方法
@JvmStatic fun y(){ } //生成java的静态方法
}
普通kotlin类(非单例)中使用使用JvmField
和JvmStatic
:
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())
}
密封类:
其实就是一个只能在同一个文件中定义子类的抽象类。不得不说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 -> {
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
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 -> {
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-dSmOssxQ-1715679918346)]
[外链图片转存中…(img-qKq9SeZo-1715679918348)]
[外链图片转存中…(img-aj1wzDAe-1715679918349)]
[外链图片转存中…(img-rHBZrYyB-1715679918350)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!