[data structure] learning of List related knowledge [detailed explanation 2]

Posted by vmarellano on Sun, 10 Oct 2021 10:01:38 +0200

List

List can be understood as a "linear table", that is, a data structure with sequential relationship;
Linear tables can be divided into two types: one is the sequential table ArrayList / vector, and the other is the linked list LinkedList.

Basic introduction to Generic

Background of the introduction of generics: in order to write a class or method, it can support many different types of objects at the same time;

Classification of generics: generic classes and generic methods.

The so-called generics, in fact, is a simple packaging of objects from the syntax level, which can help us automatically add some compiler type checks during the compilation process and automatically help us complete some type conversion.

public class TestDemo1 {
    //private int[] data;// This array is simply defined as int type, which means that only integers can be stored in the current sequence table
    //It's not appropriate to store only integers. It's too narrow to store only integers according to what type the sequence table should store. So what can be done to enable this class to store many different data types?
   //To solve this problem, you can use generics or Object
    //Using Object to solve this problem
    private Object[] data=new Object[10];
    private int size;
    public void add(Object elem){
        data[size]=elem;
        size++;
    }
    public Object get(int index){
        return data[index];
    }
    public static void main1(String[] args) {
        //String is also inherited from Object
        //When you call add, it is equivalent to upward transformation. Upward transformation can also be understood as implicit type conversion
        TestDemo1 testDemo1=new TestDemo1();
        testDemo1.add("You, you, you");//Insert element
        testDemo1.add("I, I, I");
        // When you call get, the Object is returned. Here, you need to transform down and force type conversion
        String str=(String) testDemo1.get(0);//Get element with subscript 0
    }
}

Use of generics

package java2021_1002;
/**
 * Description:generic paradigm
 */
/*
1,Angle brackets < >: is a sign of genericity
2,E Is a Type Variable, and the variable name is generally capitalized
*/
public class TestDemo2<E> { //<E> Is a generic parameter, which is used to specify which type the specific generic parameter is;
    //This parameter is equivalent to a formal parameter, which needs to be determined when the class is actually instantiated.
    //Common names of generic parameters: e t key value, etc
    private E[]data=(E[]) new Object[100];//It is not allowed to directly new a generic class. The current data type can be regarded as an object []. What type does object specifically represent
    /*It can only be determined when TestDemo2 is instantiated.
    E Such generic parameters cannot be instantiated directly. Because we don't know what type E is, we can create a new Object type
    No matter what type E is, it is a subclass derived from Object. Therefore, an Object array can be created to correspond to an array of type E. direct assignment is not allowed. Type conversion (E[]) new Object[100] is required*/
    private int size;
    public void add(E elem){
        data[size]=elem;
        size++;
    }
    public E get(int index){//E is the type of each element in the array
        return data[index];
    }
    //Generic programming is similar to a "template". The above is equivalent to a template. Based on this set of templates, you can set up various types of data. They can change automatically with generic parameters, so you can solve problems in different scenarios
    public static void main(String[] args) {
        //The E type in T TestDemo1 represents the String type
        TestDemo2<String> testDemo2=new TestDemo2<>();
        testDemo2.add("He he he");
        testDemo2.add("She she she");
        String str=testDemo2.get(0);//The return value can be assigned directly here, so there is no need to add forced type conversion
        TestDemo2<Animal> animalTestDemo2=new TestDemo2<>();
        //It can be found that the generic parameter does not have to be passed in String, as long as it is a reference type, even the self created class can be passed in
        animalTestDemo2.add(new Animal());
        animalTestDemo2.add(new Animal());
        Animal animal=animalTestDemo2.get(0);//
    }
}
package java2021_1002;
/**
 * Description:Create an Animal class yourself
 */
public class Animal {
    private String name;
}

The period of action behind generics and the simple principles behind them

The syntax of generics is a compile time mechanism, that is, the syntax involved in the compilation process. In order to facilitate programmers to write code and perform some type checking operations during compilation.

If the compilation is completed, there is no generics in the running process. That is, the compiler directly treats generic parameters as Objec in the process of compiling code

However, the compiler automatically adds some type conversion operations and type verification operations.

How can the basic types (built-in types) such as int and double be applied to generic types?

