kotlin部分常用特性总结

<h3>Kotlin中类和对象初始化</h3>

<ul>

<li>添加open关键字代表可以被继承</li>

<li>Any 是所有类的父类,类似Object,包含 equals() hashCode() toString()方法</li>

<li>constructor 关键字代表构造函数, constructor关键字可以去掉</li>

</ul>

<pre><code class="java">class User(性格: String, 长相: String, 声音: String) : Human(性格, 长相, 声音)

class User2(name: String) : Human2(name)

open class Human constructor(var 性格: String, var 长相: String, var 声音: String) : Any() {

//对象创建时调用,构造方法的方法体

init {

println("new 了一个{this.javaClass.simpleName}, ta性格:性格, 长相:长相, 声音:声音")

}

override fun toString(): String {

return "${性格} 性格"

}

}

open class Human2 {

val name: String

val age: Int

constructor(name: String) : this(name, 0) {

// 调用主构造函数或另一个辅助构造函数

}

constructor(name: String, age: Int = 18) { // 辅助构造函数

this.name = name

this.age = age

val user: User = User("温柔", "甜美", "动人")

val value: String? = getName()

println(value!!.length)

}

}

</code></pre>

<h3>空类型和智能类型转换</h3>

<ul>

<li>?.在遇到null时会静默跳过执行(返回null)</li>

<li>!!在遇到null时会立即抛出异常 (当对可空变量使用!!时,编译器会假定该变量不为null)</li>

</ul>

<pre><code>fun getName(): String? {// ? 表示返回值可以为空

return "na"//null

}

fun main(args: Array&lt;String&gt;) {

val str: String? = null

// ?.在遇到null时会静默跳过执行(返回null)

// !!在遇到null时会立即抛出异常 (当对可空变量使用!!时,编译器会假定该变量不为null)

//val length = str!!.length

// 应尽量避免使用!!,推荐替代方案包括:

// 优先使用val声明不可变变量

// 对延迟初始化变量使用 lateinit. var用lateinit 延迟初始化,val用lazy

lateinit var q: String

// 使用Elvis操作符?:提供默认值或者return

//Elvis操作符?: 结构:表达式A ?: 表达式B

//当表达式A非null时返回A的值,否则返回表达式B的结果

// 例如:

val length2 = str?.length ?: 0

val name: String = getName() ?: return

println(name.length)

main2(args)

}

</code></pre>

<h3>区间 Range,表示范围</h3>

<pre><code>//val:用于运行时常量,相当于Java的final字段,支持任何类型且仅初始化一次

//const:用于编译时常量,相当于Java的public static final字段,可通过类名直接访问。

//编译时确定值:const修饰的常量值必须在编译时确定,不能通过运行时计算或动态赋值。

//类型限制:仅支持基本类型(如int、double、string)和字符串。

//存储位置:必须声明在顶层(如包级可见变量)或伴生对象(companion object)中

val range: IntRange = 0..1024 // [0, 1024]

val range_exclusive: IntRange = 0 until 1024 // [0, 1024) = [0, 1023]

val a = (50 in range) // (i in range)判断i是否在区间中

</code></pre>

<h3>Unit</h3>

在 Kotlin 中,Unit 是一个特殊的类型,类似于 Java 中的 void,但有以下关键区别:

<ul>

<li>Unit 是一个实际存在的类型(单例对象),而 void 只是关键字</li>

<li>当函数不返回有意义的值时,Kotlin 会隐式返回 Unit</li>

<li>Unit 的实例可以用 Unit 或 () 表示</li>

</ul>

<pre><code>fun printMessage(msg: String): Unit { // 这里的 : Unit 可以省略

println(msg)

// 隐式返回 Unit

}

fun printUsage() {

println("请传入两个整型参数,例如 1 2") // (Any?) -&gt; Unit

} // ()-&gt;Unit

val sum = { arg1: Int, arg2: Int -&gt;

println("arg1 + arg2 = ${arg1 + arg2}")

arg1 + arg2

}

// (Int, Int) -&gt; Int

val printlnHello = {

println(::printUsage is ()-&gt; Unit)

println("Hello")

}

// ()-&gt; Unit

val int2Long = fun(x: Int): Long {

return x.toLong()

}

</code></pre>

<h3>继承与实现</h3>

<ul>

<li>父类需要 open 才可以被继承</li>

<li>父类方法、属性需要 open 才可以被覆写</li>

<li>接口、接口方法、抽象类默认为 open</li>

<li>覆写父类(接口)成员需要 override 关键字</li>

<li>class D: A(),B,C</li>

<li>注意继承类时实际上调用了父类构造方法</li>

