Generics of Java Series

Since JDK 1.5 provides the concept of generics, generics allow developers to define safer types. Instead of having type conversion exceptions when enforcing a type conversion, you can use Object s to accomplish operations between different types of data without introspection. However, enforcing a type conversion (downward transition) can make errors when specific types are uncertain. The generic mechanismThe introduction is to solve the problem of ambiguous data types.

Define generic classes

Define a generic class with the following syntax:

//Define generic classes
class Class name<T>{
    
}

Among them, T denotes the name of one type, T can denote other names, and it is common to write T, <>There can be more than one type inside, separated by commas. Here is a generic class, as follows:

/**
 * Define generic classes
 * @author jzman
 * @param <T>
 */
public class GenercityClass<T1,T2> {
    
    private T1 score;
    private T2 desc;
    
    public GenercityClass() {}
    
    public GenercityClass(T1 score, T2 desc) {
        this.score = score;
        this.desc = desc;
    }
    public T1 getScore() {
        return score;
    }
    public void setScore(T1 score) {
        this.score = score;
    }
    public T2 getDesc() {
        return desc;
    }
    public void setDesc(T2 desc) {
        this.desc = desc;
    }
    
    public static void main(String[] args) {
        //When using, specify a specific type, which can only be a reference type, not a basic type, such as int
        GenercityClass<Integer, String> genercity = new GenercityClass<>(90,"A");
        int score = genercity.getScore();
        String desc = genercity.getDesc();
        System.out.println("score="+score+",desc="+desc);
    }
}

Obviously, classes using generic definitions can be used to specify the true type represented by <T1, T2> according to different requirements, so that there will be no type conversion, no ClassCastException exceptions, and the compiler will check in advance whether the types match. The following will cause errors:

GenercityClass<Integer, String> genercityClass = new GenercityClass<>();
//Conforms to the specified specific type
genercityClass.setScore(80);
//String values cannot be assigned to variables of type Integer
genercityClass.setScore("A");

Define generic interfaces

Define generic interfaces with the following syntax:

//Define generic interfaces
 Interface interface name <T>{
    Method return value type method name <T>;
}

The following is the definition of a generic interface, as follows:

/**
 * Generic interfaces: Specified generics can only be used in methods
 * @author jzman
 */
public interface GenercityInterface<T> {
    //Generics cannot be used before static properties
//    T a;
    //Using generics in methods
    void start(T t);
}

When using generics in an interface, you can only use generics in the methods of the interface, not on the properties of the interface, because the properties in the Java interface are modified with public static final, and the specific types represented by the generics are determined when using them, and the specific types represented by the generics are not known at compile time.

Define generic methods

Define generic methods with the following syntax:

//Define generic methods
 Modifier <T>Return Value Type Method Name {
    
}

Create a class as follows:

package com.manu.genericity;

public class PersonBean {
    private String name;
    private int age;
    //Omit Getter, Setter, etc.
    //...
}

The following is the definition of a generic method as follows:

/**
 * generic method
 * @author jzman
 */
public class GenercityMethod {
    public static void main(String[] args) {
        PersonBean bean = new PersonBean("tom",10);
        printA("string");
        printA(bean);
        printB(bean);
    }
    //A generic does not specify its superclass, because the type cannot be determined, only its information can be accessed
    public static <T> void printA(T t) {
        System.out.println(t);
    }
    //A generic specifies a superclass that can modify the entity information it generically represents
    public static <T extends PersonBean> void printB(T t) {
        t.setName("haha");
        System.out.println(t);
    }
}

The output is as follows:

string
PersonBean [name=tom, age=10]
PersonBean [name=haha, age=10]

Because the specific type of the generic method printA is uncertain, its generic information cannot be modified. PritB specifies its superclass, which to some extent modifies the specific type of information represented by the generic.Generics can be defined as whether or not a generic method exists in a method, regardless of whether or not its class is generic.