Because the built-in type does not inherit from Object, if the generic "template" is directly applied, the compilation cannot pass,Because int is an int, there is no relationship between it and Object. The class that must be created will inherit from Object. The eight basic types of int, double and float are not the classes we create ourselves, nor the classes created by the standard library, but the built-in types. Therefore, we can't put int directly in at this time. What should we do?

  • Direct insertion does not work. We can create a class to represent an integer. At this time, the created class represents the reference type. However, this class does not need to be created manually. The standard library has helped us create these eight basic types. In other words, the standard library has helped us create one-to-one corresponding classes to represent the basic types. The classes in this class are called packaging classes. Packaging classes are the first eight basic data types, Wrap a class a little and turn it into a reference type. Now let's enter the study of packaging

Generic summary

  1. Generics are introduced to solve the generality of some containers, algorithms and other codes, and can do type checking during compilation
  2. Generics use that Object is the ancestor of all classes, and the reference of the parent class can point to the specific of the child class Object.
  3. Generics are a compile time mechanism, that is, MyArrayList and MyArrayList are one type at run time.
  4. Generics is a legal syntax in Java, marked by angle brackets < >

Wrapper Class

The Object reference can point to any type of Object, but there are exceptions. The eight basic data types are not objects. Isn't that the generic mechanism just now going to fail?
In fact, it is true. In order to solve this problem, java introduces a special class, that is, the wrapper class of these eight basic data types. In the process of use, values such as int will be wrapped into an object.

There is a direct correspondence between basic data types and packaging classes

The following table shows the current wrapper classes:

Basic data typeCorresponding packaging class
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDoublt
charCharacter
booleanBoolean
  • The wrapper class corresponding to the basic data type is basically the initial capital of the type, except Integer and Character.

Why packaging?

java itself is an object-oriented language. Sometimes it has to deal with some situations, such as converting strings into integers and integers into strings. In this case, it can only be converted with the help of wrapper classes, because if it is a class, it must have some methods to support its conversion, so, If the basic type has a corresponding wrapper class, one advantage is that when dealing with some things in the future, the basic type can be object-oriented. Once it is object-oriented, we can use the methods in the object to deal with and solve our problems, which is also the purpose of the wrapper class.

Code example: about the use of Integer packing class and packing and unpacking operation

package java2021_1002;
/**
 * Description:Packaging
 */
public class TestDemo2<E> {
    private E[]data=(E[]) new Object[100];
    private int size;
    public void add(E elem){
        data[size]=elem;
        size++;
    }
    public E get(int index){//E is the type of each element in the array
        return data[index];
    }
    //Generic programming is similar to a "template". The above is equivalent to a template. Based on this set of templates, you can set up various types of data. They can change automatically with generic parameters, so you can solve problems in different scenarios
    public static void main(String[] args) {
        //At this time, a wrapper class such as Integer is saved, so this type can be used as a generic parameter
        TestDemo2<Integer> integerTestDemo2=new TestDemo2<>();
        integerTestDemo2.add(new Integer(10)); //new is an Integer object. The content stored in this object is an Integer such as 10
        Integer num=new Integer(10);//It can also be written like this
        integerTestDemo2.add(num);
        //This operation is equivalent to converting the built-in type of int to Integer. We call this operation (manual) boxing
         Integer num1=Integer.valueOf(10);//There is a static method valueof in the Integer class, which also completes the (manual) boxing operation by calling the valueof method
        Integer num2=10;//This direct assignment of int to Integer is called auto boxing
        integerTestDemo2.add(num2);
        //Unpacking: convert Integer to int
        num=integerTestDemo2.get(0);
        int value=num.intValue();//Manual unpacking
        int value1=num;//Automatic unpacking
    }
}

Use of packaging: boxing and unboxing

  • Packing and unpacking are sometimes called packing and unpacking. The so-called packing and unpacking operations are actually type conversion, but one of these types is a built-in type and the other is a reference type.
  • Packing / packing: packing a simple type into a packing type
  • Unpacking / unpacking: change the packaging type to a simple type

You can use the help manual to view information about Integer:

Code example of manual packing and manual unpacking:

 public static void main(String[] args) {
       /*There are two ways of packing: one is valueof and the other is new construction method*/
        int i=10;//Simple type
        // Manual packing operation: create a new Integer object and put the value of i into an attribute of the object
        Integer ij=new Integer(i);//It turns out that i is just a simple type. After new, it becomes a class, which is called boxing operation
        //There is a static method valueof in the Integer class, which also completes the boxing operation by calling the valueof method
        Integer ii=Integer.valueOf(i);//The valueof method is to wrap a simple type into its corresponding packaging type. This process is also called boxing
        // Manual unpacking: take out the value in Integer object and put it into a basic data type
        int j = ii.intValue();//If you want to break the ii integer into a simple int type, call intValue()
        double d=ii.doubleValue();//If you want to split the ii integer into a simple double type, call doubleValue()
        /*Unpacking is to call its corresponding value method depending on the type to be unpacked*/
    
    }

