Abstract

This article is based on chapter 8 of Java Core Technology Volume 1. Some of the articles are excerpted from the book as personal notes. The article will not be too deep, hope the reader reference is good.

Why use generic programming

Generic programming means that you write code that can be reused by many different types of objects.

Benefits of type parameters

Before the advent of generic classes, the ArrayList class maintained only an array of Object references:

public class ArrayList {
   private Object[] elementData; // It is used to store data
   public Object get(int i) {....}public void add(Object o) {....}... }Copy the code

The problem

1. A cast must be performed when obtaining a value. 2. You can add objects of any class to the arraylist, and if the array is not of the same type, it will be an error to force the result of get to be typed.

Generics provide a better solution: type parameters:

ArrayList<String> array = new ArrayList<String>():
Copy the code

Using the type parameter information, we can keep the type uniform when we add data, and we don’t need to cast when we call get because we define the type at initialization and the compiler recognizes the type of the returned value and converts it for us.

Define a simple generic class

public class Pair<T> {
    private T num;

    public Pair(T num) { this.num = num; }
    public T getNum(a) { return num; }
    public void setNum(T num) { this.num = num; }}Copy the code

We can see that after the Pair class name, we have added a type variable of the generic class, and there can be multiple type variables, such as

public class Pair<T.U> {... }Copy the code

If we instantiate the Pair class, for example:

new Pair<String>;
Copy the code

We can then imagine the Pair class as follows:

public class Pair<String> {
    private String num;

    public Pair(String num) { this.num = num; }
    public String getNum(a) { return num; }
    public void setNum(String num) { this.num = num; }}Copy the code

Is it easy? In the Java library, the variable E represents the element type of the collection, K and V represent the key and value types of the table respectively, and T, U, and S represent any type.

Generic method

Define a method with type parameters

    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }
Copy the code

You can see that the type variable (< T >) is placed after the modifier (public static) and before the return type (T). Generic methods can be defined in ordinary or generic classes.

Qualification of a type variable

If we need to constrain a type variable, for example, the incoming variable must implement the Comparable interface because it needs to call compareTo’s methods. This allows us to qualify variables using the extends keyword.

    public <T extends Comparable> T max(T a) { a.compareTo(...) ; . }Copy the code

Whether a variable needs to be qualified to inherit from a class or implement an interface, it is qualified using the extends keyword.

Generic code and virtual machines

Type erasure

No matter how we define a generic class or method in our code, we provide a corresponding primitive type. The name of the primitive type is the name of the generic class with the type parameters removed. For example, the primitive type of

is Object and the primitive type of

is MyClass. The code looks like this:

public class Pair<T> {
    private T property;

    public Pair(T property) {
        this.property = property; }}Copy the code

After type erasure:

public class Pair<Object> {
    private Object property;

    public Pair(Object property) {
        this.property = property; }}Copy the code

Translate generic expressions

If the return type is erased, the compiler inserts a cast as follows:

Pair<Employee> buddies =.. Employee buddy = buddies.getfirst ();Copy the code

Erasing the return type of getFirst will return Object, but the compiler will automatically help us force the conversion to Employee. So: the compiler divides this method into two instructions:

The call to the original method Pair. GetFirst casts the returned Object type to Employee

Section Summary:

There are no generics in the virtual machine, only ordinary classes and methods. All type parameters are replaced by their qualified types to preserve type safety. If necessary, cast bridge methods are synthesized to preserve polymorphism.

Constraints and Limitations

Type parameters cannot be instantiated with primitive types

You can’t instantiate type parameters with eight basic data types, and you’ve never seen code like ArrayList

. Only the ArrayList < Integer >. The reason is that the basic data types are not Object. So it can only be replaced with their package type.

Runtime type queries apply only to primitive types

All type queries only produce primitive types, because there is no such thing as generic types in the virtual machine. Such as:

	Pair<String> pair = new Pair<String>("johnson");
	if (pair instanceof Pair<String>) {} // Error
	if (pair instanceof Pair<T>) {} // Error
	if (pair instanceof Pair) {} // Pass
Copy the code

Cannot create an array of parameterized types

    Pair<String>[] pairs = new Pair<String>[10]; //error
Copy the code

