-
What are generics?
- Generics are a “parameterized type” feature introduced in JDK1.5.
- Generics can restrict parameter types without casting.
- Generics detect type matches at the compiler, avoiding the “ClassCastException” caused by inconsistent types at runtime.
-
Simple use of generics
-
You can add any type without using generics
ArrayList list = new ArrayList();
list.add("hello");
list.add(18);
list.add('u');
Copy the code
-
Getting data without using generics is converted toObjectWhen used, it needs to be strong
for (Object o : list) {
if (o instanceof String) {
String item = (String) o;
}else if(o instanceof Integer){
Integer item = (Integer) o;
}else if. . }Copy the code
-
Adding data using generics must be consistent with defined generics
// Define the generic type as String
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add(18); // Error type mismatch reported
list.add('u'); // Error type mismatch reported
Copy the code
-
Data obtained using generics is automatically converted to a generic type without strong casting
for (String s : list) {
System.out.println(s);
}
Copy the code
-
The definition of generics
- Before learning about generic definitions, learn about the format of generics
Generic by"< generic type >"composition The generic type can be any reference type or custom logo * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * a reference type: < String > or the < Object > * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * custom identifier is written casually Such as: < T > < SB > < TMD > < eat? > * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * but usually we don't recommend this writing, recommended the commonly used several E: Element (Element) K: keyword (Key) N: Number T: Type V: ValueCopy the code
-
A generic class
public class Generic<String>{
privateString item; } orpublic class Generic<T>{
private T item;
}
Copy the code
-
A generic interface
public interface Generic<String>{
String getItem(a); } orpublic interface Generic<T>{
T getItem(a);
}
Copy the code
-
Generic method
// Class 1 does not define generics. Methods must define generics before they can be used
public class GenericTest {
public <T> T getItem(T item) {
returnitem; }} Notice the difference between the top and bottom <T>// In case 2, the class has already defined generics, so methods can be used without having to define generics
public class GenericTest<T> {
public T getItem(T item) {
returnitem; }}Copy the code
-
Generic combat
- Define a simple class, a member variable, and a get set method
public class TestData<T> {
private T item;
private void setItem(T item) {
this.item = item;
}
private T getItem(a) {
returnitem; }}Copy the code
-
use
// Generics pass String
public static void main(String[] args) {
TestData<String> stringData = new TestData<>();
stringData.setItem("I'm a String."); String item = stringData.getItem(); } or// The generics pass in Integer
public static void main(String[] args) {
TestData<Integer> integerData = new TestData<>();
integerData.setItem(18);
Integer item = integerData.getItem();
}
Copy the code
-
Actual combat summary:
- Generics qualify the custom identifier to T, which can be passed in any type
- Class internals automatically convert T to the type passed in (generic erasers are not considered here)
- False input is passed in <String>
// Normal code
public class TestData<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem(a) {
returnitem; }}// The converted code
public class TestData<String> {
private String item;
public void setItem(String item) {
this.item = item;
}
public String getItem(a) {
returnitem; }}Copy the code
-
Unbounded wildcard
Unbounded wildcard
is usually identified in generics with a question mark, which can represent any type, for example:
public class GenericClass {
// unbounded wildcard generic arguments
public void setList(List
list) {
System.out.println("The length of the List is:+list.size()); }}Any type of generic parameter can be passed when called
ArrayList<Integer> integersList = new ArrayList<>();
ArrayList<Number> numbersList = new ArrayList<>();
GenericClass genericClass = new GenericClass();
genericClass.setList(numbersList); / / Integer types
genericClass.setList(integersList); / / Number type
Copy the code
-
<? What’s the difference between > and <T>?
Is itself a placeholder that can represent any type,<? > can be any type, so what’s the difference? Let’s look at some code:
Code snippet1:
/ /
an error occurs when a class is defined
public class GenericClass<? >{
/ /
Definition to methods also error
public<? >void setList(List
list){}}//
defines classes and methods without error
public class GenericClass<T> {
public <T> void setList(List<T> list) {
System.out.println("The length of the List is:+list.size()); }} code snippet2:
//
cannot be treated as a generic parameter
ArrayList<T> list = new ArrayList<>();
/ /
can be used as an indeterminate generic parameterArrayList<? > list =new ArrayList<>();
Copy the code
Conclusion:
- And < T> are generic wildcards that can be used as placeholders.
- Is an indeterminate type that cannot be defined on classes and methods and is usually passed in as a parameter.
- < T> is an explicit type that can be defined on classes and methods and can be used to do operations such as: T T = getNum();
-
A bounded wildcard
Let’s start with a piece of code and see why this is an error
// Define three classes of son, father and grandfather.
public class Son extends Father{}
public class Father extends Grandpa{}
public class Grandpa {}
// Define a set of sons and fathers
ArrayList<Son> sons = new ArrayList<>();
ArrayList<Father> fathers = new ArrayList<>();
setList(sons); // Error nani?? Isn't Son a subclass of Father? Why is an error reported?
setList(fathers); / / normal
// Receive a generic set of Father
private static void setList(List<Father> list){}Copy the code
The extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends This is where the following bounded wildcard comes in.
-
The upper bound wildcard <? extends T>
Now let’s change List to List
try
ArrayList<Son> sons = new ArrayList<>();
ArrayList<Father> fathers = new ArrayList<>();
ArrayList<Grandpa> grandpas = new ArrayList<>();
setList(sons); / / normal
setList(fathers); / / normal
setList(grandpas); // error because only Father or Father [child] can be passed
private static void setList(List<? extends Father> list){}Copy the code
-
The lower wildcard <? super T>
Now let’s change List to List
try
ArrayList<Son> sons = new ArrayList<>();
ArrayList<Father> fathers = new ArrayList<>();
ArrayList<Grandpa> grandpas = new ArrayList<>();
setList(sons); // error as Father or Father can only be passed
setList(fathers); / / normal
setList(grandpas); / / normal
private static void setList(List<? super Father> list){}Copy the code
Conclusion:
- The upper bound wildcard
restricts passing only subclasses of T or T itself - The lower wildcard
restricts passing in only the superclass of T or T itself
-
Side effects of bounded wildcards
// upper wildcard
private static void setList(List<? extends Father> list){
list.add(new Son()) / / an error
list.add(new Father()) / / an error
// Get from Father
for(Father father : list) { System.out.println(father); }}// lower wildcard
private static void setList(List<? super Father> list){
list.add(new Son()) / / normal
list.add(new Father()) / / normal
list.add(new Grandpa()) // Add Father or Father subclass
// Get only Object
for(Object o : list) { System.out.println(o); }}Copy the code
Conclusion:
- Upper bound wildcards cannot be added, but can only be obtained because it is not certain whether the passed generic is T itself or a subclass of T. If it is a subclass of T, adding T itself must be an error. Therefore, directly upper bound wildcards cannot be added, but they can be obtained normally.
- The lower bound wildcard can be added, but only T and T subclasses can be added, and only Object can be received. Since we cannot determine which parent of T is passed, we can only receive the largest parent Object.
-
Generic erasure
Since generics were introduced in JDK1.5, they only exist at compile time for downward compatibility, and generic-related code is erased before entering the JVM.
-
How do I prove that generics are erased?
You can see that two different collections of generics were created below, but after running it, you find that the Class is both java.util.arrayList. There is no generics, so the result is true
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass()); //true
}
Copy the code
-
Unrestricted type erasure becomes Object
-
Type erasure with limits, become caps
-
To maintain polymorphism, the system automatically generates the bridge method