Java advanced generics, custom generics, and the use of wildcards

Generics and File

1. Why are there generics?

New features of jdk5.0

1.1. What are generics?

Generic: label ;Generic

Example:

  • Traditional Chinese Medicine Store: Labels on the outside of each drawer
  • There are many bottles on the supermarket shopping shelf, what is in each bottle and there are labels

1.2. Generic design background

The collection container class cannot determine what type of object is actually stored in the container during the design stage/declaration stage, so before JDK1.5, the element type could only be designed as Object. After JDK1.5, generics are used to solve the problem. Because at this time, except for the type of the element, other parts are determined, such as how to save and manage the element. Therefore, the type of the element is designed as a parameter at this time. This type parameter is called a generic . Collection, List, ArrayList are type parameters, that is, generics.

1.3. The concept of generics

The so-called generics allow the type of an attribute in the class to be identified or the return value and parameter type of a method to be used when defining a class or interface. This type parameter will be determined when using it (for example, inheriting or implementing this interface, declaring a variable with this type, creating an object) (that is, passing in the actual type parameter, also called a type argument)

2. Use generics in collections

Using generics in collections:

Summarize:

  1. Collection interfaces or collection classes are modified to have generic structures in jdk5.0.

  2. When instantiating a collection class, you can specify a specific generic structure

  3. After specifying, when defining a class or interface in a collection class or interface, the internal structure (such as: methods, constructors, properties, etc.)

    For example: add(E e) —> after instantiation: add(Integer e)

  4. Note: The generic type must be a class, not a basic data type. Where basic data types need to be used, replace them with wrapper classes.

  5. If the generic type is not specified when instantiating. The default type is java.lang.Object type.

Example 1:

/**
 * 在集合中使用泛型的情况::以 HashMap 为例
 */
@Test
public void test3(){
    
    
    HashMap<String, Integer> map = new HashMap<>();
    map.put("Jack", 123);
    map.put("Tom", 156);
    map.put("Book", 189);
    map.put("Abby", 145);

    Set<Map.Entry<String, Integer>> entry = map.entrySet();
    Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();

    while (iterator.hasNext()){
    
    
        Map.Entry<String, Integer> entry1 = iterator.next();
        String key = entry1.getKey();
        Integer value = entry1.getValue();
        System.out.println(key + "-->" + value);
    }
}

Example 2:

/**
     * 在集合中使用泛型的情况:以 ArrayList为例
     */
    @Test
    public void test2(){
    
    
        ArrayList<Integer> list = new ArrayList<Integer>();
        //存放学生的成绩
        list.add(78);
        list.add(66);
        list.add(98);
        list.add(80);

        //遍历方式二:包装类,使用增强for循环
//        for (Integer score: list){
    
    
//            int stuScore = score;
//            //避免强转
//            System.out.println(stuScore);
//        }

        //遍历方式三:迭代器的方式
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
    
    
            System.out.println(iterator.next());
        }

//        遍历方式一:转为数组
//        System.out.println(Arrays.toString(list.toArray()));

        //问题一:类型不安全
//        list.add("Tom");
//        for (Object score:list){
    
    
//            //强转,可能出现 ClassCastException
//            int stuScore = (Integer) score;
//            System.out.println(stuScore);
//        }
    }

3. Customized generic structure

How to customize generic structures: generic classes, generic interfaces, generic methods

Custom generic class Order

import java.util.ArrayList;
import java.util.List;

/**
 * @author: Arbicoral
 * @Description: 自定义的泛型类
 */
public class Order<T> {
    
    
    String name;
    int orderId;

    /**
     * ① 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
     * 下面例子中:类的泛型是 String ,泛型方法的泛型是 Integer,没有任何关系
     * ② 换句话说,泛型方法所属的类是不是泛型类都没有关系
     * ③ 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化时确定的
     */
    public static <E> List<E> copyFromArrayList(E[] arr){
    
    
        ArrayList<E> list = new ArrayList<>();
        for (E e: arr){
    
    
            list.add(e);
        }
        return list;
    }

    //类的内部结构就可以使用类的泛型
    T orderT;
    public Order(){
    
    
        //编译不通过:此时T还是变量,只是变量是用类型来充当的
       //T[] arr = new T[10];
        //强转,编译通过
        T[] arr = (T[]) new Object[10];
    };
    public Order(String name, int orderId, T orderT){
    
    
        this.orderT = orderT;
        this.orderId = orderId;
        this.name = name;
    }

