I. Concepts of Generics
Generics are a new feature in Java SE5. Generics are essentially type parameterized or parameterized types. Without creating new types, the types specified by generics can be used to control the specific restrictions on parameters.
2. Meaning of Generics
General classes and methods can only use specific types: either basic types or custom classes.If you're writing code that can be applied to many types, this stereotyped limitation can be very restrictive to your code.
Before Java introduced generics, it represented mutable objects, usually implemented using Object s, but there was a security risk in type casts.With generics:
- Determine the type during compilation, ensure type safety, what to put and what to take, and don't worry about throwing a ClassCastException exception.
- Enhance readability by explicitly knowing from the coding stage what object types are handled by generic collections, generic methods, and so on.
- Generics incorporate the same type of processing code to increase code reuse and flexibility.
For instance:
public static void method1() { List list = new ArrayList(); List.add(22); List.add("hncboy"); List.add(new Object()); for (Object o : list) { System.out.println(o.getClass()); } }
Before using generics, we can add any type to the set, and the traversal results are converted to Object types, because the specific type stored in the indeterminate set is shown below.
class java.lang.Integer class java.lang.String class java.lang.Object
With generics, you can explicitly specify the type by creating a collection object, determine the type of collection storage during compilation, and the object compiler that stores other types will fail.Traversing through the collection allows explicit String type output directly.
public static void method2() { List<String> list = new ArrayList(); list.add("22"); list.add("hncboy"); //list.add(new Object()); error for (String s : arrayList) { System.out.println(s); } }
3. Generic Representation
Generics can be defined in classes, interfaces, and methods as generic classes, interfaces, and methods.The use of generics needs to be declared first, declaring that symbols can be arbitrary by **<symbols>and that the compiler resolves generics by identifying the letters within angle brackets and angle brackets.Generic types can only be classes, not basic data types.Angle brackets are also fixed and can only be placed after a class name or before a method returns a value **.
General generics have conventional symbols: E stands for Element, <E>is usually used in collections; T stands for Type, <T > is usually used to represent classes; K stands for Key, V stands for Value, <K, V>is usually used for the representation of key-value pairs; and? Stands for generic wildcards.
Generic expressions are as follows:
- Common Symbol <T>
- Boundless wildcard <?>
- Upper bound wildcard <? Extends E>Parent is E
- The lower bound wildcard <? Super E>is the parent of E
4. Use of generics
4.1 Generic Class
Defining a generic type after a class name allows users to pass in different types of classes depending on the situation.Generics defined on classes can be used directly in instance methods and do not need to be defined, but generics on static methods need to be declared on static methods and cannot be used directly.For instance:
public class Test<T> { private T data; public T getData() { return data; } /** This writing is incorrect, indicating that T is undefined */ /*public static T get() { return null; }*/ /** Correctly written, T on this method and T on class are identical, but they are two representations, which can be identical without affecting each other */ public static <T> T get() { return null; } public void setData(T data) { this.data = data; } }
4.2 Generic Methods
A generic method is a specific generic type specified when a method is called.Although generics defined on classes can be used directly in instance methods, this method is not generic.For example, the get method is generic and the program compiles and runs because each element in angle brackets refers to an unknown type and can be any symbol. String in angle brackets is not a java.lang.String type, but a generic identifier <String>, and the first passed in is an Integer type, so the String identifier also refers to the Integer type, and the return value is of course an Integer type.However, this generic symbol should and should not be used in practice.
public class Test { public static <String, T, Hncboy> String get(String string, Hncboy hncboy) { return string; } public static void main(String[] args) { Integer first = 666; Double second = 888.0; Integer result = get(first, second); System.out.println(result); } }
4.3 Generic Wildcards
? is a generic, unqualified wildcard that means the type is unknown and can match any class without being declared.The wildcard is read-only, cannot be written, and does not operate on the return value.You can also use generic generics to identify where unqualified wildcards appear, but using wildcards is simpler.For instance:
Tes1() is a wildcard that outputs each element of a collection. Tes2() and test1() do the same thing, but replace the wildcard with <T>; test3() demonstrates that the collection writes with wildcards and finds compiler errors. Neither int nor String is of the? Type. Of course, no collection will be included, because all classes have null elements, it can be placedEnter the collection.For example, it is not possible for the main function to pass List <Double> and want to add a String to the collection; test4() is also written incorrectly,? Is not sure, the return value cannot be returned; test5() is used to compare List <Object> with List <?>, where calling test5(list) in the main function fails, showing java: incompatible type: java.util.List <java.lang.InteGer>cannot be converted to java.util.List<java.lang.Object> because List<Integer>is not a subclass of List<Object>.
public class Test { public static void test1(List<?> list) { for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } public static <T> void test2(List<T> list) { for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } public static void test3(List<?> list) { //list.add(1); capture of ? //list.add("1"); capture of ? list.add(null); } /*public static ? test4(List<?> list) { return null; }*/ public static void test5(List<Object> list) { for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); test1(list); test2(list); //test5(list); } }
The upper and lower boundaries of a generic <? Extend T> and <? Super T> can be achieved by using generic wildcards. The following illustrations show the upper and lower boundaries of a generic using the Number class and its subclasses. The diagram of the Number class is shown below.
<? Extends Number > denotes a subclass of type Number or Number, <? Super Integer > denotes a parent of type Integer or Integer. For example, the method1 method test is an upper bounding Number. Since the generics of arrayList1 and arrayList2 are both Number or their subclasses, insertion can succeed, whereas the type String of arrayList3 is unrelated to Number, so codingTranslation error.The method2 method tests the lower bound Integer. Since arrayList4, arrayList5, and arrayList7 types of Integer, Object, and Number are all parent classes of Integer, the insertion succeeds, while arrayList7 types of Double fail.
public class Generic { public static void main(String[] args) { ArrayList<Integer> arrayList1 = new ArrayList<>(); ArrayList<Number> arrayList2 = new ArrayList<>(); ArrayList<String> arrayList3 = new ArrayList<>(); method1(arrayList1); method1(arrayList2); //method1(arrayList3); ArrayList<Integer> arrayList4 = new ArrayList<>(); ArrayList<Object> arrayList5 = new ArrayList<>(); ArrayList<Number> arrayList6 = new ArrayList<>(); ArrayList<Double> arrayList7 = new ArrayList<>(); method2(arrayList4); method2(arrayList5); method2(arrayList6); //method2(arrayList7) } public static void method1(ArrayList<? extends Number> arrayList) { } public static void method2(ArrayList<? super Integer> arrayList) { } }
4.4 Generic Interface
A generic interface is a generic defined on an interface that needs to be declared when a class of undetermined type implements the interface.For instance:
public interface CalcGeneric<T> { T add(T num1, T num2); } public class CalculatorGeneric<T> implements CalcGeneric<T> { @Override public T add(T num1, T num2) { return null; } }
4.5 Generic Array
Arrays support covariance. What is covariance of arrays?For example, in this code, arrays support defining arrays as one, because Integer is a subclass of Number and an Integer object is a Number object, so an Integer array is also a Number array, which is the covariance of arrays.Although this writing can pass at compile time, the array actually stores Integer objects, and if a Double object is added, an ArrayStoreException exception is thrown at run time, which is a flaw in the design.Definition array compilation error shown in mode 3, code indicated in mode 4 is correct.Generics are immutable and do not have built-in covariant types. When using generics, type information is erased by the type at compile time, so generics move this error detection to the compiler.One of the design purposes of generics is to ensure type safety so that runtime errors can be found at compile time, so generics do not support covariance, and the line of code shown in 5 has compilation errors.
public class Test { public static void main(String[] args) { Number[] numbers = new Integer[10]; // 1 // java.lang.ArrayStoreException: java.lang.Double numbers[0] = new Double(1); // 2 //List<String>[] list = new ArrayList<String>[10]; // 3 List<String>[] list2 = new ArrayList[10]; // 4 //List<Number> list3 = new ArrayList<Integer>(); // 5 } }
4.6 Generic Erase
Within a generic, no information can be obtained about the generic parameter types, which are valid only at the compilation stage. Generic types are logically considered to be multiple different types, but they are all essentially the same type.Since generics only appear after JDK5, non-generic class libraries prior to JDK5 need to be handled.The core motivation for erasing is that it allows generalized clients to be implemented with nongeneralized class libraries and vice versa, often referred to as "migration compatibility".
Cost: Generics cannot be used in operations that explicitly refer to runtime types, such as transitions, instanceof operations, and new expressions, because all information about the parametric type is lost.Whenever you write code for this class, remind yourself that he is just an Object.The catch statement cannot catch an exception of a generic type.
For example, the run output of this string of code is so you can see that generics erase types during run time.
class java.util.ArrayList class java.util.ArrayList true
public static void method1() { List<Integer> integerArrayList = new ArrayList(); List<String> stringArrayList = new ArrayList(); System.out.println(integerArrayList.getClass()); System.out.println(stringArrayList.getClass()); System.out.println(integerArrayList.getClass() == stringArrayList.getClass()); }
When you compile the Java code above into byte code, you can also see that both collections are java/util/ArrayList s
public static method1()V L0 LINENUMBER 14 L0 NEW java/util/ArrayList DUP INVOKESPECIAL java/util/ArrayList.<init> ()V ASTORE 0 L1 LINENUMBER 15 L1 NEW java/util/ArrayList DUP INVOKESPECIAL java/util/ArrayList.<init> ()V ASTORE 1
Because of the type erase relationship during runtime, you can modify the classes that a collection can add by reflecting during runtime, but querying the collection after adding throws a ClassCastException exception with the following code.
public static void method4() throws Exception { ArrayList<String> stringArrayList = new ArrayList<>(); stringArrayList.add("hnc"); stringArrayList.add("boy"); System.out.println("Length before:" + stringArrayList.size()); // Add elements by reflection Class<?> clazz = stringArrayList.getClass(); Method method = clazz.getDeclaredMethod("add", Object.class); method.invoke(stringArrayList, 60); System.out.println("After length:" + stringArrayList.size()); // Save or Integer Type // java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String for (int i = 0; i < stringArrayList.size(); i++) { System.out.println(stringArrayList.get(i).getClass()); } }
V. Summary
Generics are still used a lot in normal learning.
- Arrays do not support generics
- A generic type cannot be a base data type
- Generics are valid only at compile time
Synchronize articles to public numbers and Github Contact the author if you have questions.