This is the first article I participated in beginners’ introduction

1. Introduction to generics

Generics were introduced from Java1.5. The so-called generics can be understood as parameterized types, that is, types are passed into generic classes or generic methods as parameters. The term generic means “applicable to many, many types”.

1.1 Benefits of generics

Generics make it possible to write code that can be reused by objects of many different types.

Program code written using generics is more secure and readable than code that uses Object variables haphazard and then casts them. Generics are especially useful for collection classes; ArrayList, for example, is a ubiquitous collection.

Generic classes can be thought of as factories for ordinary classes.

  • Before using generics
package com.corejava.genericprogramming; public class ArrayList{ private Object[] elementData; . public Object get(int i ){... } public void add(Object o){... }}Copy the code

There are two problems with this approach.

  1. A cast must be cast when obtaining a value. Prone to type conversion errors.
 ArrayList files = new ArrayList();
 String filename = (String) files.get(0);
Copy the code
  1. You can add objects of any type to an arraylist.
  • After using generics
ArrayList<String> files = new ArrayList<String>(); After JavaSE 7, constructors can omit generic types. ArrayList<String> files = new ArrayList<>();Copy the code

When get is called, no casting is required. The compiler knows that the return value type is String, not Object.

String filename = files.get(0);
Copy the code

1.2 Generic classes

Classes that have one or more type variables are called generic classes.

Below is a generic class.

