Fundamentals of Java: XIV. Generics

Posted by harnacks on Sat, 15 Jan 2022 18:20:13 +0100

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

  1. A generic class may have multiple parameters. In this case, multiple parameters should be placed together in angle brackets. For example: < E1, E2, E3 >
  2. The constructor of the generic class is as follows: public GenericClass() {}. The following is an error: public GenericClass() {}
  3. After instantiation, the structure of the original generic location must be consistent with the specified generic type.
  4. 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.
  5. 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.
  6. If the generic structure is an interface or abstract class, you cannot create an object of the generic class.
  7. jdk1.7. Simplified operation of generics: ArrayList flist = new ArrayList < > ();
  8. Basic data types cannot be used in the specification of generic types, but can be replaced by wrapper classes.
  9. 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.
  10. 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);
    }
}

Topics: Java