Java notes -- generics

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:
  1. Advance run-time problems to compile time
  2. Forced type conversion is avoided
  3. 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
    }
}

Tags: Java

Posted on Thu, 14 Oct 2021 14:08:12 -0400 by jack_wetson