Auto boxing and auto unpacking code example: Auto boxing / unpacking, that is, implicit type conversion

 public static void main(String[] args) {
        Integer a=10;//10 is a simple type. Assigning an int to Integer is automatic boxing (automatic boxing is a special function given by the compiler to the wrapper class, that is, only the wrapper class can use this feature, and other types are converted differently in this way)
        int b=a;//Automatic unpacking
        /*Although it is automatic boxing, its bottom layer calls valueOf method, and its bottom layer calls intValue method*/
      //
    }

You can use the decompile tool javap to view the underlying principle of automatic boxing and unpacking. The usage is: javap -c file name (class name), which can disassemble java programs.
Code example:

 public static void main(String[] args) {
        Integer a=100;//Automatic packing
        Integer b=100;
        System.out.println(a==b);
        Integer a1=200;
        Integer b1=200;
        System.out.println(a1==b1);
    }
//Print results:
true
false

Why is the result of the above code like this?

Automatic boxing is to call the valueOf method at the bottom,

Place the mouse over valueOf, click ctrl, and go to the source code of valueOf, as shown in the figure:

Therefore, if the given data is within this range (I > = - 128 & & I < = 127), the if statement will be executed, and the number will be retrieved in this subscript every time and returned. Therefore, both a and b store the first 100, so they are equal, and the result is true.
If the given data is not in this range, the if statement cannot enter, and a new object will be created. Therefore, the references of the two objects stored in a1 and b1 are not equal, and the result is false.

javap decompiler

Here, we just learn a decompile tool in a jdk to view the process of automatic boxing and automatic unpacking, and see that this process occurs during compilation.

javap -c Class name
Compiled from "Main.java"
public class Main {
  public Main(); 
    Code:
      0:aload_0 
      1: invokespecial #1     // Method java/lang/Object."<init>":()V
      4: return 
  public static void main(java.lang.String[]); 
    Code:
      0: bipush 10 
      2: istore_1 
      3: iload_1 
      4: invokestatic #2     // Method java/lang/Integer.valueOf: 
(I)Ljava/lang/Integer; 
      7: astore_2 
      8: iload_1 
      9: invokestatic #2     // Method java/lang/Integer.valueOf: 
(I)Ljava/lang/Integer; 
      12: astore_3 
      13: aload_2 
      14: invokevirtual #3   // Method java/lang/Integer.intValue:()I 
      17: istore 4 
      19: aload_2 
      20: invokevirtual #3    // Method java/lang/Integer.intValue:()I 
      23: istore 5 
      25: return 
}

  • Compile: convert. java to. class (for example, compile pork into ham sausage)
  • Decompilation: it is to convert. class to. java, but decompilation cannot 100% restore the previous code. Only part of the core logic can be seen.
  • Decompilation is that we can't restore ham sausage to pork, but we can get to its general content (made of pork).

Use of List

Common methods of List

List official document

methodexplain
boolean add(E e)Tail insert e
void add(int index,E element)Insert e into the index position
boolean addAll(Collection<?extend E>c)Trailing elements in c
E remove(int index)Delete index location element
boolean remove(Object o)Delete the first o encountered
E get(int index)Get subscript index position element
E set(int index,E element)Set the subscript index position element to element
void clear()empty
boolean contains(Object o)Judge whether o is in the linear table
int indexOf(Object o)Returns the subscript of the first o
int lastIndexOf(Object o)Returns the subscript of the last o
List subList(int fromIndex,int toIndex)Intercepted part list

The meaning of individual parameters in the above methods is explained as follows:

  • E: Indicates the data type in < >
  • e: Element
  • index: subscript
  • o: Representation object
  • c: Represents a collection

Code example:

package java2021_1002;

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

/**
 * Created by Sun
 * Description:List Interface
 * User:Administrator
 * Date:2021-10-03
 * Time:15:08
 */