<li>类只能单继承,接口可以多实现</li>

</ul>

<h3>继承之接口代理(基于 by 关键字)</h3>

通过 by 将接口实现委托给其他对象,无需手动编写代理类

<pre><code>class SeniorManager(val driver: Driver, val writer: Writer): Driver by driver, Writer by writer

class CarDriver: Driver {

override fun drive() {

println("开车呢")

}

}

class PPTWriter: Writer {

override fun write() {

println("做PPT呢")

}

}

interface Driver{

fun drive()

}

interface Writer{

fun write()

}

fun main3(args: Array&lt;String&gt;) {

val driver = CarDriver()

val writer = PPTWriter()

val seniorManager = SeniorManager(driver, writer)

seniorManager.drive()

seniorManager.write()

}

</code></pre>

<h3>接口方法冲突</h3>

<ul>

<li>接口方法可以有默认实现</li>

<li>签名一致且返回值相同的冲突</li>

<li>子类(实现类)必须覆写冲突方法</li>

<li>super&lt;[父类(接口)名]>.<a href="[参数列表]">方法名</a></li>

</ul>

<pre><code>abstract class A{

open fun x(): Int = 5

}

interface B{

fun x(): Int = 1

}

interface C{

fun x(): Int = 0

}

class D(var y: Int = 0): A(), B, C{

override fun x(): Int {

println("call x(): Int in D")

if(y &gt; 0){

return y

}else if(y &lt; -200){

return super&lt;C&gt;.x()

}else if(y &lt; -100){

return super&lt;B&gt;.x()

}else{

return super&lt;A&gt;.x()

}

}

}

//3 5 1 0

fun main(args: Array&lt;String&gt;) {

println(D(3).x())

println(D(-10).x())

println(D(-110).x())

println(D(-10000).x())

}

</code></pre>

<h3>可见性对比</h3>

模块通常指一组共同编译的 Kotlin 文件(如 Gradle 模块或 IntelliJ 模块)

<table>

<thead>

<tr>

<th align="center">kotlin</th>

<th align="center">java</th>

</tr>

</thead>

<tbody>

<tr>

<td align="center">private</td>

<td align="center">private</td>

</tr>

<tr>

<td align="center">protected</td>

<td align="center">protected</td>

</tr>

<tr>

<td align="center">-</td>

<td align="center">default(包内可见)</td>

</tr>

<tr>

<td align="center">internal(模块内可见,模块化开发的核心修饰符)</td>

<td align="center">-</td>

</tr>

<tr>

<td align="center">public</td>

<td align="center">public</td>

</tr>

</tbody>

</table>

<h3>Object 关键字</h3>

object 关键字用于实现‌单例模式‌、‌伴生对象‌和‌对象表达式‌(匿名对象),是 Kotlin 特有的简化设计模式的语法糖。以下是其三大核心用途及示例:

  1. 单例模式(对象声明)‌

直接通过 object 声明线程安全的单例:

<pre><code>object DatabaseManager {

private val connection = "DB_Connection"

fun query(sql: String) = println("Executing: sql via connection")

}

// 使用(全局唯一实例)

fun main() {

DatabaseManager.query("SELECT * FROM users") // 输出: Executing: SELECT * FROM users via DB_Connection

}

</code></pre>

特点:

* 只有一个实例的类

* 首次访问时延迟初始化(线程安全)

* 不能自定义构造函数, 可继承父类 可实现接口

<ol>

<li>伴生对象

<ul>

<li>每个类可以对应一个伴生对象</li>

<li>伴生对象的成员全局独一份 , 相当于静态方法 静态属性</li>

</ul></li>

</ol>

<pre><code>class Latitude private constructor(val value: Double){

companion object{

@JvmStatic

fun ofDouble(double: Double): Latitude{

return Latitude(double)

}

fun ofLatitude(latitude: Latitude): Latitude{

return Latitude(latitude.value)

}

@JvmField

val TAG: String = "Latitude"

}

}

</code></pre>

<ol>

<li>匿名对象

<ul>

<li>每次调用都会创建新对象</li>

