current position:Home>Java data structures and algorithms lesson 2 - generics

Java data structures and algorithms lesson 2 - generics

2022-04-29 18:13:00Knowledge and Practice

 

Catalog

One : Definition of generics

Two : Export generics

3、 ... and : Generic

3.1 The syntax of generics

3.2 Erasure mechanism ( understand )

3.3 The upper bound of generics

3.3.1 Definition of upper bound of generics  

3.3.2 The syntax of the upper bound of generics

3.4 Generic static methods

Four : wildcard

4.1 extraction

4.2 Wildcards and their upper and lower bounds

5、 ... and : Packaging

 5.1 Packing

5.2 Unpacking

5.3 An interesting topic


One : Definition of generics

         General classes and methods , Only specific types can be used : Or the basic type , Either a custom class . If you're writing code that can be applied to many types of code , This rigid restriction can be very restrictive to the code .

         Generics are in JDK1.5 New grammar introduced , Popular speaking , Generic : Is applicable to many types . In terms of code , Is to parameterize the type .

Two : Export generics

We've learned about arrays before , In an array , Only elements of the specified type can be stored . for example :

int[ ] array1 = new int[10];               // Store integer data

String[ ] array2 = new Stirng[10];    // Store string data

        Generic based definitions , We hope that an array can be applied to many types . because Object Class is the parent of all classes , So can you create an array as Object Well ? Specific examples are as follows :

class MyArray{
    public Object[] array = new Object[10];

    /**
     *  obtain pos The value of the subscript 
     *
     * @param pos
     * @return
     */
    public Object getPos(int pos) {
        return array[pos];
    }

    /**
     *  to pos Put one yuan in the subscript 
     */
    public void setPos(int pos, Object val) {
        array[pos] = val;
    }
}
public class TestDemo {

    public static void main(String[] args) {
        MyArray array = new MyArray();
        array.setPos(0,1);
        array.setPos(1,"hello");

    }
}

        So far , There seems to be nothing wrong with this code , Because the element type of the array is Object, So I can put any type of data , For example, in 0 Put the position of the subscript into the integer 1, stay 1 Put the position of the subscript into the string “hello”. But when we want to pass getPos() Function gets the element of a subscript , You'll find that :

          The compiler reported an error ! This is because the element type in the array is uncertain , So when you get elements , The compiler cannot help you detect the type of element you currently want to get , So you get an error . But in practice , We rarely need to put data of the same type in an array , It doesn't make any sense . In general , We still want to be able to specify the type ourselves , Instead of holding multiple types at the same time .

         The role of generics is reflected at this time : Specify the current container , What type of object to hold , Then let the compiler check . here , You need to type , Pass as a parameter . What kind of , Just pass in what type .

3、 ... and : Generic

3.1 The syntax of generics

class Generic class name < Type parameter list > {
// Type parameters can be used here
}
class ClassName<T1, T2, ..., Tn> {
}

class Generic class name < Type parameter list > extends Inheritance class /* Type parameters can be used here */ {
// Type parameters can be used here
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// You can use only partial type parameters
}

        Simply looking at these grammars may make you feel big , So I will simply rewrite the above example , To help us understand the syntax of generics :

package Test;

class MyArray<T>{
    public T[] array = (T[])new Object[10];

    /**
     *  obtain pos The value of the subscript 
     *
     * @param pos
     * @return
     */
    public T getPos(int pos) {
        return array[pos];
    }

    /**
     *  to pos Subscript put an element 
     *
     */
    public void setPos(int pos, T val) {
        array[pos] = val;
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyArray<Integer> array = new MyArray<Integer>();
        array.setPos(0,1);
        array.setPos(1,2);
        Integer str = array.getPos(1);
        System.out.println(str);

    }
}

The operation results are as follows :

          in other words , To write a class as “ Universal class ”, We need to do the following :

Be careful :

1. The type of each element in the array is no longer Object, And become T. So when you create an array , Write getPos() and setPos() When the method is used , All use T instead of Object;

2. When creating an array , To write public T[] array = (T[])new Object[10], On the right new One Object Type array and force to T[]. That is, you can't directly new Arrays of generic types ;