public class TestList {
        //1. Create List instance
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();// list has its own methods, ArrayList also has its own methods, and the bottom of ArrayList is an array
        //2. Add a new element, and insert e, where e is element
        list.add("Beijing");//Using the add method, it is placed at the last position of the array by default
        list.add("Shanghai");
        list.add("Guangzhou");
        list.add("Shenzhen");
        list.add("Hangzhou");
        //3. Print the whole list directly and print in the order of addition
        System.out.println("Tail insertion e:"+list);//You can print directly because the toString method has been written by default for java collection classes, so you can see the complete content as long as you print directly
        // 4. Insert e into the index position, where index is the subscript and E is the element
        list.add(1,"Xiamen");
        System.out.println("take e Insert into index position:"+list);
        //5. Put the elements of another collection class into the list
        List<String> list1=new LinkedList<>();
        list1.add("Hong Kong");
        list1.add("Macao");
        list.addAll(list1);
        System.out.println("Put the elements of another collection class into list among:"+list);
        //6. Delete the index position element. This remove passes an integer
        System.out.println("Elements with subscript 1 are:"+list.remove(1));
        System.out.println("delete index Location element:"+list);
        //7. Delete the corresponding string. This remove passes an object
        System.out.println(list.remove("Macao"));
        System.out.println("Delete the first encountered o"+list);//If there are multiple objects, the first object starting from the 0 subscript is deleted
        //8. Access elements by subscript
        System.out.println("Print elements with subscript 0:"+list.get(0));//Print elements with subscript 0
        //9. Modify the element according to the subscript (the subscript cannot cross the boundary), and update a subscript to the value you want to update
        list.set(2,"Zhengzhou");
        System.out.println("Modify elements according to Subscripts:"+list);
        //10. Judge whether o is in the linear table
        System.out.println(list.contains("Beijing"));
        System.out.println(list.contains("Henan"));
        //11. Returns the subscript where the first o is located. If there are multiple objects, it is the subscript where the first Beijing starts from the 0 subscript
        System.out.println(list.indexOf("Beijing"));
        list.add("Beijing");
        System.out.println("Tail insertion e:"+list);
        //12. Returns the subscript of the last o. if there are multiple objects, it is the subscript of the last Beijing starting from the 0 subscript
        System.out.println(list.lastIndexOf("Beijing"));
        System.out.println(list.lastIndexOf("Nanjing"));//If there is no such object, - 1 is returned
        //13. Use subList to obtain subsequence and intercept part [1, 4)
        System.out.println("Get subsequence:"+list.subList(1,4));//Front closed rear open section
        System.out.println("Print list:"+list);
        //14. The return value of subList is list < E >, so you can also use the method of two references pointing to an object at the same time. If you modify the value of this object through one reference, the value of the other reference will be changed when accessing
        List<String> list2=list.subList(1,3);
        System.out.println(list2);
        //Modify the 0 subscript element of list2 to Henan. At this time, the 0 subscript of list2 corresponds to the 1 subscript of list
        list2.set(0,"Henan");
        System.out.println("visit list2"+list2);
        System.out.println("visit list:"+list);
        //15. Empty
        list.clear();
        System.out.println("empty list:"+list);
        //Use the for loop to access each element
        for (String s : list) {//The first way of using the for loop is for each to traverse. At this time, each reference such as s will point to each element in the list
            //The interface implemented at the top layer of the list interface is called iteratable. As long as a class implements the iteratable interface, you can use the for each loop
            System.out.println("for each Loop traversal:" + s);
        }
        for (int i = 0; i < list.size(); i++) {//The second way to use the for loop: the traditional for loop to traverse each list
            //Although there is no size() method in the common methods of the list interface, because the list implements the Collection interface, the operations in the Collection can also be used by the list. There is a size() method in the Collection interface.
            System.out.println("tradition for Loop traversal:" + list.get(i));
        }
         //16. You can use the construction method to reconstruct a new List object
        List<String> list3=new ArrayList<>(list);//Copy the contents of the list to get a new object list3
        System.out.println(list3);
        //Whether such an operation is a deep copy or a shallow copy? See if modifying the list will affect list3
        list.set(0,"Nanjing");//Change element 0 in the list to Nanjing
        System.out.println(list);
        System.out.println(list3);//Print result: no effect
        //Because the generic parameter of List is String and String is an immutable parameter type, to verify whether it is a deep copy, you need to fill in a variable object type (such as Integer) for the List generic parameter.
        //17. Empty
        list.clear();
        System.out.println("empty list:"+list);
    }
}

The printing results are as follows:

Common methods of ArrayList

ArrayList official document

methodexplain
ArrayList()Nonparametric structure
ArrayList(Collection<? extends E>c)Building ArrayList with other collections
ArrayList(int initialCapacity)Specifies the initial capacity of the sequence table

