JAVA learning-generic

1. What is generic?

Java generic design principle: As long as there is no warning at compile time, there will be no ClassCastException exception at runtime .

Generics: postpone the type-specific work until the object is created or the method is called to specify the special type

Parameterized type:

  • Pass the type as a parameter

  • <数据类型> Can only be a reference type

Related terms:

  • ArrayList<E>The E in is called the type parameter variable

  • ArrayList<Integer>The Integer referred actual type arguments

  • Whole called ArrayList<E>generic type

  • The whole is ArrayList<Integer>called parameterized type ParameterizedType

2. Why do you need generics

In the early Java, Object was used to represent any type, but the downward transformation had the problem of forced transformation, so that the program was not safe

First, let’s think about it: Without generics, what would happen to collections?

  • Collection and Map collections have no restrictions on the types of elements. Originally, my Collection was loaded with all Dog objects, but there was no grammatical error in storing Cat objects in the collection outside.

  • Throw the object into the collection. The collection does not know what the type of the element is, but only knows that it is Object. Therefore, when get(), Object is returned. Obtain the object outside, but also need to force conversion

With generics:

  • The code is more concise [no forced conversion]

  • The program is more robust [As long as there is no warning during compilation, then there will be no ClassCastException exception during runtime]

  • Readability and stability [When writing a collection, the type is limited]

2.1 After having generics, use enhanced for to traverse the collection

When creating the collection, we clarified the type of the collection , so we can use the enhanced for to traverse the collection!

        //创建集合对象
        ArrayList<String> list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        //遍历,由于明确了类型.我们可以增强for
        for (String s : list) {
            System.out.println(s);
        }

Third, the basics of generics

3.1 Generic classes

A generic class is to define the generic type on the class. When the user uses the class, the type is clarified ... In this way, the user clarifies what type the class represents... The user does not need to use it Worry about forced conversion and abnormal conversion during runtime.

  • The generic type defined on the class can also be used in the method of the class!

/*
    1:把泛型定义在类上
    2:类型变量定义在类上,方法中也可以使用
 */
public class ObjectTool<T> {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
  • Test code:

Which type the user wants to use, specify the type when creating it. When used, the class will be automatically converted to the type that the user wants to use.

    public static void main(String[] args) {
        //创建对象并指定元素类型
        ObjectTool<String> tool = new ObjectTool<>();

        tool.setObj(new String("钟福成"));
        String s = tool.getObj();
        System.out.println(s);


        //创建对象并指定元素类型
        ObjectTool<Integer> objectTool = new ObjectTool<>();
        /**
         * 如果我在这个对象里传入的是String类型的,它在编译时期就通过不了了.
         */
        objectTool.setObj(10);
        int i = objectTool.getObj();
        System.out.println(i);
    }

3.2 Generic methods

The generic class has been introduced before. The generic type defined on the class can also be used in the method...

Now, we may only need to use generics on a certain method ... The outside world only cares about the method, not the other attributes of the class ... In this case, we define generics on the entire class, which is a little fuss. Up.

  • Define generic methods.... Generics are defined first and then used

    //定义泛型方法..
    public <T> void show(T t) {
        System.out.println(t);

    }
  • Test code:

What type is passed in by the user, and what type is the return value?

    public static void main(String[] args) {
        //创建对象
        ObjectTool tool = new ObjectTool();

        //调用方法,传入的参数是什么类型,返回值就是什么类型
        tool.show("hello");
        tool.show(12);
        tool.show(12.5);

    }

3.3 Subclasses derived from generic classes

We have defined a generic class earlier, a generic class is a class with the characteristics of generics, it is essentially a Java class, then it can be inherited

How is it inherited? ? There are two cases here

  1. Subclass specifies the type parameter variable of the generic class

  2. Subclass is ambiguous, the type parameter variable of the generic class

3.3.1 Subclass specifies the type parameter variable of the generic class

  • Generic interface

/*
    把泛型定义在接口上
 */
public interface Inter<T> {
    public abstract void show(T t);

}
  • Classes that implement generic interfaces.....

/**
 * 子类明确泛型类的类型参数变量:
 */

public class InterImpl implements Inter<String> {
    @Override
    public void show(String s) {
        System.out.println(s);

    }
}

3.3.2 The subclass is not clear about the type parameter variable of the generic class

  • When the subclass is not clear about the type parameter variable of the generic class, when the subclass is used by the outside world, the type parameter variable needs to be passed in, and the type parameter variable needs to be defined on the implementation class

/**
 * 子类不明确泛型类的类型参数变量:
 *      实现类也要定义出<T>类型的
 *
 */
public class InterImpl<T> implements Inter<T> {

    @Override
    public void show(T t) {
        System.out.println(t);

    }
}

Test code:

    public static void main(String[] args) {
        //测试第一种情况
        //Inter<String> i = new InterImpl();
        //i.show("hello");

        //第二种情况测试
        Inter<String> ii = new InterImpl<>();
        ii.show("100");

    }

It is worth noting that:

  • If the implementation of the class is to override the method of the parent class, the type of the return value must be the same as that of the parent class!

  • The generics declared on the class are only valid for non-static members


3.4 Type wildcard

Why do you need type wildcards? ? ? ? Let's look at a demand....

Now there is a requirement: the method receives a collection parameter, traverses the collection and prints the collection elements, what should I do?

  • According to what we did not learn about generics before, we might do this:

public void test(List list){


    for(int i=0;i<list.size();i++){

        System.out.println(list.get(i));

    }
}

The above code is correct, but a warning will appear when compiling, saying that the type of the collection element has not been determined ... This is not elegant...

