• What are generics?

  1. Generics are a “parameterized type” feature introduced in JDK1.5.
  2. Generics can restrict parameter types without casting.
  3. Generics detect type matches at the compiler, avoiding the “ClassCastException” caused by inconsistent types at runtime.
  • Simple use of generics

  1. You can add any type without using generics
    ArrayList list = new ArrayList();
    list.add("hello");
    list.add(18);
    list.add('u');
Copy the code
  1. 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
  1. 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
  1. 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:
  1. Generics qualify the custom identifier to T, which can be passed in any type
  2. Class internals automatically convert T to the type passed in (generic erasers are not considered here)
  3. 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:

  1. And < T> are generic wildcards that can be used as placeholders.
  2. Is an indeterminate type that cannot be defined on classes and methods and is usually passed in as a parameter.
  3. < 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:

  1. The upper bound wildcard
    restricts passing only subclasses of T or T itself
  2. 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:

  1. 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.
  2. 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