Generic Inheritance

What about generics when a subclass inherits a parent class? The following subclasses inherit several cases with a generic parent class, as follows:

/**
 * Generic parent
 * @author jzman
 */
public abstract class GenercityEClass<T> {
    T name;
    public abstract void print(T t);
}

/**
 * The subclass is generic and the type is determined when used
 * @author jzman
 * @param <T>
 */
class Child1<T> extends GenercityEClass<T>{
    T t; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(T t) {
        //The attributes of the parent class are determined by the parent class
        T name = this.name;
    }
}

/**
 * Subclass Specifies Specific Type
 * @author jzman
 */
class Child2 extends GenercityEClass<String>{
    Integer t; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(String t) {
        //The attributes of the parent class are determined by the parent class
        String name = this.name;
    }
}

/**
 * Erase of Parent Generics
 * Subclass is generic, parent does not specify type, generic erase uses Object instead
 * @author jzman
 * @param <T>
 */
class Child3<T/*,T1*/> extends GenercityEClass{
    T t;
    String t1; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(Object t) {
        //The attributes of the parent class are determined by the parent class
        Object obj = this.name;
    }
}

/**
 * Generic erase of both child and parent classes
 * @author jzman
 */
class Child4 extends GenercityEClass{
    //Only specific types can be used
    String str; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(Object t) {
        //The attributes of the parent class are determined by the parent class
        Object obj = this.name;
    }
}

It can be concluded that attributes in a parent class are dependent on the parent class, attributes in a subclass are dependent on the subclass, and method overrides when a subclass inherits the parent class are dependent on the parent class. This operation with generics involves generic erasing in inheritance, which is described below.

Generic Erase

In the generic inheritance section, erasing of generics is more important, so take a separate note of the two cases of generic erasing, as follows:

  1. Generic erase when inheriting or implementing (interfaces);
  2. Generic erase for specific use.

When a subclass inherits a parent class, there are two situations in which a generic is erased:

  1. Subclass generic, parent generic erase
  2. Generic erase of both child and parent classes

Here are some of the codes, which are as follows:

/**
 * Erase of Parent Generics
 * Subclass is generic, parent does not specify type, generic erase uses Object instead
 * @author jzman
 * @param <T>
 */
class Child3<T/*,T1*/> extends GenercityEClass{
    T t;
    String t1; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(Object t) {
        //The attributes of the parent class are determined by the parent class
        Object obj = this.name;
    }
}

/**
 * Generic erase of both child and parent classes
 * @author jzman
 */
class Child4 extends GenercityEClass{
    //Only specific types can be used
    String str; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(Object t) {
        //The attributes of the parent class are determined by the parent class
        Object obj = this.name;
    }
}
/**
 * Subclass erase, parent uses generics (error)
 * @author jzman
 *
class Child5 extends GenercityEClass<T>{
    @Override
    public void print(T t) {
        
    }
}
 */

Note that parent generics cannot be used, and child generics can only be erased if the number of child generics is greater than or equal to the number of parent generics.Classes that implement generic interfaces are similar to inheritance between classes and will not be overlooked.

Here is a generic erase for specific use, as follows:

class Child1<T> extends GenercityEClass<T>{
    T t; //Attributes of subclasses are determined by subclasses
    @Override
    public void print(T t) {
        //The attributes of the parent class are determined by the parent class
        T name = this.name;
    }
    
    public static void main(String[] args) {
        //1. Generic Erase When Used
        Child1 child1 = new Child1();
        Object obj = child1.name;//Property name is erased type Object
        //2. Specify type when using
        Child1<String> child2 = new Child1();
        String name = child2.name;//Property name is the specified type String
    }
}

I'll talk about generic erasing.

Advanced use of generics

The advanced uses of generics are as follows:

  1. Restrict generic available types
  2. Use type wildcards
1. Restrict generic available types

By default, you can instantiate a generic class object using any type, or you can restrict the type of generic class instance with the following syntax:

//Restrict generic available types
class <T extends AnyClass>{
    
}

The AnyClass above can be either a class or an interface, meaning that generic types must inherit the AnyClass class or implement the AnyClass interface, using the extends keyword when restricting types, whether they are classes or interfaces.The following is a case study:

/**
 * Generic Available Type Restrictions
 * @author jzman
 */
public class LimitGenercityClass<T extends List> {
    public static void main(String[] args) {
        // T extends:<upper bound, T can be a subclass of the upper bound or itself
        LimitGenercityClass<ArrayList<String>> limitClass1 = new LimitGenercityClass<>();
        LimitGenercityClass<LinkedList<String>> limitClass2 = new LimitGenercityClass<>();
        //HashMap does not implement the List interface, so HashMap cannot instantiate the type of a generic class instance
//        LimitGenercityClass<HashMap<String,String>> limitClass3 = new LimitGenercityClass<>();    
    }
}

The above code restricts generic T. Specific generic types must implement the List interface, ArrayList and LinkedList implement the List interface, and HashMap does not implement the List interface, so HashMap cannot instantiate the specific type of the corresponding generic.

Use type wildcards

Type wildcards are provided in the generic mechanism to restrict the type inheritance of a generic class or to implement a class or interface when creating a generic class object. Can they be used?Wildcards, but also can be used to restrict generics using the extends, super keywords, using the type wildcard syntax as follows:

//Use type wildcards
 Generic class name <? Extends AnyClass> a;

Here is the use of type wildcards, as follows:

/**
 * Use Wildcards
 * ? extends AnyClass:Restricting the specific type of a generic can only be a subclass of AnyClass
 * ? super AnyClass:Restricting the specific type of a generic can only be a superclass of AnyClass
 * @author jzman
 */
public class CommonCharGenercityClass<T> {
    public static void main(String[] args) {
        //1. Wildcards are used on type declarations
        CommonCharGenercityClass<? extends List> commA = null;
        //The use of the extends keyword in wildcards restricts generics to be only subclasses of List s
        commA = new CommonCharGenercityClass<ArrayList<String>>();
        commA = new CommonCharGenercityClass<LinkedList<String>>();
//        commA = new CommonCharGenercityClass<HashMap<String>>();
        
        CommonCharGenercityClass<? super List> commB = null;
        //Error, the use of the super keyword in wildcards limits generics to List superclasses, such as Object
//        commB = new CommonCharGenercityClass<ArrayList<String>>();
        commB = new CommonCharGenercityClass<Object>();
        
        List<String> listA = new ArrayList<>();
        listA.add("tom");
        
        List<?> listB = listA;
        //When using wildcards, data can only be retrieved and deleted, data cannot be added, and cannot be called because the specific type is uncertain.
//        listB.add("new");
        listB.remove(0);
        System.out.println(listB);    
    }
    
    //2. Wildcards are used on method parameters
    public static void test(CommonCharGenercityClass<? extends List> list) {
        //...
    }
}

Type wildcards?You can combine the keywords extends and super to restrict the specific type of a generic. The specific type of an extends-restricted generic should be a subclass of the target type. The specific type of a super-restricted generic should be a superclass of the target type. In addition, type wildcards cannot be used on declaring classes.

Generic Action

  1. Check type safety at compile time and find errors ahead of time
  2. Type casts in generics are automatic and implicit, improving code reuse.

Summary: A generic type must be a reference type, not a basic type. There can be more than one generic type, can you use it?Restrict generic types and method parameter types when creating objects, such as down or up restrictions on the specific types of generics using the keywords extends and super. Finally, you can declare generic arrays, but you cannot create instances of generic arrays.

You can choose to follow the WeChat Public Number: jzman-blog to get the latest updates and share your learning!

Keywords: Java JDK

Added by sheac on Sun, 09 Jun 2019 19:24:16 +0300