  • So we learned about generics, what should we do now? ? Some people might do this:

public void test(List<Object> list){


    for(int i=0;i<list.size();i++){

        System.out.println(list.get(i));

    }
}

There is nothing wrong with the syntax to do this, but it is worth noting here: the test() method can only traverse the collection loaded with Object! ! !

Emphasize: Generics are <Object>not inherited as before, that is to say List<Object>, they List<String>have nothing to do with! ! ! !

What should I do now? ? ? We don’t know what type of elements are loaded in the List collection, List<Objcet>so this won’t work... So Java generics provides type wildcards?

So the code should be changed to this:

public void test(List<?> list){


    for(int i=0;i<list.size();i++){

        System.out.println(list.get(i));

    }
}

The? Wildcard means that any type can be matched, and any Java class can be matched .....

Now it is very worth noting that when we use the? Wildcard: we can only call methods that are not related to the object's type, and cannot call methods that are related to the object's type.

Remember, you can only call methods that have nothing to do with the object, not methods that are related to the object's type . Because it is not known what the specific type is until the outside world uses it. In other words, in the above List collection, I cannot use the add() method. Because the add() method throws the object into the collection, and now I don’t know what the type of the object is.


3.4.1 Set the upper limit of wildcards

First, let's take a look at where to set the upper limit of wildcards....

Now, I want to receive a List collection, which can only operate on numeric elements [Float, Integer, Double, Byte, etc. numeric types are OK], how to do it? ? ?

We have learned wildcards, but if you use wildcards directly, the set can not only operate on numbers. So we need to set the upper limit of wildcards

    List<? extends Number>

The above code means: The elements loaded in the List collection can only be a subclass of Number or itself

    public static void main(String[] args) {


        //List集合装载的是Integer,可以调用该方法
        List<Integer> integer = new ArrayList<>();
        test(integer);

        //List集合装载的是String,在编译时期就报错了
        List<String> strings = new ArrayList<>();
        test(strings);

    }


    public static void test(List<? extends Number> list) {

    }

3.4.2 Set the lower limit of wildcard

Now that we have said how to set the upper limit of wildcards, setting the lower limit of wildcards is not unfamiliar. Let's just look at the grammar

    //传递进来的只能是Type或Type的父类
    <? super Type>

It’s not uncommon to set the lower limit of wildcards, in the TreeSet collection there are.... Let’s take a look

    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

What's the use of it? ? Let's think about it, when we want to create a TreeSet<String>variable of a type, and pass in a Comparator that can compare the size of String.

Then there are many choices for this Comparator, it can beComparator<String>Comparator<Objcet> , it can also be a parent class whose type parameter is String, for example ...

In doing so, it is very flexible . In other words, as long as it can compare the size of the string, it will do.

It is worth noting that whether it is to set the upper limit or lower limit of the wildcard, it is not possible to operate the method related to the object. As long as the wildcard is involved, its type is uncertain!

3.5 Wildcards and generic methods

Most of the time, we can use generic methods instead of wildcards .....

    //使用通配符
    public static void test(List<?> list) {

    }

    //使用泛型方法
    public <T> void  test2(List<T> t) {

    }

Both of the above methods are possible... So now the question is, should we use wildcards or generic methods? ?

in principle:

  • If the type of dependence between parameters , or return back to the value of the parameter is a dependent relationship between and the. Then use generic methods

  • If there is no dependency , use wildcards , which will be more flexible.


3.6 Generic erasure

Generics are provided to the javac compiler to use , it is used to limit the input type of the collection, so that the compiler at the source code level, that is, block the insertion of illegal data into the collection. But after the compiler compiles the java program with generics, the generated class file will no longer contain generic information , so that the efficiency of the program is not affected. This process is called "erasing".

3.6.1 Compatibility

JDK5 proposed the concept of generics, but JDK5 did not have generics before. That is, generics need to be compatible with the collection below JDK5.

When assigning a collection with generic characteristics to an old version of the collection, the generics will be erased.

It is worth noting that: it reserves the upper limit of the type parameter.

        List<String> list = new ArrayList<>();

        //类型被擦除了,保留的是类型的上限,String的上限就是Object
        List list1 = list;

What if I assign a collection without type parameters to a collection with type parameters ? ?

        List list = new ArrayList();
        List<String> list2 = list;

It will not report an error, it just prompts "unchecked conversion"


Fourth, the application of generic

When we write web pages, there are often multiple DAOs, and we have to write several DAOs each time, which is a bit troublesome.

So what is the effect we want? ? Just write an abstract DAO, and other DAOs will have corresponding methods as long as they inherit the abstract DAO.

To achieve this effect, you must use generics. Because in an abstract DAO, it is impossible to know which DAO will inherit itself, so the specific type is not known. The generic type is to specify its specific type when it is created.

  • Abstract DAO

public abstract class BaseDao<T> {

    //模拟hibernate....
    private Session session;
    private Class clazz;


    //哪个子类调的这个方法,得到的class就是子类处理的类型(非常重要)
    public BaseDao(){
        Class clazz = this.getClass();  //拿到的是子类
        ParameterizedType  pt = (ParameterizedType) clazz.getGenericSuperclass();  //BaseDao<Category>
        clazz = (Class) pt.getActualTypeArguments()[0];
        System.out.println(clazz);

    }


    public void add(T t){
        session.save(t);
    }

    public T find(String id){
        return (T) session.get(clazz, id);
    }

    public void update(T t){
        session.update(t);
    }

    public void delete(String id){
        T t = (T) session.get(clazz, id);
        session.delete(t);
    }

}
  • Inheriting the abstract DAO, the implementation class has corresponding methods for adding, deleting, modifying and checking.

CategoryDao

public class CategoryDao extends BaseDao<Category> {

}

BookDao

public class BookDao extends BaseDao<Book> {


}

 

Guess you like

Origin blog.csdn.net/qq_39331713/article/details/113884413