当前位置:网站首页>Generics, generic defects and application scenarios that 90% of people don't understand
Generics, generic defects and application scenarios that 90% of people don't understand
2022-07-05 09:52:00 【hi-dhl】
Author's brief introduction : hi Hello everyone , I am a dhl, Is maintaining its own Personal website , Focus on sharing the latest technology and original articles , involve Kotlin、Jetpack、 Algorithm animation 、 data structure 、 System source code wait .
Reprint note : Not authorized , Prohibited reproduced .
The full text is divided into Video version and Text version ,
- Text version : Text focuses on detail and depth , Some knowledge , The video is not easy to express , The text description is more accurate
- Video version : The video will be more intuitive , Read the text version , Watching video , The knowledge points will be clearer
Video version bilibili Address :https://b23.tv/AdLtUGf
Generics are no stranger to every developer , I often see it in the project , But there are many friends , Every time I see wildcards ? extends 、 ? super 、 out 、 in I can't tell the difference between them , And under what circumstances .
Through this article, you will learn the following .
- Why generics
- Kotlin and Java The covariance of
- Kotlin and Java The inverse of
- wildcard
? extends、? super、out、inThe differences and application scenarios - Kotlin and Java The difference of array covariance
- The defect of array covariance
- Application scenarios of covariance and inversion
Why generics
stay Java and Kotlin We often use sets in ( List 、 Set 、 Map wait ) To store data , Various types of data may be stored in the collection , Now we have four data types Int 、 Float 、 Double 、 Number, Let's say there's no generics , We need to create four collection classes to store the corresponding data .
class IntList{ ...... }
class FloatList{ ...... }
class DoubleList{ ...... }
class NumberList{ ...... }
......
more
If there are more types , You need to create more collection classes to store the corresponding data , This shows that it is impossible , Generics are a “ Universal type matcher ”, At the same time, it can make the compiler ensure type safety .
Generics will be concrete types ( Int 、 Float 、 Double wait ) Use symbols instead of when declaring , When you use it , To specify a specific type .
// Use symbols instead of when declaring
class List<E>{
}
// stay Kotlin Use in , Specify the specific type
val data1: List<Int> = List()
val data2: List<Float> = List()
// stay Java Use in , Specify the specific type
List<Integer> data1 = new List();
List<Float> data2 = new List();
Generics help us solve the above problems , But new problems have arisen , We all know Int 、 Float 、 Double yes Number subtypes , Therefore, the following code can work normally .
// Kotlin
val number: Number = 1
// Java
Number number = 1;
Let's take three seconds to think , Whether the following code can be compiled normally .
List<Number> numbers = new ArrayList<Integer>();
The answer is no , As shown in the figure below , Compilation error .

