IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Kotlin特性之 - 扩展函数/指向函数的引用/扩展属性 -> 正文阅读

[移动开发]Kotlin特性之 - 扩展函数/指向函数的引用/扩展属性

1. 扩展属性

kotlin允许动态为类扩展属性,扩展属性是通过添加get、set方法实现,没有幕后字段(filed)。
扩展属性也没有真的为该类添加了属性,只能说是为该类通过get、set方法计算出属性。
限制:①扩展属性不能有初始值;
②扩展属性不能用filed关键字访问幕后字段;
③val必须提供get方法,var必须提供get和set方法。

var类型

	class ExtensionTest(var param1: String, var param2: String)
	
	var ExtensionTest.extensionParam: String
	    set(value) {
	        param1 = "param1$value"
	        param1 = "param2$value"
	    }
	    get() = "$param1-$param2"
	    
	fun main(args: Array<String>) {
	    val extensionTest = ExtensionTest("a", "b")
	    println(extensionTest.param1)//a
	    println(extensionTest.param2)//b
	    println(extensionTest.extensionParam)//a-b
	}

val类型

	val Float.dp
	  get() = TypedValue.applyDimension(
	    TypedValue.COMPLEX_UNIT_DIP,
	    this,
	    Resources.getSystem().displayMetrics
	  )
	...
	val RADIUS = 200f.dp

2. 扩展函数的写法

// fun 关键字 + 要扩展的类名 + 点号 + 方法名 + 方法属性
fun String.method1(i: Int) {
  ...
}
这里要扩展函数的类名叫做Receiver(接受者),也就是谁可以去调用它.

在声明一个函数的时候在函数名的左边写个类名再加个点,你就能对这个类的对象调用这个函数了。这种函数就叫扩展函数,Extension Functions。就好像你钻到这个类的源码里,改了它的代码,给它增加了一个新的函数一样。虽然事实上不是,但用起来基本一样。

注意:

  1. 如果被扩展的类的扩展方法与该类的成员方法名字和参数一样,该类对象调用该方法时,调用的会是成员方法。
  2. 由于静态调用扩展方法是在编译时执行,因此,如果父类和子类都扩展了同名的一个扩展方法,引用类型均为父类的情况下,会调用父类的扩展方法。

3 Top Level扩展函数

package com.zhf

fun String.method1(i: Int) {
  ...
}

// 在使用的地方调用就可以了
"rengwuxian".method1(1)
Top Level扩展函数是属于谁呢?

它既是Top Level函数,又是前缀类的扩展函数, 它的作用域是package包内部, 他的Receiver是点左侧的类

看了很多教程和解释, 自己理解其实这个函数就是个顶层函数,它只属于它所在的 package, 不过他只能被Receiver(接收者)使用, 就是上面代码里的String,

虽然说它是个 Top-level Function,不属于任何类——确切地说是,不是任何一个类的成员函数——但我要限制只有通过某个类的对象才能调用你。这就是扩展函数的本质。

4 成员扩展函数

写在类里的扩展函数 , 你可以在这个类里调用这个函数,但必须使用那个前缀类的对象(Receiver)来调用它

class Example {
  fun String.method2(i: Int) {
    ...
  }
   "rengwuxian".method2(1) // 可以调用
}
成员扩展函数是属于谁呢? —

它既是外部类的成员函数,又是前缀类的扩展函数. 它的作用域是类内部, 他的Receiver是点左侧的类

这个「属于谁」其实有点模糊的,我需要问再明确点:
它是谁的成员函数?当然是外部的类的成员函数了,因为它写在它里面嘛,
那函数名左边的是什么?它是这个函数的 Receiver,对吧?也就是谁可以去调用它。
所以它既是外部类的成员函数,又是前缀类的扩展函数。

5 指向扩展函数的引用

函数是可以使用双冒号被指向的, 双冒号加方法名 指向的并不是函数本身,而是和函数等价的一个对象,
我们通常可以把这个「指向和函数等价的对象的引用」称作是「指向这个函数的引用」

顶层扩展函数的 指向扩展函数的引用

fun String.method1(i: Int) {
}
String::method1 

