| internal | √(模块内可见) | √(模块内可见) | √(模块内可见) |

| protected | × | √(可修饰内部类,类、以及子类可见) | √(类、以及子类可见) |

| private | √(文件) | √(文件) | √(类) |

顶级声明:指文件内直接定义的属性、函数、类、等

internal VS default

一般由SDK或者公共组件开发者用于隐藏模块内部细节实现 default 可通过外部创建相同包名来进行访问,访问控制非常弱 default 会导致不同抽象汇聚到相同的包下面 internal 可方便处理内外隔离,提升模块代码内聚减少接口暴露 internal 修饰的kotlin类或者成员在java当中可直接访问

2.Kotlin构造器以及属性的可见性?

正常的构造器默认都是public,那如何控制构造器的访问可见性呢?如下所示:

//默认为public修饰

class Person(val name: String, val age: Int)

//构造器私有化

class Person private constructor(val name: String, val age: Int)

属性可见性

//私有化属性,外部不可以进行访问

class Peron(private var age:Int,var name:String)

getter的可见性必须与属性保持一致 setter的可见性不得大于属性的可见性

如下所示:

三、kotlin类属性的延迟初始化?

=====================================================================================

1.为什么要延迟初始化?

类属性必须在构造时进行初始化,但是某些成员只有在类构造之后才会有值,所以需要延迟初始化

2.定义可null类型延迟初始化

如下所示:

private var name: String? = null

fun onCreate() {

//赋值

name = “zxf”

//使用

useName(name!!)

useName(name ?: “”)

}

fun useName(name: String) {

// TODO: 2021/7/5 do

}

3.使用lateinit初始化

如下所示:使用处不再需要空指针判断

private lateinit var name: String

fun onCreate() {

//赋值

name = “zxf”

//使用

useName(name)

useName(name)

}

fun useName(name: String) {

// TODO: 2021/7/5 tdo

}

注意:使用lateinit必须知道属性初始化以及使用的生命周期,如果在属性还没有初始化的时候进行使用,则会出现如下的异常:lateinit property name has not been initialized

Exception in thread “main” kotlin.UninitializedPropertyAccessException: lateinit property name has not been initialized

at org.example.zxf.kotlin5.DelayInitTest.onCreate(DelayInit.kt:22)

at org.example.zxf.kotlin5.DelayInitKt.main(DelayInit.kt:13)

at org.example.zxf.kotlin5.DelayInitKt.main(DelayInit.kt)

另外,可以使用isInitialized判断属性是否初始化

如下所示

fun onCreate() {

//判断是否初始化

if (::name.isInitialized){

name = “zxf”

}

//使用

useName(name)

}

4.使用lazy延迟初始化(推荐)

如下所示:

class Personal4(var age: Int) {

// 延迟初始化 只有在该属性第一次被访问到时,进行初始化

val name: String by lazy {

“zxf”

}

}

fun main() {

// 使用该属性

println(Personal4(2).name)

}

注意:如果确保被访问的属性不存在线程安全的问题,可传入LazyThreadSafetyMode.NONE参数,因为默认lazy使用synchronized做同步,若不存在线程安全的问题,传入LazyThreadSafetyMode.NONE可不做同步。

如下所示:

class Personal4(var age: Int) {

// 延迟初始化 只有在该属性第一次被访问到时,进行初始化

val name: String by lazy(LazyThreadSafetyMode.NONE) {

“zxf”

}

}

fun main() {

// 使用该属性

// println(Personal4(2).name)

DelayInitTest().onCreate()

}

5.延迟初始化方案对比

| 方案名称 | 推荐指数 | 理由 |

| — | — | — |

| 可空类型 | ⭐⭐ | 增加代码复杂度;初始化与声明分离;调用处需要做判空处理 |

| lateinit | ⭐⭐⭐ | 初始化与声明分离;调用处无需判空处理,但潜在的初始化问题可能被掩盖 |

| lazy | ⭐⭐⭐⭐⭐ | 初始化与声明内聚;无需声明可空类型 |

四、Kotlin代理Delegate

=====================================================================================

1.代理是什么?

接口代理:对象X代替当前类A实现接口B的方法

属性代理:对象X代替属性a实现getter/setter方法

关键字by:by关键字实际上就是一个代理运算符重载的符号,任何一个具备代理规则的类,都可以使用by关键字进行代理。

2.接口代理

使用传入的对象去代理接口。

如下所示:

//定义接口

interface Api {

fun a()

fun b()

fun c()

}

//定义实现类1

class ApiImpl : Api {

override fun a() {}

override fun b() {}

override fun c() {

println(“c is ApiImpl.”)

}

}

//定义实现类2

class ApiImpl1 : Api {

override fun a() {}

override fun b() {}

override fun c() {

println(“c is ApiImpl1.”)

}

}

