The two generic keywords out and in in Kotlin are the same as in Java? Extends and? Super is a one-to-one relationship
Declaring a list of a parent class and assigning a list object to a subclass is not allowed in Java (this is the same in Java and Kotlin)
package com.wuyue; import java.util.ArrayList; import java.util.List; Public class TestJavaG {public static void main(String[] args) {AClass AClass = new BClass(); List<AClass> list = new ArrayList<BClass>(); list <AClass> list = new ArrayList<BClass>(); AClass[] aArray = new BClass[3]; AClass[] aArray = new BClass[3]; Class BClass extends AClass {} class BClass extends AClass {}Copy the code
Of course, if you must, you can
// Subclass generic objects can be assigned to the parent class's generic type declaration List<? extends AClass> a_list = new ArrayList<BClass>(); // The following two statements will return an error when called, because we use? Extends removes this restriction but has the added effect that we can only use a_list and not modify it a_list.add(new AClass()); a_list.add(new BClass())Copy the code
A lot of people here don’t understand, what’s the use of this thing? It actually works. If you only want to use the value of a parameter in a function, and you don’t want to change it, then use this, okay? Extends greatly extends the scope of this function. Avoid a lot of trouble
package com.wuyue; import java.util.ArrayList; import java.util.List; Public class TestJavaG {// Not used? Extends wildcard so its argument must be static void printlnAll(List<AClass> aClassList) {for(AClass aClass : aClassList) { aClass.printlnInfo(); }} // use? Extends wildcard so its arguments can be static void printlnAll2 declared by any Aclsss subclass (List<? extends AClass> aClassList) {for(AClass aClass : aClassList) { aClass.printlnInfo(); } } public static void main(String[] args) { List<AClass> aList = new ArrayList<>(); List<BClass> bList = new ArrayList<>(); PrintlnAll (aList); PrintlnAll (bList); // This method will not compile the error because it is used in the method signature. Extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends wildcard extends printlnAll2(bList); } // class AClass {public voidprintlnInfo() {
System.out.println("a class"); }} class BClass extends AClass {public voidprintlnInfo() {
System.out.println("B class"); }}Copy the code
? Super and? Extends is just the opposite. Let’s look at a couple of examples
package com.wuyue; import java.util.ArrayList; import java.util.List; Public class TestJavaG {public static void main(String[] args) {BClass BClass = new AClass(); List<BClass> blist = new ArrayList<AClass>(); // Once we use? Super is a wildcard, so you don't get an error // It seems crazy, subclass declaration, superclass assignment, whatever? But it does work... List<? super BClass> blist2 = new ArrayList<AClass>(); } // class AClass {public voidprintlnInfo() {
System.out.println("a class"); }} class BClass extends AClass {public voidprintlnInfo() {
System.out.println("B class"); }}Copy the code
Now let’s look at what happens after it’s removed
package com.wuyue; import java.util.ArrayList; import java.util.List; public class TestJavaG { static void addOne(List<BClass> bClassList) { bClassList.add(new BClass()); } static void addOne2(List<? super BClass> bClassList) { bClassList.add(new BClass()); } public static void main(String[] args) { List<AClass> aClasses = new ArrayList<>(); AddOne (aClasses); AddOne2 (aClasses); } // class AClass {public voidprintlnInfo() {
System.out.println("a class"); }} class BClass extends AClass {public voidprintlnInfo() {
System.out.println("B class"); }}Copy the code
In Kotlin, out and in correspond to each other, right? Extends and? Super, I personally think Kotlin’s keywords are more concise than those in Java.
Out means? Extends means you can only read me, not write me. Because out means to export
In is the same thing as? Super means you can only write me, you can’t read me, because in means write inside
Package com.wuYUE // This avoids adding out and to every useinThis kind of keyword. // This is one way kotlin is more convenient than Java: write out or is directly at type creation timein
interface Producer<out T> {
fun produce(): T
}
interface Consumer<in T> {
fun consume(): T
}Copy the code
// In javaz, these two forms are equivalent to List<? > alist = new ArrayList<BClass>(); List<? extends Object> alist2 = new ArrayList<BClass>(); Var TV :List<*> var tv2:List<out Any>Copy the code
Finally, there is no way to make a type judgment when using generics in Java. For example, if T is a generic, you will definitely get an error:
objectA instanceof TCopy the code
But the inline function +reified keyword in Kotlin does something similar:
inline fun <reified T> printTypeMath(item: Any) {
if (item is T) {
println("match")}else {
println("miss")}}Copy the code
Here may also have some people a little confused, Java generics in the end is used for what, why the need for this thing, type erasure and type safety is what, here a simple extension, appropriate understanding of some, help us in the future work with good generics
In short, Java generics are what the Java compiler helps implement. The resulting bytecode does not contain the whole generics thing. List<String> List<Integer> is always a List when you compile it.
Type erasure is the substitution of type parameters in code directly with concrete classes at compile time. That’s all.
The advantage is that many errors can be found at compile time, which is a great convenience.
Here’s an example:
public class JavaCode {
public static Object setAndReturn(Object obj) {
return obj;
}
public static void main(String[] args) {
Integer i = (Integer) setAndReturn(new String("abc")); }}Copy the code
So it’s obviously going to crush at execution time, because a string can’t be turned into an integer
We believe that in the actual development, this kind of mistake is certainly not rare. But if you write with generics, you don’t get this error at all, because you get an error at compile time, compile an error.
public class JavaCode {
public static <T> T setAndReturn(T t) {
return t;
}
public static void main(String[] args) {
Integer i = (Integer) setAndReturn(new String("abc")); }}Copy the code
In addition, generics can save us a lot of code (cast)! Only for lazy people. Look at the following code:
class Fruit{}
class Apple extends Fruit{}
class Banana extends Fruit{}
class Bucket{
public Apple getApple() {
return apple;
}
public void setApple(Apple apple) {
this.apple = apple;
}
Apple apple;
}
Copy the code
We only defined two types of fruit, and then we defined a basket, but this basket only supports apples, what if we want the basket to support other types of fruit?
class Bucket{
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
Object object;
}Copy the code
This may seem like a good idea at this point, but we’ll eventually have to add a cast to this Bucket
Bucket bucket=new Bucket();
bucket.setObject(new Apple());
Apple apple=(Apple)bucket.getObject();Copy the code
It’s cumbersome, and if you’re not careful, you’ll get a cast error. Using generics is much easier:
class Bucket<T> {
public T getObject() {
return t;
}
public void setObject(T t) {
this.t = t;
}
T t;
}Copy the code
This will be more convenient to use.
Bucket<Apple> bucket = new Bucket();
bucket.setObject(new Apple());
Apple apple = bucket.getObject();Copy the code
The thing to notice here, though, is that generics are a little bit more convenient to write. But after the compiler’s generic erasure, the bytecode representation is essentially the same.
Whether you are Bucket<Apple> or Bucket<Banana> is equivalent to writing Bucket<Object> when compiled. There’s no difference
Reference data: www.bilibili.com/video/av663…
Kaixue. IO/kotlin – gene…
zhuanlan.zhihu.com/p/26965437