西安专业的网站设计费用,四川省住房与城乡建设厅网站管网,湖南网站推广优化,濮阳网站建设兼职Kotlin的泛型
与Java一样#xff0c;Kotlin也提供泛型。泛型#xff0c;即 参数化类型#xff0c;将类型参数化#xff0c;可以用在类#xff0c;接口#xff0c;方法上。可以为类型安全提供保证#xff0c;消除类型强转的烦恼。声明泛型类的格式如下…Kotlin的泛型
与Java一样Kotlin也提供泛型。泛型即 参数化类型将类型参数化可以用在类接口方法上。可以为类型安全提供保证消除类型强转的烦恼。声明泛型类的格式如下
class BoxT(t: T) {var value t
}
用泛型创建类的实例的时候需要指定类型参数
val box: BoxInt BoxInt(100)
// 或者
val box Box(100) // 声明泛型类时候编译器会进行类型推断100的类型是Int所以编译器知道我们说的是 BoxInt。
定义泛型类型变量可以完整地写明类型参数。如果定义泛型类的时候指定了泛型类型则编译器可以自动推断类型参数定义时就可以省略类型参数。
fun T boxIn(value: T) Box(value)val box4 boxInInt(1)
val box5 boxIn(1) // 编译器会自动进行类型推断
在调用泛型函数时如果可以推断参数类型就可以省略泛型参数。
例如如下示例泛型函数根据传入的不同类型做相应处理
fun T printType(content: T) {when (content) {is Int - println(整型参数为 $content)is String - println(字符串参数转换为大写${content.toUpperCase()})else - println(传入参数 T 既不是整型也不是字符串)}
}fun main(args: ArrayString) {val num 111val name Weyenval bool trueprintType(num) // 整型printType(name) // 字符串类型printType(bool) // 布尔型
}
对应的输出结果为 泛型约束 跟Java一样Kotlin也拥有泛型约束。在Java中使用extends关键字指明上界。在kotlin中使用对泛型的类型上限进行约束。最常见的约束是上界(upper bound)。
例如下面的代码中调用num()函数时传入的参数只能是Number及其子类如果是其他类型则会报错
fun T : Number sum(vararg param: T) param.sumByDouble { it.toDouble() }
fun main() {val va1 sum(1,10,0.6)val va2 sum(1,10,kotlin) // 这里会提示编译错误
}
默认的上界是Any?。(注意这里是Any?不是Any。Any 类似于 Java 中的 Object它是所有非空类型的超类型。但是 Any 不能保存 null 值如果需要 null 作为变量的一部分则需要使用 Any?。Any?是 Any 的超类型所以 Kotlin 默认的上界是 Any?)
如果有多个上界约束条件可以用 where 子句
open class ClassA
interface InterfaceB
class TypeClassT(var variable: ClassT) where T : ClassA, T : InterfaceB
型变 Kotlin 中没有像java一样的? extends T这样的通配符也没有父类向子类转换取而代之的是两个其他的东西声明处型变declaration-site variance与类型投影type projections。
声明处型变声明处的类型变异使用协变注解修饰符in、out (消费者 in, 生产者 out。也可以这样理解in就是只能作为传入参数的参数类型out, 就是只能作为返回类型参数的参数类型。
相对于Java的概念
out 协变类型向上转换像java中的子类向父类转换。
in 逆变类型向下转换父类向子类转换。
协变类型参数只能用作输出可以作为返回值类型但是无法作为入参的类型
// 支持协变的类
class KotlinChangeout A(val demo: A) {fun foo(): A {return demo}
}fun main(args: ArrayString) {var strCo: KotlinChangeString KotlinChange(a)var anyCo: KotlinChangeAny KotlinChangeAny(b)anyCo strCoprintln(anyCo.foo()) // 对应的控制台输出 a
}
逆变类型参数只能用作输入可以作为入参的类型但是无法作为返回值的类型
// 这个类支持逆变注意这里的in
class KotlinChangein A(num: A) {fun foo(num: A) {}
}fun main(args: ArrayString) {var strDCo KotlinChange(a)var anyDCo KotlinChangeAny(b)strDCo anyDCoprintln(strDCo.foo()) //这里就会报错了
}
星号投影(star-projection) 星号(型)投影(射)单词翻译过来的叫啥都有能明白意思就行
在Kotlin 的泛型封装里会出现 * 这称为星号投影语法用来表明不知道关于泛型实参的任何信息。
*星号投影表示“不知道关于泛型实参的任何信息”在修饰容器时因为不知道是哪个类型所以并不能向容器中写入任何东西写入的任何值都可能会违反调用代码的期望。读取值是可以的因为所有存储在列表中的值都是Any?的子类。*星型投影修饰的容器(比如MutableListMutableMap )只能读不能写。 相当于out Any?。
比如MutableList* 表示的是 MutableListout Any?
如果一个泛型类型中存在多个类型参数, 那么每个类型参数都可以单独的投影. 比如, 如果类型定义为interface Functionin T, out U , 那么可以出现以下几种星号投影:
1、Function*, String , 代表 Functionin Nothing, String ;
2、FunctionInt, * , 代表 FunctionInt, out Any? ;
3、Function, , 代表 Functionin Nothing, out Any? 。
如下示例
class KotlinBeanT(val t: T, val t2 : T, val t3 : T)
class FruitBean(var name : String)
fun main(args: ArrayString) {val a1: KotlinBean* KotlinBean(12, String, FruitBean(苹果)) //星号投影val a2: KotlinBeanAny? KotlinBean(12, String, FruitBean(苹果)) //和a1是一样的val apple a1.t3 //参数类型为Anyprintln(apple)val apple2 apple as FruitBean //强转成FruitBean类println(apple2.name)//使用数组val list:ArrayList* arrayListOf(String,1,3.14f,FruitBean(苹果))for (item in list){println(item)}
}
对应的输出为 这时我们可以换个角度理解关于星号投影其实就是*代指了所有类型相当于Any?。 End如有问题请留言讨论。