package com.corejava.genericprogramming; public class Pair<T> { private T first; private T second; public Pair(T first, T second){ this.first = first; this.second = second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public T getSecond() { return second; } public void setSecond(T second) { this.second = second; }}Copy the code

As you can see from the previous code, the type variable is in Angle brackets <> after the class name.

Multiple type variables can be introduced.

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

In the Java library, E represents the element type of the collection, K and V represent keywords and values, and T or U or S represent any type.

1.3 Generic methods

Generic methods can be defined in ordinary or generic classes.

Note that the type variable is placed after the modifier and before the return type.

package com.corejava.genericprogramming; Public class ArrayAlg {// Public static <T> T getMiddle(T... a) { return a[a.length / 2]; } public static void main(String[] args) { //System.out.println(ArrayAlg.<String>getMiddle("Matthew","Xu","CoreJava")); // In general, you can omit the <String> type parameter. // The compiler has enough information to infer the method being called. System.out.println(ArrayAlg.getMiddle("Matthew","Xu","CoreJava")); }}Copy the code

1.4 Generic Interfaces

Define a generic interface as follows.

package com.corejava.genericprogramming;

public interface IGeneric<T> {
    public T test();
}
Copy the code

When no generic arguments are passed to the generic interface

package com.corejava.genericprogramming; public class TestGeneric<T> implements IGeneric<T>{ @Override public T test() { return null; }}Copy the code

When a generic interface passes a generic argument

package com.corejava.genericprogramming; public class TestGeneric implements IGeneric<String>{ @Override public String test() { return null; }}Copy the code

1.5 Qualification of type variables

Sometimes classes or methods need to constrain type variables. Here is an example of calculating the smallest element.

package com.corejava.genericprogramming; public class ArrayAlg { public static <T> T getMin(T[] a) { if( a == null || a.length == 0) return null; T min = a[0]; for (T t : a) { if(min.compareTo(t) > 0) min = t; } return min; }}Copy the code

There is a problem here. T is of any type, but there is no guarantee that T contains a compareTo method.

The solution is to qualify T to implement the Comparable interface.

public static <T extends Comparable> T getMin(T[] a){... }Copy the code

A type variable or wildcard can have more than one qualification.

Whether you qualify an interface or a class, use extends only to connect.

The keyword extends was chosen to be closer to the concept of subclasses.

Qualified types are separated by &, while commas are used to separate type variables.

The qualified type of a type variable can have more than one interface, but at most one class.

If a class is required as a qualifier, it must be the first in the qualifier list.

T extends Comparable & Serializable
Copy the code

1.6 Generic code and virtual machines

Note that the virtual machine has no objects of generic type — all objects belong to ordinary classes.

1.6.1 Type Erasure

The primitive type of a generic type is the name of the generic type after the type parameter is removed.

Erase type variables and replace them with qualified types.

If the type is not qualified, use Object.

For example, the primitive type of Pair<T> is shown below.

package com.corejava.genericprogramming; public class Pair { private Object first; private Object second; public Pair(Object first, Object second){ this.first = first; this.second = second; } public Object getFirst() { return first; } public void setFirst(Object first) { this.first = first; } public Object getSecond() { return second; } public void setSecond(Object second) { this.second = second; }}Copy the code

If a generic type contains a qualified type variable, the original type can be replaced with the first qualified type variable. If not, replace with Object.

Code examples:

package com.corejava.genericprogramming; import java.io.Serializable; public class Interval <T extends Comparable & Serializable> implements Serializable{ private T lower; private T upper; public Interval(T first, T second) { if(first.compareTo(second) <= 0) { lower = first; upper = second; }else { lower = second; upper = first; }}}Copy the code

Original type:

package com.corejava.genericprogramming; import java.io.Serializable; public class Interval implements Serializable{ private Comparable lower; private Comparable upper; public Interval(Comparable first, Comparable second) { if(first.compareTo(second) <= 0) { lower = first; upper = second; }else { lower = second; upper = first; }}}Copy the code

2. Limitations and limitations of generics

2.1 Type parameters cannot be instantiated using primitive types

Take the previous Pair class, which had only pairs, but no pairs.

The reason:

After erasure, the Pair class contains fields of the Object class, which cannot store double values.

Even after erasing, why can’t Object store a double?

Double is automatically boxed into double, and double is an Object type that can be stored by Object.

2.2 Runtime type queries apply only to primitive types

Look at the following two pieces of code.

package com.corejava.genericprogramming; public class Generic<T> { private T first; private T second; public Generic(T first, T second) { super(); this.first = first; this.second = second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public T getSecond() { return second; } public void setSecond(T second) { this.second = second; }}Copy the code
package com.corejava.genericprogramming; import org.junit.jupiter.api.Test; class GenericTest { @Test void test() { Generic<String> genericStr = new Generic<>("first", "second"); //error:Cannot perform instanceof check against parameterized type Generic<String>. //Use the form Generic<? > instead since further generic type information will be erased at runtime //System.out.println(genericStr instanceof Generic<String>); //error:Cannot perform instanceof check against parameterized type Generic<String>. //Use the form Generic<? > instead since further generic type information will be erased at runtime //System.out.println(genericStr instanceof Generic<T>); // Output :true system.out.println (genericStr instanceof Generic); / / output: class com. Corejava. Genericprogramming. The Generic System. Out. The println (genericStr. GetClass ()); }}Copy the code

Thus, if you want to query whether an object belongs to a generic type, using instanceof will result in a compiler error.

The getClass method returns a primitive type.

2.3 Cannot create arrays of parameterized types

An array of parameterized types cannot be instantiated

package com.corejava.genericprogramming; import org.junit.jupiter.api.Test; Class GenericTest {@test void Test () {class GenericTest {@test void Test () { Cannot create a generic array of Generic<String> Generic<String>[] array = new Generic<String>[10]; // After type erasure, the array type is Generic[]. // It can be converted to Object[]. Object[] objarray = array; // The array remembers its element type, and an error should be reported when passing elements of other types. For generics, however, erasure disables the checking mechanism. // For this reason, arrays of parameterized types are not allowed to be created. objarray[0] = "hello"; }}Copy the code

It should be noted that variables declared as type Generic[] are still legal, but cannot be initialized with new Generic[10].

If you need to collect parameter typed objects, you can only use ArrayList.

2.4 Type variables cannot be instantiated

Cannot use new T(…) Or new T […]. Or a type variable in an expression like T.class. The following constructor is illegal.

    public Generic(){
        first = new T();
        second = new T();
    }
Copy the code

2.5 Generic arrays cannot be constructed

public static <T extends Comparable> T[] minmax(T[] a) {
        //error:
		T[] mm = new T[2];
	}
Copy the code

2.6 Invalid type variables in the static context of generic classes

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

Look at the code:

package com.corejava.genericprogramming; public class Generic<T> { private T first; private T second; public Generic(T first, T second) { super(); this.first = first; this.second = second; } public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public T getSecond() { return second; } public void setSecond(T second) { this.second = second; } public void test(T t) { System.out.println("hello"); } // If T is not declared, the following error message is displayed. //error: Cannot make a static reference to the non-static type T public static <T> void name(T t) { System.out.println("hello"); }}Copy the code

2.7 Instances of generic classes cannot be thrown or caught

You can neither throw nor catch a generic class object.

In fact, it is not even legal for generic classes to extend Throwable.

//The generic class Generic<T> may not subclass java.lang.Throwable public class Generic<T> extends Exception{... }Copy the code

3. Inheritance rules for generic types

Whatever S has to do with T, in general, Pair<E> has nothing to do with Pair<T>.

Look at the following code.

package com.corejava.genericprogramming; import org.junit.jupiter.api.Test; class GenericTest { @Test void test() { Manager ceo = new Manager(); Manager cfo = new Manager(); Employee employee = new Employee(); Generic<Manager> managerGroup = new Generic<>(ceo, cfo); //error:Type mismatch: cannot convert from Generic<Manager> to Generic<Employee> Generic<Employee> employeeGroup = managerGroup; employeeGroup.setFirst(cfo); }}Copy the code

Notice the difference between generics and arrays.

package com.corejava.genericprogramming; import org.junit.jupiter.api.Test; class GenericTest { @Test void test() { Manager ceo = new Manager(); Manager cfo = new Manager(); Employee lowerEmployee = new Employee(); Manager[] managerGroup = new Manager[] {ceo, cfo}; Employee[] employeeGroup = managerGroup; //error: Type mismatch: cannot convert from Employee to Manager managerGroup[0] = lowerEmployee; }}Copy the code

4. Wildcard type

4.1 Wildcard Concepts

In wildcard types, type parameters are allowed to change.

For example, the wildcard type Pair<? Extends Employee> represents any generic Pair type whose type parameter is a subclass of Employee.

Suppose you want to write a method.

package com.corejava.genericprogramming; public class GenericTest { public static void printGroup(Generic<Employee> g) { System.out.println(g.getFirst().getName() + g.getSecond().getName()); }}Copy the code

But this method cannot pass in Generic.

public static void main(String[] args) {
		Manager m1 = new Manager();
		Manager m2 = new Manager();
		m1.setName("mat");
		m2.setName("xu");
		Generic<Manager> gm = new Generic<Manager>(m1, m2);
		//error:The method printGroup(Generic<Employee>) in the type GenericTest is not applicable for the arguments (Generic<Manager>)
		printGroup(gm);
	}
Copy the code

The solution is to use wildcard types.

public static void printGroup(Generic<? extends Employee> g) {... }Copy the code

But I have a question here, why not write this way.

public static void printGroup(Generic<T extends Employee> g) {... }Copy the code

Eclipse gives the following error message:

Incorrect number of arguments for type Generic<T>; it cannot be parameterized with arguments <T, Employee>
Copy the code

In other words, <? Extends Employee> counts one parameter and two. The corresponding Generic class Generic contains only one type parameter, so the latter cannot pass.

5. Conclusion

This article draws on a number of articles and will include ideas and ideas from Java Programming Minds and Effective Java in the future. For now, the main content is from Java Core Technologies, and through writing this blog post, the previously unfamiliar Java generics are now familiar. But it still doesn’t touch on the intricacies. If you need to reprint, please indicate the source! If you have any questions or insights, please share your opinion! Thank you!

Refer to the link

  1. Overview of Generics in Java – this is definitely the most detailed overview of generic methods out there
  2. Java Core Technology Volume I
  3. Java generics
  4. Java Generics FAQs – Frequently Asked Questions
  5. Ideas for Java Programming
  6. “Effective Java”