//使用接口代理实现类包装

class ApiWrapper(private val api: Api) : Api by api {

override fun c() {

println(“c is ApiWrapper.”)

api.c()

}

}

//使用以及结果

fun main(){

ApiWrapper(ApiImpl()).c()

ApiWrapper(ApiImpl1()).c()

}

c is ApiWrapper.

c is ApiImpl.

c is ApiWrapper.

c is ApiImpl1.

2.属性代理

属性代理基本理解

属性代理是借助于代理设计模式,把这个模式应用于一个属性时,它可以将访问器的逻辑代理给一个辅助对象。

可以简单理解为属性的setter、getter访问器内部实现是交给一个代理对象来实现,相当于使用一个代理对象来替换了原来简单属性字段读写过程,而暴露外部属性操作还是不变的,照样是属性赋值和读取,只是setter、getter内部具体实现变了

属性代理的基本格式:

class Student{

var name: String by Delegate()

}

class Delegate{

operator fun getValue(thisRef: Any?, property: KProperty<*>): T{

}

operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T){

}

}

属性name将它访问器的逻辑委托给了Delegate对象,通过by关键字对表达式Delegate()求值获取这个对象。任何符合属性代理规则都可以使用by关键字。属性代理类必须要遵循getValue(),setValue()方法约定,getValue、setValue方法可以是普通方法也可以是扩展方法,并且是方法是支持运算符重载。如果是val修饰的属性只需要具备getValue()方法即可。

属性代理基本流程就是代理类中的getValue()方法包含属性getter访问器的逻辑实现,setValue()方法包含了属性setter访问器的逻辑实现。当属性name执行赋值操作时,会触发属性setter访问器,然后在setter访问器内部调用delegate对象的setValue()方法;执行读取属性name操作时,会在getter访问器中调用delegate对象的getValue方法.

常见属性代理基本使用

属性代理是Kotlin独有的特性,我们自己去自定义属性代理,当然Kotlin还提供了几种常见的属性代理实现。例如:lazy,Delegates.observable(), Delegates.vetoable() **属性代理-lazy**:代理主要用于可以初始化时候初始化而是可以延迟到之后再初始,这个在上面将延迟初始化的时候已经提到过了,这里就不多做介绍了。 **属性代理-observable**:Delegates.observable()主要用于监控属性值发生变更,类似于一个观察者。当属性值被修改后会往外部抛出一个变更的回调。它需要传入两个参数,一个是initValue初始化的值,另一个就是回调lamba, 回调出property, oldValue, newValue三个参数。

示例如下:

// 属性代理 observable

class StateManager {

// initialValue 初始值

var state: Int by Delegates.observable(0) {

// set 的时候执行当前的表达式

property, oldValue, newValue ->

println(

“”"property:$property

oldValue:$oldValue

newValue:$newValue

“”".trimMargin()

)

}

}

//使用

fun main() {

val stateManager = StateManager()

stateManager.state = 10

stateManager.state = 11

}

//输出

property:var org.example.zxf.kotlin5.StateManager.state: kotlin.Int

oldValue:0

newValue:10

property:var org.example.zxf.kotlin5.StateManager.state: kotlin.Int

oldValue:10

newValue:11

属性代理-vetoable:Delegates.vetoable()代理主要用于监控属性值发生变更,类似于一个观察者,当属性值被修改后会往外部抛出一个变更的回调。它需要传入两个参数,一个是initValue初始化的值,另一个就是回调lamba, 回调出property, oldValue, newValue三个参数。与observable不同的是这个回调会返回一个Boolean值,来决定此次属性值是否执行修改。

示例如下:

class StateManager {

var state2: Int by Delegates.vetoable(0) {

property, oldValue, newValue ->

return@vetoable newValue == 1

}

}

//使用

fun main(){

val stateManager2 = StateManager()

stateManager2.state2 = 1

stateManager2.state2 = 2

println(“stateManager2 state2 is {stateManager2.state2}”)

}

//输出

stateManager2 state2 is :1

五、Kotlin单例object

===================================================================================

0.object、companion object以及val和const val的区别

object单例

默认有一个INSTATIC的静态成员常量(static final),在静态代码块中,分配自己(new 自己)

成员变量 val 相当于 java类里面的 声明了静态常量(static final),在静态代码块中初始化值。

成员变量var相当于java类里面的 声明了静态变量(static),在静态代码块中初始化值。

方法都是对象方法。

companion object伴生对象理论上来说和object一样。

在当前类里面创建了一个Companion 的类,在当前类中,持有一个静态常量(static final),静态字段初始化的时候new Companion 对象。

里面的成员变量val 和 var 和上面的object相似,不过是在当前类中声明的,在当前类的静态代码块中初始化。

方法在用final修饰的,在Companion 对象内部声明。

