kotlin扩展函数
Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 装饰者模式。
定义形式:
fun 数据类型.函数名称(参数1, 参数2...){//参数可为空
函数体
}
//实例:
class Animal
class KotlinDemo2{
companion object {
@JvmStatic
fun main(args: Array<String>) {
test()
}
private fun test(){
val animal = Animal()
animal.speak("你是动物")
}
}
}
fun Animal.speak(str:String){
println(str)
}
//为 MutableList 添加一个swap 扩展函数:
fun MutableList<String>.swap(a: Int, b: Int) {
val tmp = this[a] // this 对应MutableList列表
this[a] = this[b]
this[b] = tmp
}
val list = mutableListOf<String>("a", "b", "c", "d")
list.swap(1, 3)
println(list)
扩展函数中的this指向, 谁调用, 指向谁
扩展函数是静态解析的,并不是接收者类型的虚拟成员, 在调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,而不是动态的类型决定的:
open class Demo
class SubDemo : Demo()
fun Demo.test(){
println("Demo")
}
fun SubDemo.test(){
println("SubDemo")
}
//在主函数中执行
val demo = Demo()
val subDemo = SubDemo()
demo.test()
subDemo.test()
//输出结果
Demo
SubDemo
若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。
open class Demo{
fun test(){
println("我是成员函数")
}
}
fun Demo.test(){
println("我是扩展函数")
}
//在主函数中执行
val demo = Demo()
demo.test()
//输出结果
我是成员函数
扩展空对象:在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数
fun Any?.toString(): String {
if (this == null) return "null"
// 空检测之后,“this”会自动转换为非空类型
return toString()
}
fun main(arg:Array<String>){
var str = null
println(str.toString())
}
//输出结果 null
扩展属性: 扩展属性只能被声明为 val。
val <T> Array<T>.length: Int
get() = size
fun main(args:Array<String>){
val arr = arrayOf(1, 2, 3, 4)
println(arr.length)
}
扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。初始化属性因为属性没有后端字段(backing field),所以不允许被初始化,只能由显式提供的 getter/setter 定义。
/* val Demo.name = "wwf" // 错误:扩展属性不能有初始化器
伴生对象扩展 */
class Base{
//伴生对象, 类似于java中的静态成员(静态属性,静态方法 )
companion object {
var token: String = "2t5856698" //类似于普通静态属性
const val ITEM_ONE:Int = 1 //常量
fun test(){//类似于静态方法
}
}
}
fun Base.Companion.demo() {
println("伴随对象的扩展函数")
}
//伴生扩展属性
val Base.Companion.number:Int
get(){
return 10
}
//伴生扩展属性
val Base.Companion.number2:Int
get() = 12
fun main(args: Array<String>) {
Base.Companion.demo()
println(Base.Companion.number)
}
扩展的作用域
//扩展函数或属性定义在顶级包下:
package com.wwf.demo
class Base
fun Base.test() {
println("Base test")
}
//要使用所定义包之外的一个扩展, 通过import导入扩展的函数名进行使用:
package com.wwf.demo2
import com.wwf.demo.Base
import com.wwf.demo.test
fun main(args: Array<String>) {
test12(Base())
}
fun test12(base: Base) {
base.test()
}
数据类与密封类
数据类 关键字: data
data class User(var name:String, var age:Int)
编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:
equals() / hashCode()
toString() 格式如 "User(name=John, age=42)"
componentN() functions 对应于属性,按声明顺序排列
copy() 函数
数据类需要满足以下条件:
主构造函数至少包含一个参数。
所有的主构造函数的参数必须标识为val 或者 var ;
数据类不可以声明为 abstract, open, sealed 或者 inner;
数据类不能继承其他类 (但是可以实现接口)。
数据类以及解构声明
val maggie = User("maggie", 35)
val (name, age) = maggie
println("$name, $age")
// prints "maggie, 35"
密封类 :sealed
密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。
sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
sealed class ItemType
data class ItemOne(val number: Double) : ItemType()
data class ItemTwo(val e1: ItemType, val e2: ItemType) : ItemType()
object NotANumber : ItemType()
fun eval(itemType: ItemType): Double = when (ItemType) {
is ItemOne-> itemType.number
is ItemTwo-> eval(itemType.e1) + eval(itemType.e2)
NotANumber -> Double.NaN
}
使用密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了
fun eval(itemType: ItemType): Double = when(itemType) {
is Expr.ItemOne-> itemType.number
is Expr.ItemTwo -> eval(itemType.e1) + eval(itemType.e2)
Expr.NotANumber -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
kotlin泛型
声明一个泛型类:
//kotlin网络请求, 数据类型基类
class BaseBean<T>{
var code:Int = 0
var message:String =""
var data:T? = null
var dataList:MutableList<T>? = null
}
创建数据类型时, 必须添加泛型, 否则报错
val baseBean = BaseBean<LoginBean>() //这个和Java不同, 必须添加
在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:
fun main(args: Array<String>) {
val age = 23
val name = "runoob"
val bool = true
doPrintln(age) // 整型
doPrintln(name) // 字符串
doPrintln(bool) // 布尔型
}
fun <T> doPrintln(content: T) {
when (content) {
is Int -> println("整型数字为 $content")
is String -> println("字符串转换为大写:${content.toUpperCase()}")
else -> println("T 不是整型,也不是字符串")
}
}
泛型约束 java中的extend, 和super都没有了, kotin中使用 :随便举的例子, 只是用来入门
class BaseBean<T : BaseType> {
var data: T? = null
}
open class BaseType {
}
class UserBean : BaseType() {
}
fun main(args: Array<String>) {
val baseBean = BaseBean<UserBean>()
val userBean : UserBean? = baseBean.data
}
默认上界为Any
型变:分为两种, 协变和逆变 即 in out两种, 类似于java中的 <?
super T> 和 <? extends T>, 理解为生产者和消费者
out 用作出参, 如返回值, in 入参, 用作传入的参数
星投影: * Kotlin中能省略泛型如集合泛型, 使用*代表不加泛型
List list = new ArrayList(); //java中
val list : ArrayList<*> = arrayListOf(1) // kotlin中, 必须初始化至少一个值, 不然报错
//1、 Kotlin的泛型使用基本和Java一致
//2、 Java的<? extends T> 相当于 Kotlin的<out T> ,Java的<? super T> 相当于 Kotlin的<in T>
//3、<out T> 只能生产(出参), <in T> 只能消费(入参)
//4、<out T> 只能生产的原因是编译器无法确认什么对象符合那个未知的 T 的子类型,只知道一定返回T,<in T> 只能消费的原因是无法确认T超类的具体类型
//5、<*>相当于java中的无泛型。对于 Foo <out T>,其中 T 是一个具有上界的协变类型参数,Foo <*> 等价于 Foo <out Any>;对于 Foo <in T>,其中 T 是一个逆变类型参数,Foo <*> 等价于 Foo <in Nothing>
kotlin枚举类 了解
//和java类似
enum class Color{
RED,BLACK,BLUE,GREEN,WHITE
}
//枚举初始化
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
enum class Shape(value:Int){
ovel(100),
rectangle(200)
}
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
};
abstract fun signal(): ProtocolState
}
//获取枚举相关信息:
val name: String //获取枚举名称
val ordinal: Int //获取枚举值在所有枚举数组中定义的顺序
fun main(args: Array<String>) {
var color:Color=Color.BLUE
println(Color.values())
println(Color.valueOf("RED"))
println(color.name)
println(color.ordinal)
}