preface

Recently when writing business code, there are a lot of similar logic, the use of generics can be better abstraction, improve code reuse, because the use of generics is less, the development speed is slow, so here is a summary of some basic use of generics

Why generics

  1. Generics implement parameterized types, allowing code to be applied to multiple object types and improving code reuse. In the absence of generics, Object can be used to store objects of any type, but it requires explicit type conversion, which requires the developer to be able to predict the corresponding parameter type. The code is not elegant, and it is prone to security risks (unexpected objects appear).
  2. The introduction of generics improves security by allowing type checking at compile time

Generic types

A generic interface
public interface GenericInterface<T> { List<T> getValue(); } class GenericInterfaceImplement implements GenericInterface<String> { @Override public List<String> getValue() { return Arrays.asList("Hello", "World"); } public static void main(String[] args) { GenericInterfaceImplement genericInterfaceImplement = new GenericInterfaceImplement(); System.out.println(genericInterfaceImplement.getValue()); }}Copy the code

Generic classes, generic methods
  1. Generics can be applied to entire classes, such as the various container classes we see in Java
  2. Even a generic class can contain parameterized methods, that is, the existence of a generic method does not depend on whether the class is generic or not
Public class GenericClass<T> {private T T; public T getT() { return t; } /** * is this a generic method? * * @param t */ public void setT(t t) {this.t = t; } /** * is this a generic method? * * @param e * @param < e > */ static < e > void printMethod(e e) { System.out.println(e); } /** * is this a generic method? * * @param t * @param < t > */ static < t > void printMethodTwo(t t) {system.out.println (t); } @param args @param <E> */ static <E> void printMethodThree(E... args) { for (E e : args) { System.out.println(e.getClass().toString() + ":" + e); } } public static void main(String[] args) { GenericClass<String> genericClassString = new GenericClass<>(); genericClassString.setT("hello world"); System.out.println(" GenericClass: String: "+ GenericClass.gett ()); GenericClass<Long> genericClassLong = new GenericClass<>(); genericClassLong.setT(12L); System.out.println(" genericClassLong: type: "+ GenericClassLong.gett ()); Genericclass.printmethod (" Generic method: Integer Type: "+ integer.class); GenericClass. PrintMethodTwo (" generic methods: type Double: "+ Double. The class). GenericClass.printMethodThree(1L, 2F, 3, "Hello"); }}Copy the code

Generic wildcard

When defining generics, we often use T, K, V, E,? Wait, what do these wildcards mean?

  • T (Type) represents a specific Java Type
  • K, V (Key, Value) are generally used to indicate the type of Key/Value pairs in Java
  • E (Element) is generally used in traversal to indicate the type of the Element
  • ? Represents an indeterminate Java type

These are all code conventions that make your code more readable, but of course you can do things that you don’t want to do, like change T to A, and it doesn’t affect your program

Extend and super upper and lower bounds

: means that the parameterized type must be T or a subclass of T

: indicates that the parameterized type must be T or a superclass of T

Test the

The parent relationship of the class in the code is Person -> Man -> StrongMan

public class Person { @Override public String toString() { return "Person"; } } public class Man extends Person { @Override public String toString() { return "Man"; } } public class StrongMan extends Man { @Override public String toString() { return "StrongMan"; } } public class SuperExtendTest { public static void main(String[] args) { List<Man> manList = new ArrayList<>(); List<Person> personList = new ArrayList<>(); List<StrongMan> strongManList = new ArrayList<>(); test(manList); testTwo(personList); // Compile without testTwo(strongManList); } static void test(List<? extends Person> persons) { persons.forEach(System.out::println); } // Accept arguments that are Man or Man's superclass. Static void testTwo(List<? super Man> mans) { mans.forEach(System.out::println); }}Copy the code

Limitations on the use of generics

There are some limitations to the use of generics, as you can see in this blog post

Blog.csdn.net/hanchao5272…

Generic erasure

Java generics are pseudo-generics, because at compile time, all generic information is erased, and the resulting bytecode contains no generic types, only the original types, which we call generic erasure

What is a primitive type? For example, a List defined in code becomes a List at compile time. The List is the primitive type, and the generic parameter type is not visible to the JVM

Here are two examples of generic erasure

public static void main(String[] args) {
    List<String> stringList = new ArrayList<String>();
    stringList.add("reflect");
    List<Integer> integerList = new ArrayList<Integer>();
    integerList.add(123);
    System.out.println(stringList.getClass() == integerList.getClass());
}
Copy the code

The output

true
Copy the code

The generic types of the two lists are different, but the class information is the same, indicating that only the original types are preserved in the JVM

public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { List<Integer> list = new ArrayList<Integer>(); list.add(1); // list.add("reflect"); String list.getClass().getMethod("add", object.class).invoke(list, "reflect"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }}Copy the code

The output

1
reflect
Copy the code

A List of Integer objects that can be added to a List by reflection is a List of Integer objects that can be added to a List by reflection. It is important to note that in normal development, you should not use this method to store multiple types of objects in a List, because when using this data, type conversion errors will be reported

Reflection on generics

Generics work better with reflection

public class GenericReflectionTest { Map<String, Integer> map; public Map<String, Integer> getMap() { return map; } public void setMap(Map<String, Integer> map) { this.map = map; } public static void main(String[] args) throws NoSuchMethodException { Class clazz = GenericReflectionTest.class; Method method = clazz.getMethod("getMap"); Type genericReturnType = method.getGenericReturnType(); // get the genericReturnType of a method if(genericReturnType instanceof ParameterizedType){ParameterizedType ParameterizedType = ((ParameterizedType) genericReturnType); / / because the return Type of the generic Type may be more than one, so the return back is an array Type [] types = parameterizedType. GetActualTypeArguments (); for (Type type : types){ Class actualClz = ((Class) type); System.out.println(" + actualClz "); SetMethod = clazz.getMethod("setMap", map.class); Type[] genericParameterTypes = setMethod.getGenericParameterTypes(); for (Type genericParameterType: GenericParameterTypes) {System. Out. Println (" genericParameterTypes is: "+ genericParameterType. GetTypeName ()); if(genericParameterType instanceof ParameterizedType){ ParameterizedType parameterizedType = ((ParameterizedType) genericParameterType); System. The out. Println (" ParameterizedType is: "+ ParameterizedType. GetTypeName ()); Type types[] = parameterizedType.getActualTypeArguments(); For (Type Type: types){system.out.println (" + ((Class) Type).getName()); } } } } }Copy the code

The resources

Github.com/byhieg/Java…