这里面的 const val 和 val的区别。

const val 是以静态字段的形式初始化(编译期常量);

val 在静态代码块中初始化(运行时常量);

1.单例的多种实现方式

饿汉式:线程安全,可用。但类一加载的时候,就实例化,提前占用了系统资源

示例如下(Java):

public class Singleton {

private Singleton() {

}

private static Singleton sSingleton = new Singleton();

public static Singleton getInstance() {

return sSingleton;

}

}

懒汉式:一般配合双重检查锁 DCL使用,保证线程安全/font>

示例如下(Java):

public class Singleton {

private Singleton() {

}

private static volatile Singleton sSingleton;

public static Singleton getInstance() {

if (sSingleton == null) {

synchronized (Singleton.class) {

// 未初始化,则初始instance变量

if (sSingleton == null) {

sSingleton = new Singleton();

}

}

}

return sSingleton;

}

}

静态内部类:使用时才会加载,且加载类时初始化,线程安全

示例如下(Java):

public class Singleton {

private Singleton () {

}

private static class InnerClassSingleton {

private final static Singleton sSingleton = new Singleton();

}

public static Singleton getInstance() {

return InnerClassSingleton.sSingleton;

}

}

2.kotlin的单例模式object

单例模式:kotlin使用object修饰的单例模式采用的是饿汉式

示例如下

object Singleton {

}

反编译为java代码如下所示

public final class Singleton {

public static final Singleton INSTANCE;

private Singleton() {

}

static {

Singleton var0 = new Singleton();

INSTANCE = var0;

}

}

可以看的出,反编译之后为饿汉式的方式实现单例的。

3.object单例模式的简单使用

简单使用:一般都用做工具类使用(object不能定义构造器)

示例如下

//声明单例类

object Singleton {

var age: Int = 0

var name: String = “”

fun test() {

println(“test”)

}

}

//使用单例类

fun main() {

Singleton.age = 10

Singleton.name = “zxf”

println(Singleton.name)

Singleton.test()

}

//输出

zxf

test

age:1

4.java访问object单例

那么java如何访问上述的单例类呢?

示例如下

Singleton.INSTANCE.getAge();

Singleton.INSTANCE.getName();

Singleton.INSTANCE.setName(“zxf”);

Singleton.INSTANCE.test();

上述是不是太麻烦了,有没有简单的方式呢?当然有,使用JvmField或者JvmStatic注解即可

示例如下

object Singleton {

//JvmField 对于java来说不生成getter/setter方法 访问等同于java Field

@JvmField

var age: Int = 0

var name: String = “”

//JvmField object的成员直接按照java静态成员生成字节码,对kotlin内部毫无影响,对于java可直接视为调用静态成员一般

@JvmStatic

fun test() {

println(“test”)

}

}

//java调用

Singleton.age = 10;

Singleton.test();

Singleton.INSTANCE.getName();

4.kotlin中对应java的静态成员

companion伴生对象,一般是 companion object 类似于 java静态变量方法的使用

示例如下

//java

public class Foo{

public static int age;

public static void y(){}

}

//kotlin 对应写法

class Foo{

companion object {

@JvmField

var age: Int = 0

@JvmStatic

fun y(){}

}

}

五、Kotlin内部类

==============================================================================

1.Java与Kotlin实现内部类方式比较

模式:默认是静态内部类,加上inner 是非静态内部类

示例如下:

//java

public class Outer{

//非静态内部类,实例持有外部类实例引用

class Inner{}

//静态内部类

static class StaticInner{}

}

//kotlin

class Outer{

//非静态内部类,实例持有外部类实例引用

inner class Inner

//静态内部类

class StaticInner

}

2.Kotlin内名内部类

示例如下:

val runnable = object : Runnable {

override fun run() {

TODO(“Not yet implemented”)

}

}

kotlin匿名内部类:可以继承类或者实现多个接口

val value = object : Runnable, RemoteJVMLauncher.CallBack {

override fun run() {

TODO(“Not yet implemented”)

}

override fun jvmStarted() {

TODO(“Not yet implemented”)

}

}

六、Kotlin数据类data

==================================================================================

1.Java与Kotlin实现内部类方式比较

数据类,不能够被继承,没有无参构造方法。可以进行解构操作、重新了equals、hashcode、toString、提供getter、setter、copy等函数

简单示例如下:

//java

public class Book{

private long id;

private String name;

private String person;

//省略getter/setter方法

}

//kotlin

data class Book(

var id:Long,

var name:String,

var person:String

)

//kotlin 解构的简单使用

val (id, name, person) = Book(1L, “zxf”, “person”)

println(“id:

i

d

,

n

a

m

e

:

id,name:

id,name:name,person:$person”)

//输出

id:1,name:zxf,person:person

2.data class 注意点

我们可以查看data class反编译之后的代码