<li>可同时继承类和实现接口(如 object : ClassA(), InterfaceB</li>

<li>注意:object 与 class 不同,不能实例化(本身就是实例)</li>

</ul></li>

</ol>

<pre><code> interface ClickListener {

fun onClick()

}

fun setClickListener(listener: ClickListener) {

listener.onClick()

}

fun main() {

var counter = 0

setClickListener(object : ClickListener {

override fun onClick() {

println("Clicked ${++counter} times") // 捕获并修改外部变量

}

})

}

</code></pre>

<h3>扩展成员</h3>

<ul>

<li>为现有类添加方法、属性</li>

<li>fun X.y(): Z {... }</li>

<li>val x.m 注意扩展属性不能初始化,类似接口属性</li>

<li>Java 调用扩展成员类似调用静态方法</li>

</ul>

<pre><code> operator fun String.times(int: Int): String{

val stringBuilder = StringBuilder()

for(i in 0 until int){

stringBuilder.append(this)

}

return stringBuilder.toString()

}

val String.a: String

get() = "abc"

var String.b: Int

set(value) {

}

get() = 5

//abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc

//5

fun main(args: Array&lt;String&gt;) {

println("abc" * 16)

"abc".b = 5

println("abc".b)

}

</code></pre>

<h3>operator关键字</h3>

operator 关键字用于‌重载运算符‌或‌约定特定函数‌,让类实例支持类似基础类型的操作(如 +、[]、in 等)

<h4>运算符重载‌</h4>

通过重载预定义的运算符函数,使对象支持算术、比较等操作

<pre><code>data class Point(val x: Int, val y: Int) {

// 重载 "+" 运算符

operator fun plus(other: Point): Point {

return Point(x + other.x, y + other.y)

}

}

fun main() {

val p1 = Point(1, 2)

val p2 = Point(3, 4)

println(p1 + p2) // 输出: Point(x=4, y=6)

}

</code></pre>

<table>

<thead>

<tr>

<th>运算符</th>

<th>对应函数名</th>

<th>示例表达式</th>

</tr>

</thead>

<tbody>

<tr>

<td>+</td>

<td>plus</td>

<td>a + b</td>

</tr>

<tr>

<td>-</td>

<td>minus</td>

<td>a - b</td>

</tr>

<tr>

<td>[]</td>

<td>get</td>

<td>a[i]</td>

</tr>

<tr>

<td>in</td>

<td>contains</td>

<td>a in b</td>

</tr>

<tr>

<td>==</td>

<td>equals</td>

<td>a==b</td>

</tr>

</tbody>

</table>

<h4>约定函数</h4>

operator 还可用于标记‌特定名称的函数‌,实现与语言特性的交互:

<ul>

<li>解构声明(Destructuring)</li>

</ul>

<pre><code>class User(val name: String, val age: Int) {

operator fun component1() = name // 解构为 (name, age)

operator fun component2() = age

}

fun main() {

val user = User("Alice", 25)

val (name, age) = user // 解构赋值

println("name, age") // 输出: Alice, 25

}

</code></pre>

<ul>

<li>迭代器支持</li>

</ul>

<pre><code>class Counter(val range: IntRange) {

operator fun iterator(): Iterator&lt;Int&gt; = range.iterator()

}

fun main() {

for (i in Counter(1..5)) { // 支持 for-in 循环

print("$i ") // 输出: 1 2 3 4 5

}

}

</code></pre>

<h4>注意事项‌</h4>

<ul>

<li>不可随意创造运算符‌:只能重载 Kotlin 预定义的运算符47。</li>

<li>一致性要求‌:如 plus 不应修改原对象,应返回新实例35。</li>

<li>与扩展函数结合‌:可为现有类添加运算符支持</li>

</ul>

<pre><code>operator fun Int.times(str: String) = str.repeat(this)

fun main() {

println(3 * "Hi ") // 输出: Hi Hi Hi

}

</code></pre>

<h3>属性代理</h3>

<h4>懒加载 lazy</h4>

<ul>

<li>延迟到首次访问时执行</li>

<li>线程安全模式‌:默认 LazyThreadSafetyMode.SYNCHRONIZED,可选 PUBLICATION(允许多线程初始化)或 NONE(单线程)</li>

</ul>

<pre><code>class Delegates{

val hello by lazy {

"HelloWorld"

}

val hello0 by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {

"HelloWorld"

}

val hello2 by X()

var hello3 by X()

}

</code></pre>

<h4>基本用法</h4>

<pre><code>// val 属性‌:只需实现 getValue

‌// var 属性‌:需同时实现 getValue 和 setValue

class X{

private var value: String? = null

operator fun getValue(thisRef: Any?, property: KProperty&lt;*&gt;): String {

println("getValue: thisRef -\> {property.name}")

return value?: ""

}

operator fun setValue(thisRef: Any?, property: KProperty&lt;*&gt;, value: String){

println("setValue, thisRef -\> {property.name} = $value")

this.value = value

}

}

fun main6(args: Array&lt;String&gt;) {

val delegates = Delegates()

println(delegates.hello)

println(delegates.hello2)

println(delegates.hello3)

delegates.hello3 = "value of hello3"

println(delegates.hello3)

println(delegates.hello)

}

//HelloWorld

//getValue: com.spro.globalsearch.Delegates@1593948d -&gt; hello2

//

//getValue: com.spro.globalsearch.Delegates@1593948d -&gt; hello3

//

//setValue, com.spro.globalsearch.Delegates@1593948d -&gt; hello3 = value of hello3

//getValue: com.spro.globalsearch.Delegates@1593948d -&gt; hello3

//value of hello3

//HelloWorld

</code></pre>

<h3>数据类DataClass</h3>

<ul>

<li>自动生成标准方法:

数据类会自动生成 equals()、hashCode()、toString()、copy() 等方法,普通类需手动实现</li>

<li>主构造函数要求:

必须至少有一个参数,且参数需标记为 val 或 va, 普通类无此限制</li>

<li>解构声明支持

数据类自动支持解构,可直接将属性拆分为变,普通类则需手动实现 componentN()</li>

<li>不可变性推荐‌:

属性通常声明为 val(不可变),但支持 var(可变)‌</li>

<li>继承限制‌

数据类不能是 abstract、open、sealed 或 inner 类‌</li>

<li>无无参构造函数

需显式定义默认值或辅助构造函数‌</li>

</ul>

<h4>应用</h4>

<ul>

<li>数据传输对象

如 JSON 解析后的数据实体‌</li>

<li>简化数据操作

利用 copy() 实现不可变对象的修改‌

val user2 = user1.copy(age = 26)</li>

</ul>

<pre><code>data class Country(val id: Int, val name: String)

data class Country2(var id: Int, var name: String)

//component 组件

class ComponentX{

operator fun component1(): String{

return "您好,我是"

}

operator fun component2(): Int{

return 1

}

operator fun component3(): Int{

return 1

}

operator fun component4(): Int{

return 0

}

}

fun main7(args: Array&lt;String&gt;) {

//componentN解构声明

val china = Country(0, "中国")

println(china)// Country(id=0, name=中国)

println("{china.component1()} ------ {china.component2()} ")//0 ------ 中国

val (idx, name) = china //解构赋值

println("idx ------ name")//0 ----- 中国

val componentX = ComponentX()//解构赋值

val (a, b, c, d) = componentX

println("a bcd")//您好,我是 110

}

</code></pre>

<h3>内部类</h3>

静态内部类与非静态内部类的区别:到底是否持有外部类的状态 (非静态内部类持有外部类的状态,可以访问外部类的属性)

<pre><code>open class Outter{

val a: Int = 0

class InnerDefaultStatic{

}

//非静态内部类

inner class Inner{

val a: Int = 5

fun hello(){

println(this@Outter.a)

}

}

}

interface OnClickListener{

fun onClick()

}

class View{

var onClickListener: OnClickListener? = null

}

fun main(args: Array&lt;String&gt;) {

val innerDefaultStatic = Outter.InnerDefaultStatic()

val inner = Outter().Inner()

val view = View()

//匿名内部类看上去没有名字,但是编译生成字节码文件有自己的ID,类似Outter$1.class

view.onClickListener = object : Outter(), OnClickListener{

override fun onClick() {

}

}

}

</code></pre>

<h3>枚举类</h3>

<ul>

<li>实例可数的类,注意枚举也是类</li>

<li>可以修改构造,添加成员</li>

<li>可以提升代码的表现力,也有一定的性能开销</li>

<li>实例可数‌指枚举(enum)类型的成员数量固定且不可扩展。</li>

<li>枚举通过enum class声明,其所有成员(如VERBOSE、DEBUG等)均为该类的实例对象,且默认构造函数为私有(private constructor()),因此无法被继承或扩展</li>

</ul>

<pre><code>enum class LogLevel(val id: Int){

VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);

fun getTag(): String{

return "id, name"

}

override fun toString(): String {

return "name, ordinal"

}

}

println(LogLevel.DEBUG.ordinal)

LogLevel.values().map(::println)

println(LogLevel.valueOf("ERROR"))

//VERBOSE, 0

//DEBUG, 1

//INFO, 2

//WARN, 3

//ERROR, 4

//ASSERT, 5

//ERROR, 4

</code></pre>

<h3>密封类</h3>

子类可数

<pre><code>sealed class PlayerCmd{

}

class Play(val url:String,val position:Long =0):PlayerCmd()

class Seek(val position: Long): PlayerCmd()

object Pause:PlayerCmd()

object Resume:PlayerCmd()

object Stop:PlayerCmd()

enum class PlayerState{

IDLE, PAUSE, PLAYING

}

</code></pre>