3. After the class name <T> Represents a placeholder , Indicates that the current class is a generic class ,【 standard 】 Type parameters are generally represented by a capital letter , Common names are :

  • E Express Element
  • K Express Key
  • V Express Value
  • N Express Number
  • T Express Type
  • S, U, V wait - second 、 Third 、 The fourth type

4. Generics can only accept classes , All basic data types must use wrapper classes ! The box Integer instead of int;

5. When the compiler can deduce type arguments based on context , You can omit the filling of type arguments ;

MyArray<Integer> list1 = new MyArray<>(); // It can be deduced that the type arguments required for instantiation are Integer

MyArray<String> list2 = new MyArray<>();   // It can be deduced that the type arguments required for instantiation are String

6. Generics are parameterization of data types , To pass ;

7. Use <T> Indicates that the current class is a generic class ;

8. The advantages of generics so far : Data type parameterization , Automatic type checking and conversion at compile time .

3.2 Erasure mechanism ( understand )

         The erasure mechanism is in compile when , be-all T Are erased for Object. Popular speaking , Is in the process of compiling , Will all T Replace with Object This mechanism of .

3.3 The upper bound of generics

3.3.1 Definition of upper bound of generics  

         When defining generic classes , Sometimes you need to make certain constraints on the incoming type variables , You can constrain by type boundaries . in other words , The upper bound of a generic type is a function of the type variable passed in constraint .

3.3.2 The syntax of the upper bound of generics

class Generic class name < Type parameter extends Type boundary > {
...
}

Examples are as follows :

class Test<E extends Number> {
        
    }

public class TestDemo2 {
    public static void main(String[] args) {
        Test<Number> test = new Test<>();
        Test<Integer> test1 = new Test<Integer>();
        Test<Float> test2 = new Test<Float>();
        Test<Double> test3 = new Test<Double>();
    }
}

        This code shows : The type variable passed in must be Number Classes and subclasses .

        according to java Document display , The types we can pass in include Byte,Double,Float......

Complex examples :  

public class MyArray<E extends Comparable<E>> {
...
}

E It must be realized Comparable Interface .  Specific examples are as follows :

package Test;

class Student implements Comparable<Student>{
    public String name;
    public int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age-o.age;
    }
}

class Alg<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}



public class TestDemo1 {
    public static void main(String[] args) {
    Alg<Integer> alg = new Alg<Integer>();
    Integer[] array = {1,4,5,21,8,19};
    Integer max = alg.findMax(array);
    System.out.println(" The largest element in this integer array is :"+max);

    Alg<Student> alg2 = new Alg<Student>();
    Student[] students = new Student[3];
    students[0] = new Student("wukong",18);
    students[1] = new Student("bajie",99);
    students[2] = new Student("shashidi",5);
    Student student = alg2.findMax(students);
    System.out.println(" The oldest student in the student array is :"+student);
}
}

The operation results are as follows :

analysis :

          We found that , Every time you call findMax() When the method is used , You must instantiate the object first , Before calling findMax() Method . that , Is it possible not to instantiate objects , Call directly findMax() Methods? ? The answer is yes . This requires static methods .

3.4 Generic static methods

        After clarifying its grammar , We will “ The upper bound of generics ” Join in , That is, make certain constraints on the incoming type variables :

        Now , We can call... Directly with the class name findMax() Method ,1 Instead of instantiating the object first . Specific examples are as follows :

class Alg2 {
    public static<T extends Comparable<T> > T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}



public class TestDemo1 {

    
    public static void main(String[] args) {
        Integer[] array = {1,4,5,21,8,19};
        Integer max = Alg2.findMax(array);
        System.out.println(max);
    }
}

  The operation results are as follows :

Four : wildcard

4.1 extraction

        wildcard , seeing the name of a thing one thinks of its function , That is to adapt to various types .        

         What's the use of wildcards ? in short , Wildcards are used to solve the problem that generics cannot covariate , Covariance means if Student yes Person Subclasses of , that List<Student> Should also be List<Person> Subclasses of . But generics do not support such parent-child relationships . Examples are as follows :

          As shown in the figure ,Student Class is Person Subclasses of classes , We think that there should be no problem for the parent class to refer to the child class object . However , When we put our ideas into practice , Found this illegal , This is because types do not support such parent-child relationships , This is called incoherence . And to solve this problem , You need to use wildcards . Examples are as follows :