上面 String::method1 就是指向扩展函数的引用, 它其实是可以作为对象来传递和使用的,当然它也可以作为参数,传递给方法, 这就是高阶函数了
注意: 以下代码中 method3 和 method4 为什么都可以 传如String 的函数引用 下文会说到

	fun String.method1(i: Int): String {
	}
	class Example {
		val a = String::method1
		val b = a

        method3(String::method1)
        method3(b)
        
        method4(String::method1)
        method4(b)

		fun method3(method: String.(Int) -> String) {}
		fun method4(method: (String, Int) -> String) {}
	}
 

成员扩展函数的 指向扩展函数的引用 ( *** 不存在)

一个成员函数怎么引用:类名加双冒号加函数名对吧?扩展函数呢?也是类名加双冒号加函数名对吧?只不过这次是 Receiver 的类名。那成员扩展函数呢?还用类名加双冒号加函数名呗?但是……用谁的类名?是这个函数所属的类名,还是它的 Receiver 的类名?这是有歧义的,所以 Kotlin 就干脆不许我们引用既是成员函数又是扩展函数的函数了,一了百了。

	fun Extensions .method2(i: Int) {
		...
	}
	class Extensions {
	  fun String.method1(i: Int) {
	    ...
	  }
	  fun method2(i: Int) {
		...
	  }
	  String::method1 // 报错
	}
	
	class Example {
		Extensions ::method1 // 报错
		Extensions ::method2  // 方法名相同, 成员方法优先
	}

6 把扩展函数的引用赋值给变量

扩展函数的引用也可以赋值给变量, 然后你再拿着这个变量去调用,或者再次传递给别的变量,都是可以的
跟普通函数的引用一样,扩展函数的引用也可以被调用,直接调用或者用 invoke() 都可以,不过要记得把 Receiver 也就是接收者或者说调用者填成第一个参数

	
	val a: String.(Int) -> Unit = String::method1
	"zhf".a(1)
	a("zhf", 1)
	a.invoke("zhf", 1)

7 有无 Receiver 的变量的互换

在 Kotlin 里,每一个有 Receiver 的函数——其实就是成员函数和扩展函数——它的引用都可以赋值给两种不同的函数类型变量:一种是有 Receiver 的,一种是没有 Receiver 的:
有 Receiver 的函数和没有 Receiver 的函数,在写法上就是把 Receiver 放在没有Receiver 的第一个参数

	val a: String.(Int) -> Unit = String::method1
	val b: (String, Int) -> Unit = String::method1
	
	val c: String.(Int) -> Unit = b
	val d: (String, Int) -> Unit = a

扩展 (可直接跳过)

下面三段代码,第一段代码里的 clz / clz1/ clz2/ clz3 这四个对象是一个对象吗? 他们之间有何不同呢?

  1. LoginActivity::class 和 mLoginActivity::class 这两个是相同的对象,
    类名或者类的对象加双冒号,代表 指向扩展函数的引用 所以 clz1和clz2 是相同的对象
  2. LoginActivity::class 返回的是什么呢 ? 在kotlin中的Class与Java不同,
    kotlin中有一个自己的Class叫做KClass 双冒号加class 返回的就是 KClass
  3. mLoginActivity::class.java 和 mLoginActivity.javaClass 这两个是相同的对象 .
    第二段代码,是KClass 的一个扩展函数, 他的返回值是 Class 第三段代码,是T 的一个扩展函数, T就是某个函数名 他的返回值是 Class

结论就是: clz != clz1 == clz2 ==clz3

       代码一 
        val clz = LoginActivity::class
        val clz1 = LoginActivity::class.java
        val clz2 = mLoginActivity::class.java
        val clz3 = mLoginActivity.javaClass
  
        val intent = Intent();
        intent.setClass(mContext, clz1 )
        startActivity(intent)
代码二
	@Suppress("UPPER_BOUND_VIOLATED")
	public val <T> KClass<T>.java: Class<T>
	    @JvmName("getJavaClass")
	    get() = (this as ClassBasedDeclarationContainer).jClass as Class<T>
代码三
	public inline val <T : Any> T.javaClass: Class<T>
	    @Suppress("UsePropertyAccessSyntax")
	    get() = (this as java.lang.Object).getClass() as Class<T>

本文摘录自:
https://rengwuxian.com/kotlin-extensions/
https://www.cnblogs.com/nicolas2019/p/10932131.html

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:24:09  更:2021-09-29 10:25:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:54:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码