Introduction of generics
Different types of elements can be added to the List collection, such as the following
public class demo1 { public static void main(String[] args) { List list = new ArrayList(); list.add("hello"); list.add("java"); list.add(12); Iterator iterator = list.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); String s = (String)obj; System.out.println(s); } } }
This code does not report an error during compilation, but once it is run, it will report ClassCastException: an error of type conversion exception
The reason is that there are both String and Integer elements in the list collection
This will cause a lot of trouble in the process of compiling and operating the collection. At this time, you want the collection to be the same as the array. You can only add elements of a certain type at the beginning
In this way, when adding elements, only elements of defined types can be added
Such a technique is called generics
In general, generics are mainly used in collections
Generics: advance the work of specifying data types to compile time, and specify them when creating objects.
This operation is a bit like passing a type as a parameter, so generics have another name: parameterized types.
Format: < data type >
Note: the data type here can only be reference data type
Benefits of using generics:
- Advance run-time problems to compile time
- Forced type conversion is avoided
- The code program is optimized to eliminate unnecessary warnings
public class demo1 { public static void main(String[] args) { //Collection using generics List<String> list1 = new ArrayList<>(); //The String in < > after ArrayList can be omitted. It used to be new ArrayList < String > (); list1.add("java"); list1.add("hive"); list1.add("flume"); //Generics also need to be added after Iterator Iterator<String> it = list1.iterator(); while(it.hasNext()){ //Casts are avoided String s = it.next(); System.out.println(s); } } }
When the parameter passed in is a class
public class demo2 { public static void main(String[] args) { List<Student> list = new ArrayList<>(); list.add(new Student("zhang",12)); list.add(new Student("zhao",15)); list.add(new Student("zhou",18)); Iterator<Student> iterator = list.iterator(); while(iterator.hasNext()){ Student s = iterator.next(); System.out.println(s.getName()+"---"+s.getAge()); } } }
In fact, when we look up the relevant contents in the api, we should have seen the relevant usage of generics
Here is the expression of generics
Why is there an E in < > instead of explicit String, Integer and other reference data types?
Because E here only represents a parameter type, which is a variable and can refer to any reference data type, which is the data type passed in according to the actual use.
Since this is a variable, it is OK as long as it conforms to the naming rules of the variable. In order to have recognition, E or T is usually used as the content in the brackets
Advanced usage of generics: (wildcard)
Generic wildcard <? >—— Any type, if not specified, is Object and any Java class
< ? Extensions E > -- downward limit, e, classes of the same level as e and their subclasses
< ? Super E > -- upper limit, e, classes at the same level as e and their parent classes
public class demo3 { public static void main(String[] args) { ArrayList<?> arrayList = new ArrayList<>(); //Generic wildcard <? > //Represents any type, which can be Object and any Java class ArrayList<?> objects1 = new ArrayList<Object>(); ArrayList<?> objects2 = new ArrayList<Animal>(); ArrayList<?> objects3 = new ArrayList<Dog>(); //<? Extensions E > downward qualification, e and its subclasses ArrayList<? extends Animal> list1 = new ArrayList<Animal>(); ArrayList<? extends Animal> list2 = new ArrayList<Dog>(); ArrayList<? extends Animal> list3 = new ArrayList<Cat>(); //<? Super E > upper limit, e and its parent classes ArrayList<? super Animal> list11 = new ArrayList<Animal>(); ArrayList<? super Animal> list22 = new ArrayList<Object>(); //Wrong writing ArrayList <? super Animal> list33 = new ArrayList<Dog>(); } }
Generic class
Generic class: define generics on a class
package test.GenericDemo; //T here is a parameter that can refer to any reference data type //The setObj method of this class can pass in String, Integer and other data types public class genericDemo1<T> { private T obj; public void setObj(T obj){ this.obj = obj; } public T getObj(){ return obj; } }
Write a class to use generic classes
package test.GenericDemo; public class genericTest1 { public static void main(String[] args) { //Although we have defined a generic class, we can not use it genericDemo1 g1 = new genericDemo1(); //At this point g1, you can pass in any parameter g1.setObj("hello"); System.out.println(g1.getObj()); //hello g1.setObj(20); System.out.println(g1.getObj()); //20 /* Although the above results are successfully printed, in fact, both hello and 20 here are Object types Try the following statement String s= g1.getObj(); If you write this, an error will be reported because the Object cannot be converted to String type Therefore, if we only need String type, we need to use generics to define it */ genericDemo1<String> g2 = new genericDemo1<>(); g2.setObj("hello"); String s = g2.getObj(); System.out.println(s); //hello, the result is correct } }
generic method
Generic methods: define generics on methods
Format: public < generic type > return type method name (generic type variable name)
Let's first look at what it would be like to write a method that passes in multiple data types without using generics
public class genericDemo2 { 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); } }
Write a class to test
public class genericTest2 { public static void main(String[] args) { genericDemo2 g1 = new genericDemo2(); g1.show("hello"); //hello g1.show(12); //12 g1.show(true); /true } }
The result is correct, but if we need to pass in a data type, we need to write a corresponding method, which is too troublesome
At this point, generic methods are used
Format: public < generic type > return type method name (generic type variable name)
package test.GenericDemo; //generic method public class genericDemo2 { public <T> void show(T t){ System.out.println(t); } }
Write a test class
package test.GenericDemo; public class genericTest2 { public static void main(String[] args) { genericDemo2 g2 = new genericDemo2(); g2.show("hello"); //hello g2.show(12); //12 g2.show(12.23); //12.23 g2.show(true); //true } }
These corresponding results can also be printed, but a lot of code is saved
generic interface
Define generics on interfaces
Format: public interface interface name < generic type 1... >
Interface
public interface genericDemo3<T> { public abstract void show(T t); }
Classes that implement interfaces
public class genericImpl<T> implements genericDemo3<T> { @Override public void show(T t) { System.out.println(t); } }
Specific test classes
package test.GenericDemo; public class genericTest3 { public static void main(String[] args) { genericImpl<String> g1 = new genericImpl(); g1.show("hello"); //hello genericImpl<Integer> g2 = new genericImpl<>(); g2.show(12); //12 } }