    public T getOrderT() {
    
    
        return orderT;
    }

    public void setOrderT(T orderT){
    
    
        this.orderT = orderT;
    }

    @Override
    public String toString() {
    
    
        return "Order{" +
                "name='" + name + '\'' +
                ", orderId=" + orderId +
                ", orderT=" + orderT +
                '}';
    }

//    /**
//     * 静态方法中不能使用类的泛型
//     * 因为类的泛型是造对象的时候确定的,静态方法早于对象创建的,相当于类型还没有确定就要用了,不行!
//     * @param orderT
//     */
//    public static void show(T orderT){
    
    
//        System.out.println(orderT);
//    }

//    public void show(){
    
    
//        //编译不通过
//        try{
    
    
//
//        }catch (T t)
//    }
}

Two subclasses of Order, SubOrder and SubOrder1

public class SubOrder extends Order<Integer>{
    
    //SubOder:不再是泛型类
}
public class SubOder1<T> extends Order<T>{
    
    //SubOder1<T>:仍然是泛型类
}

Points to note :

  1. A generic class may have multiple parameters, in which case multiple parameters should be placed together within angle brackets. for example:

    <E1, E2, E3>

  2. The constructor of a generic class is as follows: public GenericClass(){}.

    ​ And the following is wrong: public GenericClass<\E>(){}

  3. After instantiation, the structure operating on the original generic location must be consistent with the specified generic type.

  4. Different references of generic types 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 the 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: Use generics all the way. If not, don’t use it all the way.

  6. If the generic structure is an interface or abstract class, you cannot create objects 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 generics and can be replaced by wrapper classes.

  9. Generics declared on a class/interface represent a certain type in this class or this interface, and can be used as the type of non-static properties, the parameter type of non-static methods, and the return value type of non-static methods. But you cannot use class generics in static methods.

  10. Exception classes cannot be generic

  11. New E[] cannot be used. But you can: E[] elements = (E[])new Object[capacity]; Reference: ArrayList source code declares: Object[] elementData, not a generic parameter type array.

  12. The parent class has generics, and the subclass can choose to retain the generics or specify the generic type.

    • Subclasses do not retain the generics of the parent class: implementation on demand

      • No type erasure
      • concrete type
    • Subclass retains the generics of the parent class: generic subclass

      • keep all

      • Partially reserved

Conclusion: Subclasses must be "rich second generation". In addition to specifying or retaining the generics of the parent class, subclasses can also add their own generics.

/**
 * 注意点4:泛型不同的引用不能相互赋值。
 */
public void test3(){
    
    
    ArrayList<String> list1 = null;
    ArrayList<Integer> list2 = null;
    //泛型不同的引用不能相互赋值。
    //list2 = list1;
}
/**
 * @author: Arbicoral
 * @Description: 注意点10: 异常类不能声明为泛型类
 */
public class MyException<T> extends Exception {
    
    
}

2.1. Use of generic methods

@Test
/**
 * ① 泛型方法:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系
 * 下面例子中:类的泛型是 String ,泛型方法的泛型是 Integer,没有任何关系
 * ② 换句话说,泛型方法所属的类是不是泛型类都没有关系
 * ③ 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化时确定的
 */
public void test4(){
    
    
    Order<String> order = new Order<>();
    Integer[] arr = new Integer[]{
    
    1,2,3,4};
    //泛型方法在调用时,指明泛型参数的类型
    List<Integer> list = order.copyFromArrayList(arr);

    System.out.println(list);
}

4. The reflection of generics in inheritance

/**
 * 1. 泛型在继承方面的体现
 * 虽然类A 是类B的父类, 但是G<A> 和 G<B>二者不具备子父类关系,二者是并列关系
 *
 * 补充:类A 是类B的父类, A<G> 是B<G>的父类
 */
@Test
public void test1(){
    
    
    Object obj = null;
    String str = null;
    //多态
    obj = str;

    Object[] arr1 = null;
    String[] arr2 = null;
    //多态展示
    arr1 = arr2;

    List<Object> list1 = null;
    List<String> list2 = null;
    //此时的list1 和 list2 的类型不具有子父类关系
    //编译不通过
    // list1 = list2;
}

5. Use of wildcards

5.1. Use of wildcards

/**
 * 2. 通配符的使用
 *    通配符:?
 *    类A是类B的父类,G<A>和G<B>是没有关系的,二者共同的父类是G<?>
 */