This means that generics are immutable ,IDE Think ArrayList<Integer> No List<Number> subtypes , This assignment is not allowed , So how to solve this problem , This requires covariance , Covariance allows the above assignment to be legal .
Kotlin and Java The covariance of
- stay Java Wildcards are used in
? extends TRepresents covariance ,extendsThe parent type is restrictedT, among?Indicates an unknown type , such as? extends Number, As long as the type passed in when declaring isNumberperhapsNumberAll subtypes of - stay Kotlin Key words in
out TRepresents covariance , Meaning and Java equally
Now let's modify the above code , Take three seconds to think , Whether the following code can be compiled normally .
// kotlin
val numbers: MutableList<out Number> = ArrayList<Int>()
// Java
List<? extends Number> numbers = new ArrayList<Integer>();
The answer is that you can compile normally , Covariant wildcards ? extends Number perhaps out Number Express acceptance Number perhaps Number The subtype is a collection of objects , Covariance relaxes constraints on data types , But relaxation comes at a price , We were thinking for three seconds , Whether the following code can be compiled normally .
// Koltin
val numbers: MutableList<out Number> = ArrayList<Int>()
numbers.add(1)
// Java
List<? extends Number> numbers = new ArrayList<Integer>();
numbers.add(1)
call add() Method will fail to compile , Although covariance relaxes the constraints on data types , Acceptable Number perhaps Number The subtype is a collection of objects , But at the cost of Unable to add element , You can only get elements , So covariance can only be a producer , Provide data to the outside .
Why can't I add elements
because ? Indicates an unknown type , So the compiler doesn't know what kind of data it will add to the collection , Therefore, it is simply not allowed to add elements to the collection .
But if you want the above code to compile and pass , Want to add elements to the collection , This requires inversion .
Kotlin and Java The inverse of
Inversion actually reverses the inheritance relationship , such as Integer yes Number Subtypes of , however Integer Add the inverse wildcard ,Number yes ? super Integer Subclasses of , As shown in the figure below .
[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-8bRLR2Qd-1655947414076)(https://img.hi-dhl.com/16551339994410.jpg)]
- stay Java Wildcards are used in
? super TRepresent contravariant , among?Indicates an unknown type ,superMainly used to restrict subtypes of unknown typesT, such as? super Number, As long as the declaration is passed inNumberperhapsNumberThe parent type of the can - stay Kotlin Key words in
in TRepresent contravariant , Meaning and Java equally
Now let's simply modify the above code , Take three seconds to think about whether you can compile normally .
// Kotlin
val numbers: MutableList<in Number> = ArrayList<Number>()
numbers.add(100)
// Java
List<? super Number> numbers = new ArrayList<Number>();
numbers.add(100);
The answer can be compiled normally , Inverse wildcard ? super Number Or keywords in Reverse the inheritance relationship , Mainly used to restrict subtypes of unknown types , In the example above , The compiler knows that the subtype is Number, So as long as it's Number Subclasses of can be added .
Contravariant can add elements to the set , Can I get the elements ? Let's take three seconds to think about , Whether the following code can be compiled normally .
// Kotlin
val numbers: MutableList<in Number> = ArrayList<Number>()
numbers.add(100)
numbers.get(0)
// Java
List<? super Number> numbers = new ArrayList<Number>();
numbers.add(100);
numbers.get(0);
No matter call add() Method or call get() Method , Can be compiled normally , Now modify the above code , Think about whether you can compile normally .
// Kotlin
val numbers: MutableList<in Number> = ArrayList<Number>()
numbers.add(100)
val item: Int = numbers.get(0)
// Java
List<? super Number> numbers = new ArrayList<Number>();
numbers.add(100);
int item = numbers.get(0);
call get() Method will fail to compile , because numbers.get(0) The value obtained is Object The type of , So it cannot be assigned directly to int type , Contravariant is the same as covariant , Relaxed constraints on data types , But at the cost of Cannot read elements by generic type , That is, add... To the set int Data of type , call get() Method does not get int Data of type .
For the content of this section , Let's briefly summarize .
| keyword (Java/Kotlin) | add to | Read | |
|---|---|---|---|
| Covariance | ? extends / out | ||
| Inversion | ? super / in |
Kotlin and Java The difference of array covariance
Whether it's Kotlin still Java The meaning of covariance and contravariant is the same , But the wildcards are different , But they also have differences .
Java Support array covariance , The code is as follows :
Number[] numbers = new Integer[10];
however Java Array covariance in is defective , Change the above code , As shown below .
Number[] numbers = new Integer[10];
numbers[0] = 1.0;
Can compile normally , But it will crash when running .

Because at first I will Number[] Covariant transformation Integer[], Then I added... To the array Double Data of type , So the operation will crash .
and Kotlin Our solution is very straightforward , Array covariance is not supported , There will be errors when compiling , For array inversion Koltin and Java Don't support .
Application scenarios of covariance and inversion
Covariant and inverse applications need to follow PECS(Producer-Extends, Consumer-Super) principle , namely ? extends perhaps out As a producer ,? super perhaps in As a consumer . The advantages of following this principle are , You can keep your code safe at compile time , Reduce the occurrence of unknown errors .

Covariant application
- stay Java Wildcards are used in
? extendsRepresents covariance - stay Kotlin Key words in
outRepresents covariance
Covariant can only read data , Can't add data , So I can only be a producer , Provide data to the outside , So it can only be used to output , It is not used to input .
stay Koltin A covariant class in , Add before parameter out After modification , This parameter is in the current class Can only be used as the return value of a function , Or modify the read-only attribute , The code is as follows .
// Normal compilation
interface ProduceExtends<out T> {
val num: T // For read-only properties
fun getItem(): T // Return value for function
}
// Compile failed
interface ProduceExtends<out T> {
var num : T // For variable attributes
fun addItem(t: T) // Parameters for function
}
When we determine that an object is only a producer , Provide data to the outside , Or as the return value of a method , We can use ? extends perhaps out.
- With Kotlin For example , for example
Iterator#next()Method , Keyword usedout, Returns each element in the collection

- With Java For example , for example
ArrayList#addAll()Method , Wildcards are used? extends

Pass in the parameter Collection<? extends E> c As a producer to ArrayList Provide data .
Inverter applications
- stay Java Use wildcards in
? superRepresent contravariant - stay Kotlin Use keywords in
inRepresent contravariant
Inversion can only add data , Cannot read data by generics , So only as a consumer , Therefore, it can only be used to input , Cannot be used to output .
stay Koltin An inverse class in , Add before parameter in After modification , This parameter is in the current class Can only be used as an argument to a function , Or modify variable attributes .
// Normal compilation , Parameters for function
interface ConsumerSupper<in T> {
fun addItem(t: T)
}
// Compile failed , Return value for function
interface ConsumerSupper<in T> {
fun getItem(): T
}
When we determine that an object is only a consumer , When passed in as a parameter , Only for adding data , We use wildcards ? super Or keywords in,
- With Kotlin For example , For example, extension methods
Iterable#filterTo(), Keyword usedin, Internally, it is only used to add data

- With Java For example , for example
ArrayList#forEach()Method , Wildcards are used? super

I don't know if my friends have noticed , In the source code above , Different generic tags are used separately T and E, Actually, let's pay a little attention , There are several high-frequency generic tags in the source code T 、 E 、 K 、 V wait , They are applied to different scenarios .
| Marker | Application scenarios |
|---|---|
| T(Type) | class |
| E(Element) | aggregate |
| K(Key) | key |
| V(Value) | value |
This is the end of the article , Thanks for reading , It's not easy to stick to originality , Welcome to 、 give the thumbs-up 、 Share it with your friends , I will continue to share original dry goods !!!
边栏推荐
- Oracle combines multiple rows of data into one row of data
- 小程序启动性能优化实践
- What should we pay attention to when entering the community e-commerce business?
- LeetCode 31. Next spread
- 百度智能小程序巡检调度方案演进之路
- 揭秘百度智能测试在测试自动执行领域实践
- H. 265 introduction to coding principles
- Deep understanding of C language pointer
- uni-app---uni.navigateTo跳转传参使用
- Small program startup performance optimization practice
猜你喜欢

分布式数据库下子查询和 Join 等复杂 SQL 如何实现?

卷起來,突破35歲焦慮,動畫演示CPU記錄函數調用過程

【OpenCV 例程200篇】219. 添加数字水印(盲水印)

基于宽表的数据建模应用

【sourceTree配置SSH及使用】

Application of data modeling based on wide table

How to correctly evaluate video image quality

Node-RED系列(二九):使用slider与chart节点来实现双折线时间序列图

Vs code problem: the length of long lines can be configured through "editor.maxtokenizationlinelength"

From "chemist" to developer, from Oracle to tdengine, two important choices in my life
随机推荐
Apache DolphinScheduler 入门(一篇就够了)
cent7安装Oracle数据库报错
uni-app---uni.navigateTo跳转传参使用
百度智能小程序巡检调度方案演进之路
Tdengine already supports the industrial Intel edge insight package
Idea debugs com intellij. rt.debugger. agent. Captureagent, which makes debugging impossible
Fluent development: setting method of left and right alignment of child controls in row
MySQL does not take effect in sorting string types
【C语言】动态内存开辟的使用『malloc』
[200 opencv routines] 219 Add digital watermark (blind watermark)
MySQL installation configuration and creation of databases and tables
【el-table如何禁用】
90%的人都不懂的泛型,泛型的缺陷和应用场景
[team PK competition] the task of this week has been opened | question answering challenge to consolidate the knowledge of commodity details
Develop and implement movie recommendation applet based on wechat cloud
The writing speed is increased by dozens of times, and the application of tdengine in tostar intelligent factory solution
[how to disable El table]
百度交易中台之钱包系统架构浅析
Wechat applet obtains household area information
【技术直播】如何用 VSCode 从 0 到 1 改写 TDengine 代码