Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

What is a paradigm?

Generic programming is a style or paradigm of programming languages. Generics allow programmers to write code in strongly typed programming languages using types that are specified later and specified as parameters when instantiated. Support for generics varies from programming language to programming language and from compiler to runtime environment.

Definition and purpose of generics

There are two main definitions of generics:

  1. In programming, some types contain type parameters, that is, the parameters of the generic type can only represent the class, not the individual object. (This is the more common definition today)
  2. Classes that contain parameters in program coding. Its arguments can represent classes or objects, and so on. (Most people now call this a template.)

Regardless of which definition is used, the parameters of the generic type must be specified when the generic type is actually used.

Some strongly typed programming languages support generics. The main purpose is to enhance type safety and reduce the number of class conversions, but some generics support only partially.

Generics in Java

The parameters of Java generics can only represent classes, not individual objects. Because the actual types of Java generics’ type parameters are eliminated at compile time, the types of their type parameters cannot be known at run time, and primitive value types cannot be used directly as generic type parameters. Java compilers automatically encode type conversions when they compile generics, so they don’t run any faster with generics.

Java and JVM development have also attempted to solve this problem, as it is often criticized for eliminating generics’ object instance type information at runtime. For example, Java can obtain some generics information through reflection interfaces by adding type derivation assistance information when generating bytecode. By improving the implementation of generics in the JVM to support basic value type generics and direct access to generics information.

Paradigms exist in several forms

The implementation of ordinary code

public class Box {
   private Object object;

   public void set(Object object) { this.object = object; }
   public Object get(a) { returnobject; }}Copy the code

Implementation of the paradigm

public class Box<T> {
    private T t;

    public void set(T t) { this.t = t; }
    public T get(a) { returnt; }}Copy the code

Some common generic type variables:

  • E: Element, mostly used in Java collections framework
  • K: Key
  • N: Number
  • T: Type (Type)
  • V: Value

A stereotype exists in the interface

We can define an ICall interface with a stereotype

public interface ICall<T> {
    T exec(Param param);
}
Copy the code
  1. We can define such an implementation class to implement ICall if we are definingMethodCallClass does not declare a stereotype

MethodCall implements ICall

prompts a compilation error:

Error:(6, 43) Java: not found symbol symbol: class T

public class MethodCall<T> implements ICall<T> {

    @Override
    public T exec(Param param) {
        Object object = new ArrayList<>();
        return null; }}Copy the code
  1. When implementing generic interface classes that pass concrete types, the interface methods should also be modified to implement concrete types. Such as:
public class MethodCall<String> implements ICall<String> {

    @Override
    public String exec(Param param) {
        Object object = new ArrayList<>();
        return null; }}Copy the code

A paradigm exists in a class

The most common JDK Collection classes are List, Set, Collection, etc

public class MethodCall<T> {
    
    public T exec(Param param) {
        return null; }}Copy the code

Note:

  • The type arguments of a generic type must be class types, not base types (Boolean, byte, char, short, int, long, float, double).
  • You cannot use the Instanceof operation on an exact generic type. The following operations are illegal and will cause errors during compilation.
Object object = new ArrayList<>();
if (object instanceof List<String>) {

}
Copy the code

Stereotypes in static methods

public class JsonUtil {

    public static <T> T toJson(String jsonStr, Class<T> clazz) {
        try {
            T t = clazz.newInstance();
            // todo ...
            return t;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null; }}Copy the code

A paradigm in a common method

public class MethodCall<T> {

    public T exec(Param param) {
        return null; }}Copy the code

Generic inheritance and subtypes

Generic inheritance is not supported as

List<Number> list = new ArrayList<>();
list.add(new Integer(1));
list.add(new Double(0.1));
Copy the code

This is not supported if you modify the list

list = new ArryList<Integer>(); // Error compiling
Copy the code

Type inference

Type inference is the ability of the Java compiler to look at each method call and corresponding declarations to determine the type parameters that make the call applicable. The inference algorithm determines the type of the parameter and determines whether the result was assigned or returned, if any. Finally, the inference algorithm tries to find the most specific type to use with all the parameters.

To illustrate this last point, in the following example, the inference determines that the second parameter passed to the pick method is of type Serializable:

static <T> T pick(T a1, T a2) { 
  return a2; 
}

Serializable s = pick("d".new ArrayList<String>());
Copy the code

Instantiate type inference

Such as:

Map<String, String> map = new HashMap<>();
Copy the code

Type inference in the constructor

class<T> MyClass {
  private T t
  public MyClass(T t) {
    this.t = t;
  }
}

MyClass myClass = new MyClass("a");
Copy the code

Type erasure

Generics were introduced into the Java language to provide stricter type checking at compile time and support generic programming. To implement generics, the Java compiler applies type erasure to:

  • If type parameters are unrestricted, replace all type parameters in the generic type with their boundary orobject. Therefore, the resulting bytecode contains only ordinary classes, interfaces, and methods.
  • Type conversions are inserted when necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

Type erasure ensures that no new classes are created for parameterized types; Therefore, generics incur no runtime overhead.

case

  1. Case a
List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
System.out.println(list1.getClass() == list2.getClass());

/ / print true
Copy the code

Reference documentation

Docs.oracle.com/javase/tuto…

Baike.baidu.com/item/%E6%B3…

Docs.oracle.com/javase/tuto…

www.sohu.com/a/245549100…