4.1 generic overview
- Genericity: a new feature introduced in JDK5, it provides compile time type safety monitoring mechanism, which allows illegal types to be detected at compile time. Its essence is parameterized type, that is, the data type operated is specified as a parameter.
When it comes to parameters, the most familiar thing is that when a method is defined, there is a formal parameter. Then when the method is passed, the parameter can be passed.
As the name suggests, it is to parameterize the type from the original specific type, and then pass in the specific type when using / calling.
This parameter type can be used in classes, methods and interfaces, which are called generic classes, generic methods and generic interfaces respectively. - Generic definition format:
(1) < type >: Specifies the format of a type. The type here can be regarded as a formal parameter;
(2) < type 1, type 2... >: specify mu lt iple types of formats separated by commas. The type here can be regarded as a formal parameter;
(3) In the future, the given type can be regarded as an argument, and the type of the argument can only be a reference type. - What does generics do? If we do not use generics for the Collection collection to store strings and traverse:
public static void main(String[] args) { Collection c = new ArrayList(); //When we do not specify the element type in the collection, the type passed in by add() is the Object type by default, because the collection is the reference type by default, and the Object type can represent all reference types. If we pass in an element of type String, it will be transformed upward to type Object. c.add("liubei"); c.add("guanyu"); c.add("zhangfei"); Iterator it = c.iterator(); while (it.hasNext()){ Object obj = it.next(); System.out.println(obj); } }
We store a String type. We don't want to use it as an Object type, so we need to forcibly convert it to:
public static void main(String[] args) { Collection c = new ArrayList(); c.add("liubei"); c.add("guanyu"); c.add("zhangfei"); Iterator it = c.iterator(); while (it.hasNext()){ String s = (String) it.next(); System.out.println(s); } }
However, if we use all elements as String types and pass in an element that is not of String type at a certain moment, an error will be reported:
public static void main(String[] args) { Collection c = new ArrayList(); c.add("liubei"); c.add("guanyu"); c.add("zhangfei"); c.add(100);//The storage is of Integer type, and Integer cannot be forcibly converted to String type, so an error is reported. When we use it, I may think that we only store String types, so we forcibly turn it, and then there is a problem. In other words, if we do not use generics, the program implies the possibility of type conversion exceptions. Iterator it = c.iterator(); while (it.hasNext()){ String s = (String) it.next();//ClassCastException System.out.println(s); } }
With generics, the program will directly report an error when the type of the added element does not conform to the type specified by generics, that is, the problem of the runtime is advanced to the compilation period, and the iterator can also specify the element type through generics to avoid forced type conversion:
public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("liubei"); c.add("guanyu"); c.add("zhangfei"); //c.add(100);// Report red Iterator<String> it = c.iterator(); while (it.hasNext()){ String s = (String) it.next(); System.out.println(s); } }
To sum up, the benefits of generics are as follows:
(1) Advance the run-time problems to the compilation time;
(2) Cast is avoided.
4.2 generic classes
- Definition format of generic class:
(1) Modifier class class name < type > {}
(2) Example: public classGeneric {}, where T can be written as any identifier. Common parameters such as T, E, K and V are often used to represent generics.
public class Generic<T> { private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } }
public class GenericDemo { public static void main(String[] args) { Generic<String> g1 = new Generic<>(); g1.setT("liubei"); System.out.println(g1.getT()); Generic<Integer> g2 = new Generic<>(); g2.setT(100); System.out.println(g2.getT()); } }
4.3 generic methods
- Method overloading without generics:
public class Generic<T> { public void show(String s){ System.out.println(s); } public void show(Integer i){ System.out.println(i); } public void show(Boolean b){ System.out.println(b); } }
public static void main(String[] args) { Generic g = new Generic(); g.show("liubei"); g.show(30); g.show(true); g.show(213.13); }
- Improved by using generic classes:
public class Generic<T> { public void show(T t){ System.out.println(t); } }
public static void main(String[] args) { Generic<String> g1 = new Generic<>(); g1.show("liubei"); Generic<Integer> g2 = new Generic<>(); g2.show(30); Generic<Boolean> g3 = new Generic<>(); g3.show(true); }
- Definition format of generic method:
(1) Modifier < type > return value type method name (type variable name) {};
(2) Example: public void show (T) {}. - Improved by using generic methods:
public class Generic { //At the moment of calling the method, the type is really determined according to the type of the incoming parameter public<T> void show(T t){ System.out.println(t); } }
public static void main(String[] args) { Generic g1 = new Generic(); g1.show("liubei"); g1.show(20); g1.show(false); }
4.4 generic interfaces
- Definition format of generic interface:
(1) Format: modifier interface interface name < type > {}
(2) Example: public interface Generic {}
public interface Generic<T> { void show(T t); }
public class GenericImpl<T> implements Generic<T>{ @Override public void show(T t) { System.out.println(t); } }
public class GenericDemo { public static void main(String[] args) { Generic<String> g1 = new GenericImpl<>(); g1.show("liubei"); Generic<Integer> g2 = new GenericImpl<>(); g2.show(20); } }
4.5 type wildcards
- To represent the parent classes of various generic lists, you can use the type wildcard:
(1) Type wildcard: <? >;
(2)List<?>: Represents a list whose element type is unknown. Its elements can match any type (that is, any reference data type can be specified when new);
(3) This List with wildcards only indicates that it is the parent of various generic lists, and cannot add elements to it. - If we don't want List <? > Is the parent class of any generic List. You only want it to represent the parent class of a generic List. You can use the upper limit of type wildcard:
(1) Upper limit of type wildcard = = <? Extensions type >;
(2)List<? Extensions Number >: the type it represents is Number or its subtype = =. - In addition to specifying the upper limit of type wildcards, we can also specify the lower limit of type wildcards:
(1) Lower limit of type wildcard: <? Super type >;
(2)List<? Super Number >: the type it represents is Number or its parent type.
public static void main(String[] args) { //First, we need to know that the parent class of Integer is Number and the parent class of Number is Object //Type wildcard: <? > List<?> list1 = new ArrayList<Object>(); List<?> list2 = new ArrayList<Number>(); List<?> list3 = new ArrayList<Integer>(); //Upper limit of type wildcard: <? Extensions type > //List<? extends Number> list4 = new ArrayList<Object>();// report errors List<? extends Number> list5 = new ArrayList<Number>(); List<? extends Number> list6 = new ArrayList<Integer>(); //Type wildcard lower limit: <? Super type > List<? super Number> list7 = new ArrayList<Object>(); List<? super Number> list8 = new ArrayList<Number>(); //List<? super Number> list9 = new ArrayList<Integer>();// report errors }
4.6 variable parameters
- Variable parameters are also called variable number of parameters. If they are used as formal parameters of a method, the number of method parameters is variable:
(1) Format: modifier return value type method name (data type... Variable name) {};
(2) Example: public static int sum(int... a) {}.
public class ArgsDemo { public static void main(String[] args) { System.out.println(sum(10,20)); System.out.println(sum(10,20,30)); System.out.println(sum(10,20,30,40)); System.out.println(sum(10,20,30,40,50)); System.out.println(sum(10,20,30,40,50,60)); System.out.println(sum(10,20,30,40,50,60,70)); System.out.println(sum(10,20,30,40,50,60,70,80)); System.out.println(sum(10,20,30,40,50,60,70,80,90)); } public static int sum(int...a){ int sum = 0; for (int i : a){ sum += i; } return sum; } }
- Precautions for variable parameters:
(1) The variable here is actually an array;
(2) If a method has multiple parameters, including variable parameters, the variable parameters should be placed last.
4.7 use of variable parameters
- There is a static method in the Arrays tool class:
(1) public static List asList(T... a): returns a fixed size list supported by the specified array;
(2) The returned collection cannot be added or deleted, but can be modified. - There is a static method in the List interface (after JDK9):
(1) public static List of(E... elements): returns an immutable list containing any number of elements;
(2) The returned collection cannot be added, deleted or modified. - There is a static method in the Set interface (after JDK9):
(1) public static Set of(E... elements): returns an immutable set containing any number of elements;
(2) The returned collection cannot be added or deleted. There is no modified method.
public static void main(String[] args) { List<String> list = Arrays.asList("liubei","guanyu","zhangfei"); //list.add("zhugeliang");//UnsupportedOperationException //list.remove("liubei");//UnsupportedOperationException list.set(1,"zhugeliang"); System.out.println(list);//[liubei, zhugeliang, zhangfei] //List<String> list2 = list.of("liubei","guanyu","zhangfei"); //list2.add("zhugeliang");//UnsupportedOperationException //list2.remove("liubei");//UnsupportedOperationException //list2.set(1,"zhugeliang");//UnsupportedOperationException //System.out.println(list2); //Set<String> set = Set.of("liubei","guanyu","zhangfei"); //set.add("zhugeliang");//UnsupportedOperationException //set.remove("liubei");//UnsupportedOperationException //System.out.println(set); }