public final class Book {

private final long id;

@NotNull

private final String name;

@NotNull

private final String person;

public final long getId() {

return this.id;

}

public final void setId(long var1) {

this.id = var1;

}

//其他getset省略

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

Intrinsics.checkNotNullParameter(name, “name”);

Intrinsics.checkNotNullParameter(person, “person”);

super();

this.id = id;

this.name = name;

this.person = person;

}

public final long component1() {

return this.id;

}

@NotNull

public final String component2() {

return this.name;

}

@NotNull

public final String component3() {

return this.person;

}

@NotNull

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

Intrinsics.checkNotNullParameter(name, “name”);

Intrinsics.checkNotNullParameter(person, “person”);

return new Book(id, name, person);

}

// $FF: synthetic method

public static Book copy$default(Book var0, long var1, String var3, String 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.person;

}

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

}

@NotNull

public String toString() {

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

}

public int hashCode() {

//todo 省略

}

public boolean equals(@Nullable Object var1) {

//todo 省略

}

}

除了常规的方法外,还提供了几个component,上面我们使用的解构的功能,就是通过component实现的。

基于component提供相等性,解构等功能 数据类属性类型最好为基本类型、string、或者其他dataclass Component不可以自定义getter、setter 定义成员最好定义为val,防止修改后equals和hashcode的相等性判断错误

七、枚举类EnumClass

=================================================================================

1.Java与Kotlin实现枚举类比较

java与kotlin实现枚举对比

简单示例如下:

//java

enum State{

InComplete,Complete

}

//使用

State.InComplete.name()//InComplete

State.InComplete.ordinal()//0

//kotlin

enum State{

InComplete,Complete

}

//使用

State.InComplete.name//InComplete

State.InComplete.ordinal//0

定义构造器示例如下:

//java

enum State{

InComplete(0),Complete(1);

int id;

State(int id){

this.id = id;

}

}

//kotlin

enum class State(val id: Int){

InComplete(0),Complete(1)

}

2.Kotlin枚举的简单使用

// 定义枚举类

enum class Color {

WHITE, BLACK, RED;

}

// 为枚举定义扩展方法

fun Color.nextColor(): Color {

// values()以集合的形式返回出所有的枚举

return Color.values().let {

// ordinal 当前的序号

val nextOrdinal = (this.ordinal + 1) % it.size

it[nextOrdinal]

}

}

fun main() {

// 获取枚举的位置和名字

val ordinal = Color.BLACK.ordinal

val name = Color.BLACK.name

println(“enum:name:

n

a

m

e

,

i

n

d

e

x

:

name,index:

name,index:ordinal”)

// 枚举比较大小 按照序号比较

println(Color.BLACK > Color.RED)

// 使用扩展方法获取下一个

println(“whitenextcolor:${Color.WHITE.nextColor().name}”)

// 枚举的区间

val closedRange = Color.WHITE…Color.RED

}

八、密封类sealed class

====================================================================================

1.密封类概念

密封类是一种特殊的抽象类 密封类的子类定义在与自身相同的文件中 密封类的子类个数是有限的

密封类构造器是私有的,子类只能写在同一个文件夹里面

密封类构VS枚举类

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

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

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

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)

最后是今天给大家分享的一些独家干货:

【Android开发核心知识点笔记】

【Android思维脑图(技能树)】

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【Android高级架构视频学习资源】

// 枚举比较大小 按照序号比较

println(Color.BLACK > Color.RED)

// 使用扩展方法获取下一个

println(“whitenextcolor:${Color.WHITE.nextColor().name}”)

// 枚举的区间

val closedRange = Color.WHITE…Color.RED

}

八、密封类sealed class

====================================================================================

1.密封类概念

密封类是一种特殊的抽象类 密封类的子类定义在与自身相同的文件中 密封类的子类个数是有限的

密封类构造器是私有的,子类只能写在同一个文件夹里面

密封类构VS枚举类

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

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

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。 [外链图片转存中…(img-GLStOCMw-1711965291777)] [外链图片转存中…(img-SBGNMz4c-1711965291778)] [外链图片转存中…(img-UnCufyG7-1711965291778)] [外链图片转存中…(img-QCvSZJuD-1711965291779)] [外链图片转存中…(img-JX7USwXr-1711965291779)] [外链图片转存中…(img-ZOpgfYF9-1711965291779)]

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

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

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android) [外链图片转存中…(img-TsLP5lak-1711965291780)]

最后是今天给大家分享的一些独家干货:

【Android开发核心知识点笔记】

[外链图片转存中…(img-2ineRyVj-1711965291780)]

【Android思维脑图(技能树)】

[外链图片转存中…(img-1Sec6n3B-1711965291780)]

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-BDMCmV24-1711965291780)]

【Android高级架构视频学习资源】

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

推荐链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: