当前位置:网站首页>Sorting out Android kotlin generic knowledge points
Sorting out Android kotlin generic knowledge points
2022-06-21 17:30:00 【Lighthouse @kuaidao】
Preface
Learning knowledge requires setting goals in advance , Only by learning with problems can we have a definite aim . Whether it's java Generic or kotlin Language generics are all writing frameworks , Write general tool artifact . If you are not familiar with generic Syntax , There will be many strange problems in the development process . Of course, the advanced features of the language must not be understood .
Ben blog be based on 《kotlin actual combat 》 Chapter 9 comes from the understanding of generics
1. Declaration of generic functions and classes
kotlin Introducing new concepts : Materialization type parameter 、 Declare point variants 、 Use point deformation
Materialization type parameter : Type parameter modification of generic function refixed Embellishment Such as : , And set the generic function to inline Inline function , Then the specific types of generic arguments of generic parameters can be obtained at runtime .( Ordinary classes and functions don't work , Not inline The runtime type information of function arguments will be erased )
Declare point deformation : You can tell whether a generic type with type parameters is a subtype of another generic type , Their basic types are the same , The type parameters are different
// Local variants of the declaration
interface Compare< A>{
}
interface Compare< B>{
}
Use point deformation : Can reach and java wildcard ( ?) Same effect
interface Compare{
// Use point variant
fun <T> compare(o1:T,o2:T){
}
}
1.1 Generic Type Parameter ( Generic classes )
class A<T>{
}
class B :A<String>()
Above : Two classes A、B, class A Followed by... In angle brackets T, Called a class A Of Type parameter or type parameter , And category B Derived from class A, And for classes A The generic parameters of Materialization , class B Followed by the class A In angle brackets of String type , Become Type arguments , It can also be said as a class B Middle to class A The type parameter of the uses String Type is materialized . It can be analogous to the initial assignment of parameters .
Of course, a class can declare more than one type parameter , You can also state N individual , For example kotlin Of Functions.kt The statement 22 There are so many :
//Functions.kt class
/** A function that takes 22 arguments. */
public interface Function22<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : Function<R> {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
}
tips: java The language allows the use of generic types without type parameters ( Original ecological type ) Because java 1.5 To introduce generics , It needs to be compatible with the old version , and kotlin Native types are not supported , Type parameters must be defined , because kotlin Support generic types from the beginning .
//①
ArrayList list=new ArrayList();
//②
val list: ArrayList<*> = ArrayList<Any?>()
1、2 Represent the java Primitive types , Without type parameters ,②kotlin The equivalent of language must define type parameters
1.2 Generic functions and properties
fun <T> List<T>.slice(indices:IntRange):List<T>
class A<T>(val a: T) {
}
explain : Type parameter declaration , The receiver and return value use type parameters T. Generic types must be defined , If the system can deduce it, there is no need to specify the generic type manually . such as
val letter =('a' ..'z').toList()
// There are two ways to write it. One is that the generic argument type is not specified , One is to specify generic arguments , This is equivalent to ,
// Because the second system can pass through letters The values stored in the set are derived T The value of is Char.
println(letters.slice<Char>(0..2))
println(letters.slice(0..2))
1.3 Declare generic classes
kotlin By adding a pair of angle brackets after the class name , And put the type parameter in angle brackets to declare the generic class or
Generic interface
class A<T>{
}
interface List<T>{
operator fun get(index:Int):T
}
Inside the interface T It can be used as a common type , If your class inherits a generic class , Then you need to use generic arguments to materialize generic parameters . Type arguments can be concrete types or Another type parameter
class ArrayList<T> :List<T>{
override fun get(index:Int):T = ...
}
Notice the ArrayList Type parameter of T, and List Medium T Is not a T, Names can all be called T, Or not T. Call others abc,Ac Fine
class ArrayList<B> :List<T>{
override fun get(index:Int):T = ...
}
1.4 Type parameter constraint
Why do I need to be right Generic Type Parameter Make constraints , You can restrict the types of type arguments that are generic classes and generic functions , Limit List Only subtypes derived from a type or called itself... Can be added to the collection Upper bound constraint , Restricting the collection to only add certain types of superclasses is called Lower bound constraint , Here we can combine java Declaration of generics :<? super T> and <? extends T>
java How to write it :
<T extends Number> T sum(List<T> list)
<T super Number> T sum(List<T> list)
kotlin How to write extension functions :
fun<T:Number> List<T>.sum():T
In rare cases, you need to specify multiple constraints on a type parameter , It can be used if necessary where keyword ,
fun<T> ensureTrailingPeriod(seq:T):where T:CharSequence,T:Appendable{
}
In this case, the parameter types as type arguments must be implemented by colleagues CharSequence and Appendable Two interfaces .
1.5 Make the type parameter non empty
By default, generic types T The type is Any?, That is, generic types can be assigned with null and non null values . So how to restrict the type parameter to be non null , You only need to explicitly make a non empty constraint on the generic parameter to achieve .
// The default type is T:Any?
class Processor<T:Any>{
fun test(value:T){
value.hashCode()
}
}
2. Instantiate type parameters and type erasure
jvm Upper generics are generally implemented by type erasure , The type arguments of generic type instances are in The runtime is not reserved .
2.1 Type checking and conversion
kotlin The generics of are also erased at runtime , This means that a generic class instance does not carry information about the type arguments used to create it .
val list=listof(1,2,3)
val strList=listof("a","b","c")
At run time list、 and strList You don't know if they are declared as strings , Integer list or other object list . Because the runtime does not attach any type of argument information . The advantage of this is to save memory , Less type information is stored in memory .
So use is List It can't be . But it can. Asterisk projection To determine whether the type is a List List instead of Set list .<*> similar Java Medium <?> Indicates that you have an unknown type .
fun printSum(c:Collection<*>){
val intList=c as? List<Int>?:throw IllegalArgumentException("List is expected")
println(intList.sum())
}
fun main(args: Array<String>) {
printSum(listOf(1,2,3))
printSum(listOf("1","2","3"))
}
This function is used to count the elements of a set , Normal output for the first case 6, And the second case is right String List summation of types , You will be prompted with a type conversion exception
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number
How to avoid this abnormal situation ?
kotlin There are special syntax structures that allow you to use specific type arguments in the body of a function , But only inline A function can
2.2 Declare functions that implement type parameters
inline fun <reified T> isA(value:Any)=value is T
Above isA The function is declared as inline Function with generic arguments reified modification .(reified Materialize modifier ),reified Declared that type parameters will not be erased at run time .
public inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R> {
return filterIsInstanceTo(ArrayList<R>())
}
fun main(args: Array<String>) {
println(listOf(1,2,"abc").filterIsInstance<String>())
// printSum(listOf("1","2","3"))
}
System level materialization api, Traverse the elements in the list , Determine whether the element is an object of the specified type .
Why is materialization only valid for inline functions ?
Because the bytecode code of the inline function will be compiled into the calling function , Every time you call a function that implements a type parameter , The compiler knows the exact type used as a type argument in this particular call . When called filterIsInstance< String>(), Type arguments passed . Because the generated bytecode refers to a specific class , Instead of type parameters , It will not be affected by type parameter erasure at runtime .
tips:
belt reified Of type parameter inline Function cannot be in java Call in code , Ordinary inlining can be done in the same way as regular functions java Call in , But the inlining feature is lost . Functions with typed materialized arguments require special handling , Replace the value of the type argument with the bytecode . Must always be inline , So it can't be used java Call in the normal way .
2.3 Materialized types replace class references and restrictions on their use
Materialization reified Use scenarios .
inline fun <reified T:Activity> Context.startActivity(){
val intent=Intent(this,T::class.java)
startActivity(intent)
}
Materialization type T, It can be used as a concrete type in a function
Can be used in :
- Type checking and type conversion (is,as?)
- Use kotlin Reflection of api
- obtain Class(::class.java)
- As type arguments for calling other functions
Can't do :
- Create an instance of a class that specifies type parameters
- Call the companion object of the type parameter
- When calling the parameter function of the materialized type, use the formal parameter of the non materialized type as the type argument
- Ba class , The type parameter of an attribute or non inline function is marked as reified
3. Variant : Declare point deformations and use point deformations
Variant : Used to describe arguments with the same base type and different types ( Generic ) How the types of are related . for example List<String> and List<Any>, A proper understanding of deformation helps to create that which is neither inconvenient nor Restrict users , It will not destroy what users expect Type safety
fun printContents(list:List<Any>){
println(list.joinToString())
}
fun main{
printContents(listof("a","b"))
}
>>>> a,b
The function treats each element as Any treat , Because the string is Any, It's completely safe . Then there is a situation to consider , If the formal parameter is List Will function interface types still be safe ?
fun printContents(list:MutiableList<Any>){
list.add(100)
}
This is the unsafe type , Because in the function for List The element of . If you call in the above way, you will report a type conversion exception .
3.1 class 、 type 、 subtypes
The type of the variable specifies the possible values of the variable , Sometimes you can think of types and classes as the same concept . But they are not exactly the same .
A generic class : You can use the class name as a type directly .
var x:String
var x:String?
One kotlin Class can be used to construct at least two types 【 Null type 】 and 【 Non empty type 】
The case of generic classes becomes more complicated , To get a valid type, you need a type argument to replace the type parameter .List Not a type , But all the alternatives listed below are legal types .List、List<List>, Each generic class may generate a potentially wireless number of types .
subtypes 、 Supertype It's the opposite . In a specific context . Whenever you need a type A Value , Can use types B The value of . type B It's the type A Subtypes of . And vice versa A It's the type B The supertype of . The compiler checks this every time it assigns a value to a variable or passes an argument to a function ( Whether the type of the argument is a subtype of the parameter type .)
subtypes and Subclass , It essentially means the same thing , however kotlin Nullable and non nullable types of the same class , Do not follow this .A yes A? Subtypes of . The reverse is not true .
Invariant type : A generic class MutableList If for any two types A and B,MutableList neither MutableList Its subtype is not its supertype ,MutableList It is called immutable on this type parameter . stay kotlin Speaking in a language environment ,java Classes in are immutable .( Readable class ,Mutiable Modify the read / write class )
3.2 Covariance , Inversion
Covariance : Keep subtype relationships , Modifier :<out T> Can only be used in the return value position
Inversion : Reverse rotor type relation , Modifier <in T>, It can only be used in the input position .
interface TransFormer<out T>{
fun transform(t:T):T
}
Here is the parameter declaration t:T yes in Location , Return value T yes out Location , Type parameter T Keywords on out There are two meanings .
- Subtypes will be preserved (Producer<Cat> yes Producer<Animal> Subtypes of )
- T Can only be used in out Location
for example :Kotlin type List The declaration of leads to List Is a readable list , Not right List Conduct add Elements .
// System declaration List<out T> Retaining subtypes will be preserved
public interface List<out E> : Collection<E> {
}
//
interface Comparator<in T>{
fun compare(e1:T,e2:T):Int{
}
}
| Covariance | Inversion | Immutable |
|---|---|---|
| Producer< out T> | Consumer< in T> | MutableList< T> |
| The subtype relationship of the class preserves :Producer< Cat> yes Producer< Animal> Subtypes of | Subtypes are reversed ,Consumer< Animal> yes Consumer< Cat> Subtypes of | No subtypes |
| T Only in out Location | T Only in ini Location | T Can be in in perhaps out Location or any other location |
Tips:
kotlin Representation (P)->R Is said Function<P,R> Another form of readability , It can be written.
<in P,out R>, Means the first type parameter of this function type , Subtypes are reversed , The second type parameter subtype preserves .
3.3 Use point variant : Specify the variant where the type appears .
Declare point variants : It is convenient to specify parameter types and use deformation modifiers when declaring classes . After the modifier is decorated , Will be applied where all classes are used .
Use point deformation : Every time you use a type with a type parameter , You can specify whether type accommodation can be replaced with its subtype or supertype . such as java Wildcard syntax for <? extends>,<?Super>;
kotlin Point deformation is also supported , Allows you to specify deformations where type parameters appear .( Even if the type declaration cannot be declared as Covariance or Inversion )
MutableList Neither covariant nor contravariant , Because it produces and consumes values of the types specified as their type parameters at the same time , But the common scenario for this type of variable is , It is common to use a particular function as a role .
fun <T> copyData(source:Mutiable<T>,destination:MutableList<T>){
for(src in source){
destination.add(src)
}
}
To make the function support different types of lists , A second generic parameter can be introduced
fun <T:R,R> copyData(source:Mutiable<T>,destination:MutableList<R>){
for(src in source){
destination.add(src)
}
}
You can use the morph modifier to achieve the same function more gracefully
fun <T> copyData(source:Mutiable<out T>,destination:MutableList<int T>){
for(src in source){
destination.add(src)
}
}
tips:
kotlin Use point variant to directly correspond to java Bounded wildcard ,kotlin Medium MutableList<outT> Corresponding java Medium MutableList<? extends T> It means the same thing ,in Projective MutableList<in T> Corresponding java Of MutableList<? super T>, Using point variants helps to broaden the range of acceptable types .
3.4 Model projection : Use * Instead of type parameters
Asterisk projection : Indicates that you do not know any information about generic arguments
MutiableList<> And MutiableList<Any?> Dissimilarity ,(MutiableList stay T Is of invariant type ),MutiableList<Any?> Can contain any type of element ,MutiableList<> Contains elements of a specific type , The specific element doesn't need to be concerned .
MutiableList<*> Contains a list of special types , The specific type is not clear , It leads to a problem , This type of collection can only read and cannot write any elements ( I don't know which type can be stored , An error will be reported for any type of deposit )
summary :
kotlin Generics and java Quite close to , Declare generic classes and generic functions in the same way ,kotlin Generic , Type arguments are also erased at run time , So it can't be used is Operator , You can declare a function as inline , The type parameter is marked as reified After implementation, the type arguments of generic parameters can be obtained at function runtime for use is Judge . Variant is a way to describe the subtype relationship between generic classes with different type parameters of the same base class . It states that one of the generic parameters is a subtype of the other generic parameter , The reverse is the supertype . You can declare that a class is covariant on a type parameter , If this parameter is only used in out Location , Inversion is just the opposite , Only in in Location ,kotlin in List Declared covariant , that List< String> yes List< Any> Subtypes of .MutiableList Function type , You can declare inversion on the first parameter , The second parameter is covariant . send (Animal)->Int Become (Cat)->Number Subtypes of .kotlin You can specify variants for the entire generic class ( Declare point deformation ), You can also specify variants for the specific use of generic types ( Use point variant ); When the exact type arguments are unknown or unimportant , You can use projection syntax
边栏推荐
- 牛客网:大数加法
- 今年的 618 不行了?
- Nanjing University static program analyses -- Introduction learning notes
- 还在用 Xshell ?试试这款炫酷的 SSH 终端工具吧,功能很强大!
- 【Leetcode】297. 二叉树的序列化与反序列化 (困难)
- In the "roll out" era of Chinese games, how can small and medium-sized manufacturers solve the problem of going to sea?
- 函数调用模型
- variable
- The new razor component supports proxy connection to RDP, and jumpserver fortress v2.23.0 is released
- Beaucoup de sociétés de logiciels sont en fait des "blagues"
猜你喜欢

Fisher信息量检测对抗样本代码详解

Garbage collector

【毕业N年系列】 毕业第四年

Use picgo core and Alibaba cloud to automatically upload typera pictures
![[ros2 basics] Introduction to navigation2 navigation system](/img/7f/ad6af972460d7a78fb28d9b4c24477.png)
[ros2 basics] Introduction to navigation2 navigation system
![[graduation n-year series] the fourth year of graduation](/img/0a/e7d903dec475c54ba1277fe133963f.png)
[graduation n-year series] the fourth year of graduation

【mysql学习笔记17】常用函数整理

Design a print function to print the whole tree

贝叶斯公式的两种理解

UDP和TCP的对比
随机推荐
很多軟件公司,其實都是“笑話”
泊松抽样与伯努利抽样主要联系与区别
[MySQL learning notes 13] comprehensive exercise of query statements
IEC62133与EN62133有何区别?主要测试哪些项目?
Integrated base scheme presentation
Uni app framework learning notes
栈的生长方向和内存生长方向
Variables and pointers
Niuke network: verify the IP address
贝叶斯公式的两种理解
List set map in kotlin
Redis6.0新特性(上)
Use picgo core and Alibaba cloud to automatically upload typera pictures
设计一个打印整棵树的打印函数
data type
【没搞懂路由策略?盘它!】
关于xlrd库的基础操作(新手向)
Summary of the 16th week
Exness: the impact of inflation in the United States is too great, and the leaders of the Federal Reserve have expressed their position one after another
Design and implementation of face verification system for floating population management