@Test
public void test2(){
    
    
    List<Object> list1 = null;
    List<String> list2 = null;

    List<?> list = null;
    list = list1;
    list = list2;

    print(list1);
    print(list2);
}

//遍历
public void print(List<?> list){
    
    
    Iterator<?> iterator = list.iterator();
    while (iterator.hasNext()){
    
    
        Object next = iterator.next();
        System.out.println(next);
    }
}

5.2. Use of wildcards with restrictions

image.png

6. Examples of generic applications

Define a generic class DAO and define a Map member variable in it. The key of Map is of String type and the value is of T type.

Create the following methods respectively:

  • public void save(String id,T entity): Save the object of type T to the Map member variable
  • public T get(String id): Get the object corresponding to id from map
  • public void update(String id,T entity): Replace the content whose key is id in the map with the entity object
  • public List list(): Returns all T objects stored in the map
  • public void delete(String id): delete the specified id object

Define a User class : This class contains: private member variables (int type) id, age; (String type) name.

Define a test class : Create an object of the DAO class, call its save, get, update, list, and delete methods to operate the User object, and use the Junit unit test class for testing

泛型类 DAO

package 20230527.exer;

import java.util.*;

/**
 * @author: Arbicoral
 * @create: 2023-05-27 17:45
 * @Description:
 *
 * 定义个泛型类 DAO<T>,在其中定义一个 Map 成员变量,Map 的键为 String 类型,值为 T 类型。
 * 分别创建以下方法:
 * public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中
 * public T get(String id):从 map 中获取 id 对应的对象
 * public void update(String id,T entity):替换 map 中 key 为 id 的内容,改为 entity 对象
 * public List<T> list():返回 map 中存放的所有 T 对象
 * public void delete(String id):删除指定 id 对象
 */
public class DAO<T> {
    
    
    private Map<String, T> map = new HashMap<String, T>();

    /**
     * 保存 T 类型的对象到 Map 成员变量中
     * @param id
     * @param entity
     */
    public void save(String id,T entity){
    
    
        map.put(id, entity);
    }

    /**
     * 从 map 中获取 id 对应的对象
     */
    public T get(String id){
    
    
        return map.get(id);
    }

    /**
     * 替换 map 中 key 为 id 的内容,改为 entity 对象
     */
    public void update(String id,T entity){
    
    
        if (map.containsKey(id)){
    
    
            map.put(id, entity);
        }
    }

    /**
     * 返回 map 中存放的所有 T 对象
     * @return
     */
    public List<T> list(){
    
    
        //错误的
//        Collection<T> values = map.values();
//        return (List<T>) values;

        //正确的
        ArrayList<T> list = new ArrayList<>();
        Collection<T> values = map.values();
        for(T t: values){
    
    
            list.add(t);
        }
        return list;
    }


     /**
     删除指定 id 对象
     */
    public void delete(String id){
    
    
        map.remove(id);
    }
}

User 类

package 20230527.exer;
import java.util.Objects;

/**
 * @author: Arbicoral
 * @create: 2023-05-27 20:16
 * @Description:
 *
 * 定义一个 User 类:
 * 该类包含:private 成员变量(int 类型) id,age;(String 类型)name。
 */
public class User {
    
    
    private int id;
    private int age;
    private String name;

    //空参构造器
    public User(){
    
    }

    //带参构造器
    public User(int id, int age, String name){
    
    
        this.age = age;
        this.id = id;
        this.name = name;
    }

    public void setId(int id){
    
    
        this.id = id;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public int getId() {
    
    
        return id;
    }

    public String getName() {
    
    
        return name;
    }

    @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;
        return id == user.id && age == user.age && Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(id, age, name);
    }
}

测试类

package 20230527.exer;

import java.util.List;

/**
 * @author: Arbicoral
 * @create: 2023-05-27 20:22
 * @Description:
 *
 * 定义一个测试类:
 * 创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,
 * 使用 Junit 单元测试类进行测试
 */
public class DAOTest {
    
    
    public static void main(String[] args) {
    
    
        DAO<User> dao = new DAO<User>();
        dao.save("1001", new User(1001, 34,"周杰伦"));
        dao.save("1002", new User(1002, 20,"昆凌"));
        dao.save("1003", new User(1003, 25,"蔡依林"));

        dao.update("1003", new User(1003, 35,"方文山"));

        dao.delete("1002");

        List<User> list = dao.list();
        list.forEach(System.out::println);
    }
}

Guess you like

Origin blog.csdn.net/Miss_croal/article/details/132953339
Recommended