Why can’t we define it this way? Since pairs are of type Pair[] and can be converted to Object[], ArrayStoreException is thrown if an attempt is made to store an element of another type.

	pairs[0] = 10L; / / thrown exception
Copy the code

In a word, not rigorous. So you can’t create arrays of parameterized types.

Type variables cannot be instantiated

Cannot use new T(…) , new T […]. Or tc lass. Because when the type is erased, T will become Object, and we certainly don’t want to instantiate Object. After Java8, however, we can implement it using the Supplier

interface, which is a functional interface that represents a function with no arguments and a return type of T:

public class Pair<T> {
    private T first;
    private T second;

    private Pair(T first, T second) {
        this.first = first;
        this.second = second;
    }

    public static <T> Pair<T> makePair(Supplier<T> constr) {
        return new Pair<>(constr.get(), constr.get());
    }
    
	public static void main(String[] args) {
        Pair<String> pair = Pair.makePair(String::new); }}Copy the code

A static context type variable in a generic class is invalid

You cannot reference a type variable in a static field or method. Such as:

public class Pair<T> {
    private static T instance; //Error

    public static T getInstance(a) { //Error
        if (instance == null) 
            instance = new Pair<T>();
        returninstance; }}Copy the code

Because a type variable (

) in a class is scoped in an object, not in a class. If you want to use generic methods, you can refer to generic methods in this article

An instance of a generic class cannot be thrown or caught

Objects that cannot throw or catch generic classes, or even extend Throwable, are illegal:

public class Pair<String> extend Exceotion {} //Error
Copy the code
public static <T extends Throwable> void doWork(Class<T> t) {
	try{... }catch (T e) { //Error. }}Copy the code

However, it is possible to use type variables for an exception after it has been thrown (I don’t think I’ve ever seen such code).

public static <T extends Throwable> void doWork(Class<T> t) throw T { //Pass
	try{... }catch (Exception e) {
		throwe; }}Copy the code

Inheritance rules for generic types

For example, the Manager class inherits from the Employee class. But Pair

and Pair

are not related. As in the following code, an error is reported and the delivery failed:

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<Employee> employeePair = managerPair; //Error
Copy the code

Wildcard type

Wildcard concept

Wildcard types allow type parameters to change, using? Identify wildcard types:

Pair<? extends Employee>
Copy the code

If the Pair class is as follows

public class Pair<T> {
    private T object;

    public void setObject(T object) {
        this.object = object; }}Copy the code

Using wildcards solves the problem of inheritance rules for generic types, such as:

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<? extends Employee> employeePair = managerPair; //Pass
        Manager manager = new Manager();
        employeePair.setObject(manager); //Error
Copy the code

Use the
, the compiler only knows that employeePair is a subclass of Employee. It does not know what subclass employeePair is, so the last step employeepair.setobject (Manager) cannot be executed.

Supertype qualification for wildcards

Wildcards have the added ability to specify a supertype qualification, such as:

public class Pair<T> [
	...
	public static void salary(Pair<? super Manager> result) {
        //...
    }
}
Copy the code

This wildcard is for all supertypes of Manager (including Manger), for example:

        Pair<Manager> managerPair = new Pair<Manager>();
        Pair<Employee> employeePair = new Pair<Employee>();

        Pair.salary(managerPair); //Pass
        Pair.salary(employeePair); //Pass

		// If ManagerChild is a Manager subclass
        Pair<ManagerChild> managerChildPair = new Pair<ManagerChild>();
        Pair.salary(managerChildPair); //Error
Copy the code

Unqualified wildcard

Unqualified wildcards, such as Pair

    public static boolean hasNull(Pair
        pair) {
        return pair.getObject() == null;
    }
Copy the code

To tell you the truth, the wildcard made my head dizzy, repeatedly read the article, began to understand slowly, I was too difficult… This is the end of the article, I do not know if you understand, did not understand it may be my skills and article writing ability is still to be improved, friends can also go to see the Java core technology volume 1, this book, feel very good. Recently, I picked up this book and found that the foundation is very important. If the foundation is settled well, it will be easier to start with other technical points and know what it is. Recently, I like this sentence very much: “Great oaks from little acorns grow, do not build a platform on floating sand”.

Personal blog: colablog.cn/

If my article helps you, you can follow my wechat official number and share the article with you as soon as possible