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
- 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).
- 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
- Generics can be applied to entire classes, such as the various container classes we see in Java
- 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…