1. Remote control story: Generic
Girlfriend: I really want a universal remote control.
Me: why don't I teach you to implement one with Kotlin's generics!
Girlfriend: cut, you want to fool me to learn Kotlin. [white eyes]
Me: it's really simple. I'm sure you'll see it at a glance.
1-1 generic class
Me: This is a universal remote control with a generic parameter
// Generic parameter (formal parameter) of class // ↓ class Controller<T>() { fun turnOn(obj: T){ ... } fun turnOff(obj: T){ ... } }
Me: it's also easy to use. Just pass in the corresponding generic type to control what you want, just like selecting a pattern:
// As a generic argument // ↓ val tvController: Controller<TV> = Controller<TV>() val tv = TV() // Control TV tvController.turnOn(tv) tvController.turnOff(tv) // Electric fan as generic argument // ↓ val fanController: Controller<Fan> = Controller<Fan>() val fan = Fan() // Control electric fan fanController.turnOn(fan) fanController.turnOff(fan)
With the help of Kotlin's top-level function, the Controller class can even be omitted, and the generic function can be used directly:
1-2 generic functions
// Generic arguments to functions // ↓ ↓ fun <T> turnOn(obj: T){ ... } fun <T> turnOff(obj: T){ ... }
Generic functions are also simple to use:
// Control TV val tv = TV() turnOn<TV>(tv) turnOff<TV>(tv) // Control fan val fan = Fan() turnOn<Fan>(fan) turnOff<Fan>(fan)
Girlfriend: I know how to use it! Is that right?
val boyFriend = BoyFriend() turnOff<BoyFriend>(boyFriend)
Me:
2. Recruitment story: invariance of generics
Girlfriend: I want to recruit some college students to do part-time jobs. Please recommend some universities.
Me: OK, but I'll recommend it to you through Kotlin generics.
Girlfriend: Er... The generic type you talked about just now is quite simple. What's new this time?
Me: you'll see.
Me: let's do some preparatory work first:
// student open class Student() // schoolgirl class FemaleStudent: Student() // university class University<T>(val name: String) { // Take it out on behalf of recruitment fun get(): T { ... } fun put(student: T){ ... } }
I: your recruitment needs can be described with this Code:
// Pay attention here // Girlfriend needs a University (variable declaration) ↓ lateinit var university: University<Student> // Pay attention here // I recommend any university ↓ university = University<Student>("A university") val student: Student = university.get()// recruit
Girlfriend: it turns out that Kotlin is not so difficult
Girlfriend: can you assign a "women's University"?
Me: No, it will report an error.
// Pay attention here // ↓ lateinit var university: University<Student> // This is the reason for the error // ↓ university = University<FemaleStudent>("university for women") val student: Student = university.get() // Compiler error!! /* Type mismatch. Required: University<Student> Found: University<FemaleStudent> */
Girlfriend: what the hell...
Me: Although there is a parent-child relationship between Student and FemaleStudent, there is no relationship between University and university. This is called the invariance of generics.
Girlfriend: This is unreasonable! Are the students recruited by women's universities not students?
Me: of course, recruitment is logical, but don't forget that University has another method.
Me: how do you prevent others from putting a male student in a women's University?
Me: let's see what problems will arise if "women's University" can be used as "ordinary university":
// The declared type is: Ordinary University, however, the actual type is: Women's University. // ↓ ↓ var university: University<Student> = University<FemaleStudent>("university for women") val maleStudent: Student = Student() // Male students are put into women's universities! unreasonable. university.put(maleStudent)
Girlfriend: I see. It turns out that this is the reason for generic invariance. It can really avoid a lot of trouble.
// By default, the compiler only allows this // The declared generic parameters should be consistent with the actual ones ↓ ↓ var normalUniversity: University<Student> = University<Student> ↓ ↓ var wUniversity: University<FemaleStudent> = University<FemaleStudent>
3. Recruitment: covariant of generics
Girlfriend: if I delete the put method in the university class, can I assign a value with "women's University"? In this way, there is no need to worry about putting male students in women's universities.
Me: This is not enough. We also need to add a keyword out to tell the compiler: we will only take it out from the university class, not put it in. At this time, university can be regarded as a subclass of University.
Me: This is called generic covariance.
open class Student() class FemaleStudent: Student() // Look here // ↓ class University<out T>(val name: String) { fun get(): T { ... } }
Girlfriend: I'll try. It's really good!
// No more error reporting var university: University<Student> = University<FemaleStudent>("university for women") val student: Student = university.get()
Me: it's a waste of time not to write code.
4. Fill in volunteer Stories: generic contravariant
Girlfriend: my sister has just finished the college entrance examination. She will fill in her volunteer soon. Please recommend a university to me.
Me: I've just seen generic covariance. Why don't you try to solve the problem of filling in volunteers by yourself? There happens to be a put method in the University. Just take put as a volunteer.
Girlfriend: I'll try to follow the gourd and draw a gourd... Apply for a women's University for my sister.
open class Student() class FemaleStudent: Student() class University<T>(val name: String) { fun get(): T { ... } // Put it in, it means to fill in the volunteer fun put(student: T){ ... } } val sister: FemaleStudent = FemaleStudent() val university: University<FemaleStudent> = University<FemaleStudent>("university for women") university.put(sister)//Women's University
Girlfriend: perfect!
Me: great.
Girlfriend: can you apply for another general university?
Me: No, have you forgotten generic invariance?
val sister: FemaleStudent = FemaleStudent() // Reason for error reporting: the declaration type is: Women's University, and the assignment type is: Ordinary University // ↓ ↓ val university: University<FemaleStudent> = University<Student>("Ordinary university") university.put(sister) // report errors /* Type mismatch. Required: University<FemaleStudent> Found: University<Student> */
Girlfriend: my sister can apply for a women's University, but she can't apply for an ordinary comprehensive university? This is unreasonable!
Me: don't forget, does University have a get method? Ordinary comprehensive universities don't have to be female students.
Girlfriend: Oh. Then I delete the get method and add a keyword?
Me: Yes. Delete the get method and add a keyword: in. Its function is to tell the compiler that we will only put it in the university class, not take it out. At this time, university can be regarded as a subclass of University.
Me: This is actually called the inversion of generics, and their inheritance relationship is reversed.
// Look here // ↓ class University<in T>(val name: String) { fun put(student: T){ ... } } val sister: FemaleStudent = FemaleStudent() // Compile passed val university: University<FemaleStudent> = University<Student>("Ordinary university") university.put(sister)
Girlfriend: generics are interesting.
Me: covariance and inversion mentioned above. They are implemented by modifying the generic declaration of the University class, so they are collectively referred to as declaration type change, which is a concept unique to Kotlin and not in Java.
5. Use site variance
Girlfriend: what if the University is provided by a third party and we can't modify it? Can you achieve the same goal without modifying the University class?
Me: Yes, it's necessary to change the type of use. They are also divided into: covariance at use and inversion at use.
open class Student() class FemaleStudent: Student() // Suppose University cannot modify class University<T>(val name: String) { fun get(): T { ... } fun put(student: T){ ... } }
5-1 covariance at use
Me: add an out keyword in front of the generic argument, which means that we will only take it out from the University, not put it in. By doing so, the use covariance is achieved.
// Look here // ↓ fun useSiteCovariant(university: University<out Student>) { val femaleStudent: Student? = university.get() // Error: Require Nothing? found Student? // university.put(femaleStudent) }
Girlfriend: it's easy to understand. What about the inverter? Add an in?
5-2 inverter at use
Me: Yes. Add an in keyword in front of the generic argument, which means that we will only put it in from the University and not take it out. In this way, the inversion at the use point is realized.
// Look here // ↓ fun useSiteContravariant(universityIn: University<in FemaleStudent>) { universityIn.put(FemaleStudent()) // Error: Require FemaleStudent? found Any? // val femaleStudent: FemaleStudent? = universityIn.get() }
Girlfriend: the thought is the same.
Girlfriend: if you recruit students from University, you take them out. In this case, it is covariant. You can use university to replace University, because female students from women's universities and students from ordinary universities are students.
Girlfriend: if a university wants to recruit students, it is to put them in. In this case, it can only replace the university with the University, because the enrollment scope of ordinary universities is wider. Ordinary universities also accept students that women's universities can accept.
Me: you summed up very well. By the way, Kotlin's use is a type change. It's also called type projections. That's a terrible name.
The specific details of the above code can be seen in my GitHub Commit.
5-3 comparison between kotlin and Java
Me: since you have no pressure to understand Kotlin generics, I'll give you another meal to compare the use of Java.
Girlfriend: uh... What is Java?
Me: it's all right. Just watch it.
Covariance at use | Inverter at use | |
---|---|---|
Kotlin | University | University |
Java | University<? extends Student> | University<? super FemaleStudent> |
Me: is it simple and clear?
Girlfriend: it's also Kotlin's easy to understand: out means you can only get out and in means you can only put in.
Me: Yes.
Girlfriend: in contrast, Java's expression is really unable to make complaints about it. (-_-)
// Java chicken covariant syntax // ↓ University<? extends Student> covariant = new University<FemaleStudent>("university for women"); Student student = covariant.get(); // report errors covariant.put(student); // Java syntax // ↓ University<? super FemaleStudent> contravariant = new University<Student>("Ordinary university"); contravariant.put(new FemaleStudent()) // report errors Student s = contravariant.get();
The specific details of the above code can be seen in my GitHub Commit.
6. Kotlin generic combat
Me: here is a Demo of Kotlin. Why don't you see where generic optimization can be used?
Girlfriend: too much! Even if you let me learn Kotlin, do you want me to write code for you?
Girlfriend: you write, I'll see.
Me: Er... Listen to the leader.
6-1 generic version of the apply function
Me: This is the code in the previous chapter. In fact, this apply function can be simplified with generics so that all classes can use it.
## Interview dictionary **Knowledge points must be asked during the interview BATJ Real interview questions over the years+analysis** **[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)** ![](https://img-blog.csdnimg.cn/img_convert/0235ddb855acf2a54b54a5ad51b3e0f0.png) ### Summary of learning experience **(1) Adjust your mind** Mentality is the key to a person's success. If you don't adjust your mentality well, it's difficult to calm down and learn. Especially in such an impetuous society, the current situation of most programmers is three points and one line, and they feel very tired. Some older programmers will feel more anxiety, and this anxiety will become stronger and stronger with age, Then the only solution is to adjust your attitude and be confident, young and diligent.**Such adjustment, on the one hand, is helpful to your study, on the other hand, it makes you deal with the interview more calmly and smoothly.** **(2) Squeeze in time and make a plan** Once you have made up your mind to improve yourself, no matter how busy you are, you should squeeze time every day. Remember not to "catch fish in two days and dry the net in three days". In addition, it is also necessary to make a good study plan. Review logically and methodically, check the omissions and fill the gaps first, and then review systematically,**In this way, we can get twice the result with half the effort and the effect will be immediate.** **(3) Constantly learn technical knowledge and update their knowledge reserves** In storage...(img-Xo8GfQLK-1630558302320)] ### Summary of learning experience **(1) Adjust your mind** Mentality is the key to a person's success. If you don't adjust your mentality well, it's difficult to calm down and learn. Especially in such an impetuous society, the current situation of most programmers is three points and one line, and they feel very tired. Some older programmers will feel more anxiety, and this anxiety will become stronger and stronger with age, Then the only solution is to adjust your attitude and be confident, young and diligent.**Such adjustment, on the one hand, is helpful to your study, on the other hand, it makes you deal with the interview more calmly and smoothly.** **(2) Squeeze in time and make a plan** Once you have made up your mind to improve yourself, no matter how busy you are, you should squeeze time every day. Remember not to "catch fish in two days and dry the net in three days". In addition, it is also necessary to make a good study plan. Review logically and methodically, check the omissions and fill the gaps first, and then review systematically,**In this way, we can get twice the result with half the effort and the effect will be immediate.** **(3) Constantly learn technical knowledge and update their knowledge reserves** For a programmer, technical knowledge is very important and can be said to be the top priority.**If you want to interview a large factory, you must have a very rich knowledge reserve. If you lack arms and legs, you can't pass the interview alone, let alone in actual work.**In terms of technology, first of all, we must have solid basic knowledge, including language foundation, computer foundation, algorithm and programming in our own direction.