Code example:

package java2021_1002;

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

/**
 * Description:ArrayList(Common methods of sequence table)
 */
public class TestArrayList {
    //Use the construction method to reconstruct a new List object
    //1. Nonparametric structure
    List<Integer> list1=new ArrayList<>();
    //2. Building ArrayList with other collections
    ArrayList<Integer> list2=new ArrayList<>(list1);//Pass a collection list1, which is equivalent to new creating an ArrayList
    ArrayList<Integer> list3=new ArrayList<>(new ArrayList<>());
    //3. Specifies the initial capacity of the sequence table
    ArrayList<Integer> list4=new ArrayList<>(10);//At this time, the capacity of the sequence table is 10
}

Common methods of LinkedList

LinkedList official document

methodexplain
LinkedList()Nonparametric structure

Code example:

package java2021_1002;

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

/**
 * Description:LinkedList(Common methods of sequence table)
 */
public class TestLinkedList {
    //You can use the construction method to reconstruct a new List object
    //1. Nonparametric structure
    List<Integer> list1=new LinkedList<>();
    LinkedList<Integer> list4=new  LinkedList<>();// The underlying layer of LinkedList is a two-way linked list. The linked list has no size, so it cannot pass a parameter with an integer
    //2. Building ArrayList with other collections
    LinkedList<Integer> list2=new LinkedList<>(list1);//Pass a set list1, which is equivalent to a LinkedList
    LinkedList<Integer> list3=new LinkedList<>(new  LinkedList<>());
}

Exercises

Exercise 1

Topic Description: there are several students in a school (student objects are placed in a list). Each student has a name (String), class (String) and test score attribute (double). After a test, each student obtains a test score. Traverse the list collection and print out the student object attribute.

code:

package java2021_1002;

import java.util.ArrayList;

class Student{
    //set a property
    private String name;
    private String classes;
    private double score;
    //Provide construction method
    public Student(String name, String classes, double score) {
        this.name = name;
        this.classes = classes;
        this.score = score;
    }
    //Because it is private, you need to provide getter and setter methods

    public String getName() {
        return name;
    }

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

    public String getClasses() {
        return classes;
    }

    public void setClasses(String classes) {
        this.classes = classes;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
    //Print out all the properties of the student. You need to override the toString method
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", classes='" + classes + '\'' +
                ", score=" + score +
                '}';
    }
}
public class TestExercises1 {
    public static void main(String[] args) {
        ArrayList<Student> list1=new ArrayList<>();//Here we can know that the type does not have to be Integer, String, etc
        list1.add(new Student("Little","1 class",89));
        list1.add(new Student("greatly","2 class",77));
        list1.add(new Student("much","1 class",99));
        //Print using the overridden toString method
        System.out.println(list1);//
        System.out.println("====================");
        //You can also use for loop printing
        for (Student student:list1) {
            System.out.println(student);
        }
    }
}

Print results:

Exercise 2

Title Description: there is a List that stores integer data. It is required to use Collections.sort to sort the List.

code:

package java2021_1002;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class TestExercises2 {
    public static void main(String[] args) {
        ArrayList<Integer> list=new ArrayList<>();
        list.add(9);
        list.add(18);
        list.add(2);
        list.add(5);
        list.add(11);
        System.out.println("Before sorting:"+list);
        Collections.sort(list);
        System.out.println("After sorting:"+list);
    }
}

Print results:

Exercise 3

Delete the characters in the second string that appear in the first string.

For example:

String str1="welcome to beijing";
String str2="come";
Output results: wl t bijing

Code: how to use collections

package java2021_1002;

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

public class TestExercises3 {
    public static void func(String str1,String str2){
        if(str1==null || str2==null){
            return;
        }
    List<Character> list=new ArrayList<>();//The wrapper class of Character is Character
    for(int i=0;i<str1.length();i++){//Traverse every character in str1
        char ch=str1.charAt(i);
        if(!str2.contains(ch+"")){
            list.add(ch);
        }
    }
    //Print
        System.out.println(list);
    //Use for loop printing
        for (char c:list) {
            System.out.print(c);
        }
    }
    public static void main(String[] args) {
        String str1="welcome to beijing";
        String str2="come";
        func(str1,str2);//Call func method and pass parameters
        //func("welcome to beijing","come"); / / you can also pass a string directly
    }
}

Print results:

Topics: data structure list