package Test;


class Message<T> {
    private T message ;

    public T getMessage() {
        return message;
    }

    public void setMessage(T message) {
        this.message = message;
    }

}

public class TestDemo4 {

    public static void function() {
        Message<String> message = new Message<String>() ;
        message.setMessage(" Go out laughing , My generation is not Penghao people !");
        fun(message);
    }

    public static void main(String[] args) {
        Message<Integer> message = new Message<Integer>() ;
        message.setMessage(1);
        fun(message);
    }

    public static void fun(Message<?> temp){
        //temp.setMessage(1); You can't add elements to it .
        //Message<?> temp   Can accept many types 
        System.out.println(temp.getMessage());
    }
}

4.2 Wildcards and their upper and lower bounds

1、 wildcard , For unknown types , Represents not concerned or unable to determine the type of actual operation , It is generally used with containers .

public void testV(List<?> list) {}

2、<? extends T>, Define the upper limit , During this period, only reading ability . This method indicates that the parameterized type may be the specified type or subtype . Acceptable T And its subclasses .

//t1 Or Test2, Or Test2 Subclasses of 

public void testC(Test1<? extends Test2> t1) {

    Test2 value = t1.getValue();

    System.out.println("testC Medium :" + value.getT());

}

3、<? super T>, Lower limit definition , Have reading ability and some writing ability , The subclass can write to the parent class . This method indicates that the parameterized type can be the specified type , It can also be a parent class . You can receive T And their parents , Can write T And its subclasses .

//t1 Or Test5, Or Test5 Parent class of 

public void testB(Test1<? super Test5> t1) {

    // The subclass replaces the parent 

    Test2 value = (Test2) t1.getValue();

    System.out.println(value.getT());

}

        The above is the wildcard and its upper bound 、 The whole content of the lower bound .

5、 ... and : Packaging

stay Java in , Because the basic type does not inherit from Object, In order to support basic types in generic code ,Java Each basic type corresponds to a packaging type .

        The figure shows each basic type and its corresponding packaging class .

        What we're going to introduce today , Mainly packing and unpacking .

 5.1 Packing

public class TestDemo6 {
 
    public static void main(String[] args) {
        int a = 10;
        Integer b = a;// Automatic boxing 
        Integer c = Integer.valueOf(a);// Manual packing 
        System.out.println(b);
    }
}

         How to automatically pack ? Direct will int The type variable is assigned to Integer Variable of type . For manual packing, call balueOf() Method .

5.2 Unpacking

public class TestDemo6 {

    public static void main(String[] args) {
        Integer a = 10;
        int b = a;// Automatic dismantling 
        double d = a;//intValue()  The default is intValue() Demolition 

        double d2 = a.doubleValue();// Manual unpacking 

        System.out.println(b);
    }

}

        When unpacking ,a by Integer type , Then the default will be intValue() Unpacking ; How to unpack manually , Then you need to explicitly call the corresponding method .

5.3 An interesting topic

        For unpacking and packing , We've learned almost everything . Next, I will introduce a very interesting topic , That's included “ Packing ” Relevant knowledge .

         Analysis of the code , Why does this happen ?

        When executing these lines of code , We know something happened . And at the bottom , By default, boxing calls valueOf() Method . So to solve this problem , We need to check valueOf() The original code of , Let's see how it realizes packing .

          To test our conclusions , We use the special value method to verify :

        The conclusion is true ! The solution is simple , Is the use of equals() Methods for comparison .( Comparison of reference types )

public class TestDemo6 {
    public static void main(String[] args) {
        Integer a = 128;
        Integer b = 128;
        System.out.println(a.equals(b));
    }
}

          The operation results are as follows :

          This tells us , When comparing reference types , Be sure to use equals() Method or compareTo() Method .


The end of this lesson !

copyright notice
author[Knowledge and Practice],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2022/119/202204291636241140.html

Random recommended