1. Why generics
1.1. Examples
- Generics: labels
- In the traditional Chinese medicine store, there are labels on the outside of each drawer
- There are many bottles on the supermarket shelves. What is in each bottle and there are labels.
1.2 design background of generics
The collection container class cannot determine what type of objects actually exist in this container in the design phase / declaration phase, so in jdk1 Before 5, the element type can only be designed as Object, jdk1 After 5, use generics to solve it. At this time, except the element type is uncertain, other parts are determined, such as how to save and manage the element. Therefore, the element type is designed as a parameter, which is called genericity. Collection, List and ArrayList are type parameters, that is, generic types.
1.3 other instructions
- The so-called genericity is to allow an identifier to represent the type of an attribute in a class or the return value and parameter type of a method when defining a class or interface. This type parameter will be determined when it is used (for example, inheriting or implementing this interface, declaring variables and creating objects with this type) (that is, passing in the actual type parameter, also known as the type argument).
- From jdk1 After 5, Java introduced the concept of "parameterized type", which allows us to specify the type of collection elements when creating a collection, such as List, which indicates that the List can only store objects of string type.
- JDK1.5 rewrites all interfaces and classes in the collection framework and adds generic support for these interfaces and classes, so that type arguments can be passed in when declaring collection variables and creating collection objects.
1.4. So why should there be generics
- So why do we need generics? Can direct objects also store data?
- Solve the security problem of element storage, such as commodity and drug labels.
- **To solve the problem of type coercion when obtaining data elements, for example, you don't have to identify goods and drugs every time you get them**
Java generics can ensure that ClassCastException exceptions will not be generated at runtime if the program does not issue a warning at compile time. At the same time, the code is more concise and robust.
import org.junit.Test; import java.util.ArrayList; /** * Use of generics * 1.jdk5.0 New features */ public class GenericTest { //Before using generics in a collection: @Test public void test(){ ArrayList list = new ArrayList(); //Requirements: store students' grades list.add(78); list.add(49); list.add(72); list.add(81); list.add(89); //Problem 1: unsafe type // list.add("Tom"); for(Object score : list){ //Problem 2: type conversion exception may occur during forced conversion int stuScore = (Integer)score; System.out.println(stuScore); } } }
2. Use generics in Collections
Note: the type of a generic type must be a class, not a basic data type. Where the basic data type needs to be used, replace it with a wrapper class
2.1 examples
- Collection interface or collection class in jdk5 0 is modified to a structure with generics.
- When instantiating a collection class, you can specify a specific generic type
- After specifying, when defining a class or interface in a collection class or interface, the location where the generic type of the class is used by the internal structure (such as method, constructor, attribute, etc.) is specified as the instantiated generic type.
- For example: add(E e) - > after instantiation: add(Integer e)
- Note: the type of a generic type must be a class, not a basic data type. Where the basic data type needs to be used, replace it with a wrapper class
- If the generic type is not specified when instantiating. The default type is Java Lang. object type.
import org.junit.Test; import java.util.*; public class GenericTest { //Using generics in Collections: take HashMap as an example @Test public void test3(){ // Map<String,Integer> map = new HashMap<String,Integer>(); //jdk7 new feature: type inference Map<String,Integer> map = new HashMap<>(); map.put("Tom",87); map.put("Tone",81); map.put("Jack",64); // map.put(123,"ABC"); //Nesting of generics Set<Map.Entry<String,Integer>> entry = map.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = entry.iterator(); while(iterator.hasNext()){ Map.Entry<String, Integer> e = iterator.next(); String key = e.getKey(); Integer value = e.getValue(); System.out.println(key + "----" + value); } } //Using generics in Collections: take ArrayList as an example @Test public void test2(){ ArrayList<Integer> list = new ArrayList<Integer>(); list.add(78); list.add(49); list.add(72); list.add(81); list.add(89); //When compiling, type checking will be carried out to ensure the safety of data // list.add("Tom"); //Mode 1: // for(Integer score :list){ // //The operation of forced rotation is avoided // int stuScore = score; // // System.out.println(stuScore); // } //Mode 2: Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ int stuScore = iterator.next(); System.out.println(stuScore); } } }
3. Custom generic structure
3.1. Examples of custom generic classes
OrderTest class
/** * Custom generic class * */ public class OrderTest<T> { String orderName; int orderId; //The internal structure of the class can use the generics of the class T orderT; public OrderTest(){ }; public OrderTest(String orderName,int orderId,T orderT){ this.orderName = orderName; this.orderId = orderId; this.orderT = orderT; } //None of the following three methods are generic methods public T getOrderT(){ return orderT; } public void setOrderT(T orderT){ this.orderT = orderT; } @Override public String toString() { return "Order{" + "orderName='" + orderName + '\'' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } //Generic method: the generic structure appears in the method, and the generic parameters have nothing to do with the generic parameters of the class. //In other words, it doesn't matter whether a generic method belongs to a generic class or not. //Generic methods that can be declared static. Reason: generic parameters are determined when the method is called. Not determined when instantiating a class. public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } }
SubOrder class
public class SubOrder extends OrderTest<Integer>{ //SubOrder: is not a generic class }
SubOrder1 class
public class SubOrder1<T> extends OrderTest<T> {//Suborder1 < T >: still generic class }
GenericTest1 class
import org.junit.Test; /** * How to customize generic structure: generic class and generic interface; Generic methods. * * 1.About custom generic classes and generic interfaces: */ public class GenericTest1 { @Test public void test(){ /** * If a generic class is defined and the instantiation does not specify the generic type of the class, the generic type is considered to be Object type * Requirement: if you have defined that the class is generic, it is recommended to specify the generic type of the class when instantiating. */ OrderTest order = new OrderTest(); order.setOrderT(123); order.setOrderT("ABC"); //Suggestion: specify the generic type of the class when instantiating OrderTest<String> order1 = new OrderTest<String>("orderAA",1001,"order:AA"); order1.setOrderT("AA:hello"); } @Test public void test2(){ SubOrder sub1 = new SubOrder(); //Because the subclass indicates the generic type when inheriting the parent class with generics. When instantiating subclass objects, you no longer need to specify generics. sub1.setOrderT(1122); SubOrder1<String> sub2 = new SubOrder1<>(); sub2.setOrderT("order2..."); } }
3.2. Considerations for custom generic classes and generic interfaces
Attention
- A generic class may have multiple parameters. In this case, multiple parameters should be placed together in angle brackets. For example: < E1, E2, E3 >
- The constructor of the generic class is as follows: public GenericClass() {}. The following is an error: public GenericClass() {}
- After instantiation, the structure of the original generic location must be consistent with the specified generic type.
- References of different generics cannot be assigned to each other. Although ArrayList and ArrayList are two types at compile time, only one ArrayList is loaded into the JVM at run time.
- If a generic type is not specified, it will be erased. The types corresponding to the generic type are treated as Object, but they are not equivalent to Object.
Experience: generics should be used all the way. No, not all the way. - If the generic structure is an interface or abstract class, you cannot create an object of the generic class.
- jdk1.7. Simplified operation of generics: ArrayList flist = new ArrayList < > ();
- Basic data types cannot be used in the specification of generic types, but can be replaced by wrapper classes.
- The generic type declared on the class / interface represents a type in this class or interface, and can be used as the type of non static attribute, parameter type of non static method and return value type of non static method. However, you cannot use generics of classes in static methods.
- Exception class cannot be generic
//An exception class cannot be declared as a generic class //public class MyException<T> extends Exception{ //}
Code demonstration
Cannot use new E []. However, you can: E[] elements = (E[])new Object[capacity]; Reference: the ArrayList source code declares: Object[] elementData, not a generic parameter type array.
Person class
public class Person { }
OrderTest class
/** * Custom generic class */ public class OrderTest<T> { String orderName; int orderId; //The internal structure of the class can use the generics of the class T orderT; public OrderTest(){ //Compilation failed // T[] arr = new T[10]; //Compile passed T[] arr = (T[]) new Object[10]; }; public OrderTest(String orderName,int orderId,T orderT){ this.orderName = orderName; this.orderId = orderId; this.orderT = orderT; } public T getOrderT(){ return orderT; } public void setOrderT(T orderT){ this.orderT = orderT; } @Override public String toString() { return "Order{" + "orderName='" + orderName + '\'' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } //Generics of classes cannot be used in static methods. // public static void show(T orderT){ // System.out.println(orderT); // } public void show(){ //Compilation failed // try{ // // // }catch(T t){ // // } } }
GenericTest1 class
import org.junit.Test; import java.util.ArrayList; /** * How to customize generic structure: generic class and generic interface; Generic methods. * * 1.About custom generic classes and generic interfaces: * */ public class GenericTest1 { @Test public void test3(){ ArrayList<String> list1 = null; ArrayList<Integer> list2 = new ArrayList<Integer>(); //References of different generics cannot be assigned to each other. //list1 = list2; Person p1 = null; Person p2 = null; p1 = p2; } }
Using generics in inheritance
The parent class has a generic type, and the child class can choose to keep the generic type or specify the generic type:
- Subclasses do not retain the genericity of the parent class: on-demand implementation
- No type erase
- Specific type
- Subclasses retain the genericity of the parent class: generic subclasses
- remove none
- Partial retention
class Father<T1, T2> {} // Subclasses do not retain the generics of the parent class // 1) No type erase class Son1 extends Father {// Equivalent to class son extends father < object, Object > {} } // 2) Specific type class Son2 extends Father<Integer, String> {} // Subclasses retain the generics of the parent class // 1) Keep all class Son3<T1, T2> extends Father<T1, T2> {} // 2) Partial retention class Son4<T2> extends Father<Integer, T2> {}
Conclusion: the subclass must be a "rich second generation". In addition to specifying or retaining the generics of the parent class, the subclass can also add its own generics.
3.3 examples of custom generic methods
explain
- Method can also be generalized, regardless of whether the class defined in it is a generic class or not. Generic parameters can be defined in generic methods. In this case, the type of parameter is the type of incoming data.
- Format of generic method:
[Access rights] <generic paradigm> Return type method name([Generic identity parameter name]) Exception thrown For example: public static <E> List<E> copyFromArrayToList(E[] arr) throws Exception{ }
Code demonstration
OrderTest class
import java.util.ArrayList; import java.util.List; /** * Custom generic class */ public class OrderTest<T> { /** * Generic method: the generic structure appears in the method, and the generic parameters have nothing to do with the generic parameters of the class. * In other words, it doesn't matter whether a generic method belongs to a generic class or not. * Generic methods that can be declared static. Reason: generic parameters are determined when the method is called. Not determined when instantiating a class. */ public static <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } }
Test class
import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * How to customize generic structure: generic class and generic interface; Generic methods. * * 1.About custom generic classes and generic interfaces: * */ public class GenericTest1 { //Test generic methods @Test public void test4(){ OrderTest<String> order = new OrderTest<>(); Integer[] arr = new Integer[]{1,2,3,4}; //When a generic method is called, it indicates the type of generic parameter. List<Integer> list = order.copyFromArrayToList(arr); System.out.println(list); } }
SubOrder class
import java.util.ArrayList; import java.util.List; public class SubOrder extends OrderTest<Integer>{ //SubOrder: is not a generic class public static <E> List<E> copyFromArrayToList(E[] arr){//Static generic method ArrayList<E> list = new ArrayList<>(); for(E e : arr){ list.add(e); } return list; } }
3.4. Give examples of usage scenarios of generic classes and generic methods
DAO class
import java.util.List; public class DAO<T> { //DAO for common operations of tables //Add a record public void add(T t){ } //Delete a record public boolean remove(int index){ return false; } //Modify a record public void update(int index,T t){ } //Query a record public T getIndex(int index){ return null; } //Query multiple records public List<T> getForList(int index){ return null; } //generic method //Example: how many records are there in the acquisition table? Get the maximum employee induction time? public <E> E getValue(){ return null; } }
Customer class
public class Customer { //This class corresponds to the customers table in the database }
CustomerDAO class
public class CustomerDAO extends DAO<Customer>{//You can only operate on the DAO of a table }
Student class
public class Student { }
StudentDAO class
public class StudentDAO extends DAO<Student> {//You can only operate on the DAO of a table }
DAOTest class
import org.junit.Test; import java.util.List; public class DAOTest { @Test public void test(){ CustomerDAO dao1 = new CustomerDAO(); dao1.add(new Customer()); List<Customer> list = dao1.getForList(10); StudentDAO dao2 = new StudentDAO(); Student student = dao2.getIndex(1); } }
4. Embodiment of generic type in inheritance [wildcard]
import org.junit.Test; import java.util.AbstractList; import java.util.ArrayList; import java.util.List; /** * 1.The embodiment of generics in inheritance * * 2.Use of wildcards * */ public class GenericTest { /** * 1.The embodiment of generics in inheritance * Although class A is the parent of class B, G < a > and G < b > do not have child parent relationship, and they are juxtaposed. * Supplement: Class A is the parent of class B, and a < g > is the parent of class B < g > */ @Test public void test(){ Object obj = null; String str = null; obj = str; Object[] arr1 = null; String[] arr2 = null; arr1 = arr2; //Compilation failed // Date date = new Date(); // str = date; List<Object> list1 = null; List<String> list2 = new ArrayList<String>(); //At this time, the types of list1 and list2 do not have a child parent relationship //Compilation failed // list1 = list2; /** * Counter evidence: * Assume list1 = list2; * list1.add(123);Results in mixing non String data. Error. */ show(list1); show2(list2); } public void show2(List<String> list){ } public void show(List<Object> list){ } @Test public void test2(){ AbstractList<String> list1 = null; List<String> list2 = null; ArrayList<String> list3 = null; list1 = list3; list2 = list3; List<String> list4 = new ArrayList<>(); } }
5. Use of wildcards
explain
-
Use type
Wildcard:?
- For example: List <? >, Map<?,?>
- List<?> It is the parent class of list, list and other generic lists.
-
Read list <? > It is always safe to use the elements in the list of objects, because no matter what the real type of the list is, it contains objects.
-
Not when writing elements in the list. Because we don't know the element type of c, we can't add objects to it.
-
The only exception is null, which is a member of all types.
-
Adding any element to it is not type safe:
- Collection<?> c = new ArrayList(); - c.add(new Object()); // Compile time error because we don't know the element type of c, we can't add objects to it. The add method has the type parameter E as the element type of the collection. Any parameter passed to our subclass add must be of unknown type. Because we don't know what type it is, we can't pass anything in.
-
-
On the other hand, we can call the get() method and use its return value. The return value is an unknown type, but we know that it is always an Object.
Code demonstration
import org.junit.Test; import java.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 1.The embodiment of generics in inheritance * 2.Use of wildcards */ public class GenericTest { /** * 2.Use of wildcards * Wildcard:? * * Class A is the parent class of class B. g < a > and G < b > have no relationship. Their common parent class is g <? > */ @Test public void test3(){ List<Object> list1 = null; List<String> list2 = null; List<?> list = null; list = list1; list = list2; //Compile passed print(list1); print(list2); } public void print(List<?> list){ Iterator<?> iterator = list.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } } }
5.1 requirements for reading and writing data after using wildcards
import org.junit.Test; import java.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 1.The embodiment of generics in inheritance * * 2.Use of wildcards */ public class GenericTest { /** * 2.Use of wildcards * Wildcard:? * * Class A is the parent class of class B. g < a > and G < b > have no relationship. Their common parent class is g <? > */ @Test public void test3(){ List<Object> list1 = null; List<String> list2 = null; List<?> list = null; list = list1; list = list2; //Compile passed // print(list1); // print(list2); List<String> list3 = new ArrayList<>(); list3.add("AA"); list3.add("BB"); list3.add("CC"); list = list3; //Add (write): for list <? > You can't add data to it. //In addition to adding null. // list.add("DD"); // list.add('?'); list.add(null); //Get (read): data can be read. The read data type is Object. Object o = list.get(0); System.out.println(o); } }
5.2 use of restricted wildcards
explain
-
<?>: Allow all generic reference calls
-
Wildcard to specify upper limit
Extensions: when used, the specified type must inherit a class or implement an interface, i.e<=
-
Wildcard to specify lower limit
super: the type specified when using cannot be less than the class of the operation, i.e. >=
-
give an example:
-
<? Extensions Number > (infinitesimal, Number]
Only reference calls with generic Number and Number subclasses are allowed
-
<? Super number > [number, infinity)
Only reference calls with generic Number and Number parent are allowed
-
<? extends Comparable>
Only generic calls are allowed for references to implementation classes that implement the Comparable interface
-
Code demonstration
Person class
public class Person { }
Student class
public class Student extends Person{ }
Test class
import org.junit.Test; import java.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * 1.The embodiment of generics in inheritance * * 2.Use of wildcards */ public class GenericTest { /** * 3.Use of restricted wildcards. * * ? extends A: * G<? extends A> Can be the parent of G < a > and G < b >, where B is the child of A * * ? super A: * G<? super A> Can be the parent of G < a > and G < b >, where B is the parent of A */ @Test public void test4(){ List<? extends Person> list1 = null; List<? super Person> list2 = null; // List<Student> list3 = null; // List<Student> list4 = null; // List<Student> list5 = null; List<Student> list3 = new ArrayList<Student>(); List<Person> list4 = new ArrayList<Person>(); List<Object> list5 = new ArrayList<Object>(); list1 = list3; list1 = list4; // list1 = list5; // list2 = list3; list2 = list4; list2 = list5; //Read data: list1 = list3; Person p = list1.get(0); //Compilation failed //Student s = list1.get(0); list2 = list4; Object obj = list2.get(0); Compilation failed // Person obj = list2.get(0); //Write data: //Compilation failed // list1.add(new Student()); //Compile passed list2.add(new Person()); list2.add(new Student()); } }
6. Generic application examples
6.1. Generic nesting
public static void main(String[] args) { HashMap<String, ArrayList<Citizen>> map= new HashMap<String, ArrayList<Citizen>>(); ArrayList<Citizen> list= new ArrayList<Citizen>(); list.add(new Citizen("Hawick Lau")); list.add(new Citizen("Yang Mi")); list.add(new Citizen("Small glutinous rice")); map.put("Hawick Lau", list); Set<Entry<String, ArrayList<Citizen>>> entrySet= map.entrySet(); Iterator<Entry<String, ArrayList<Citizen>>> iterator= entrySet.iterator(); while(iterator.hasNext()) { Entry<String, ArrayList<Citizen>> entry= iterator.next(); String key= entry.getKey(); ArrayList<Citizen> value= entry.getValue(); System.out.println("a householder:"+ key); System.out.println("member of family:"+ value); } }
6.2 actual cases
interface Info{ // Only subclasses of this interface represent human information } class Contact implements Info{ // Indicates contact information private String address ; // Contact address private String telephone ; // contact information private String zipcode ; // Postal Code public Contact(String address,String telephone,String zipcode){ this.address = address; this.telephone = telephone; this.zipcode = zipcode; } public void setAddress(String address){ this.address = address ; } public void setTelephone(String telephone){ this.telephone = telephone ; } public void setZipcode(String zipcode){ this.zipcode = zipcode; } public String getAddress(){ return this.address ; } public String getTelephone(){ return this.telephone ; } public String getZipcode(){ return this.zipcode; } @Override public String toString() { return "Contact [address=" + address + ", telephone=" + telephone + ", zipcode=" + zipcode + "]"; } } class Introduction implements Info{ private String name ; // full name private String sex ; // Gender private int age ; // Age public Introduction(String name,String sex,int age){ this.name = name; this.sex = sex; this.age = age; } public void setName(String name){ this.name = name ; } public void setSex(String sex){ this.sex = sex ; } public void setAge(int age){ this.age = age ; } public String getName(){ return this.name ; } public String getSex(){ return this.sex ; } public int getAge(){ return this.age ; } @Override public String toString() { return "Introduction [name=" + name + ", sex=" + sex + ", age=" + age + "]"; } } class Person<T extends Info>{ private T info ; public Person(T info){ // Setting information property content through constructor this.info = info; } public void setInfo(T info){ this.info = info ; } public T getInfo(){ return info ; } @Override public String toString() { return "Person [info=" + info + "]"; } } public class GenericPerson{ public static void main(String args[]){ Person<Contact> per = null ; // Declaring a Person object per = new Person<Contact>(new Contact("Beijing","01088888888","102206")) ; System.out.println(per); Person<Introduction> per2 = null ; // Declaring a Person object per2 = new Person<Introduction>(new Introduction("Li Lei","male",24)); System.out.println(per2) ; } }
7. Custom generic class exercise
requirement
Code demonstration
Generic class DAO
import java.util.*; /** * Define a generic class Dao < T >, in which a Map member variable is defined. The key of Map is String type and the value is t type. * * Create the following methods: * public void save(String id,T entity): Save objects of type T into Map member variables * public T get(String id): Get the object corresponding to the id from the map * public void update(String id,T entity): Replace the content in the map where the key is id and change it to an entity object * public List<T> list(): Returns all T objects stored in the map * public void delete(String id): Deletes the specified id object */ public class DAO<T> { private Map<String,T> map = new HashMap<String,T>(); //Save objects of type T into Map member variables public void save(String id,T entity){ map.put(id,entity); } //Get the object corresponding to the id from the map public T get(String id){ return map.get(id); } //Replace the content in the map where the key is id and change it to an entity object public void update(String id,T entity){ if(map.containsKey(id)){ map.put(id,entity); } } //Returns all T objects stored in the map public List<T> list(){ //FALSE: // Collection<T> values = map.values(); // return (List<T>) values; //correct: ArrayList<T> list = new ArrayList<>(); Collection<T> values = map.values(); for(T t : values){ list.add(t); } return list; } //Deletes the specified id object public void delete(String id){ map.remove(id); } }
User class
/** * Define a User class: * This class includes: private member variable (int type), id, age; (String type) name. */ public class User { private int id; private int age; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public User() { } @Override public String toString() { return "User{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (id != user.id) return false; if (age != user.age) return false; return name != null ? name.equals(user.name) : user.name == null; } @Override public int hashCode() { int result = id; result = 31 * result + age; result = 31 * result + (name != null ? name.hashCode() : 0); return result; } }
Test class
import java.util.List; /** * The DAO, get and update classes are called to create the DAO, list and delete objects respectively * Method to manipulate the User object, and use the Junit unit test class to test. */ public class DAOTest { public static void main(String[] args) { DAO<User> dao = new DAO<User>(); dao.save("1001",new User(1001,34,"Jay Chou")); dao.save("1002",new User(1002,20,"Hannah ")); dao.save("1003",new User(1003,25,"Cai Yilin")); dao.update("1003",new User(1003,30,"Fang Wenshan")); dao.delete("1002"); List<User> list = dao.list(); // System.out.println(list); list.forEach(System.out::println); } }