Container [basic use, index operation, union, intersection, difference] (2) - comprehensive detailed explanation (learning summary --- from entry to deepening)

 

 

Table of contents

 Wildcards in generics

 Upper and lower limits of wildcards Upper and lower limits of wildcards

 wildcard lower limit

Generics limitations and common mistakes

List interface introduction

 Basic use of ArrayList container

Index operation of ArrayList container

 Union, intersection and difference of ArrayList

Determine whether the array is expanded

Basic use of Vector containers

Vector source code analysis


 Wildcards in generics

 The unbounded wildcard
"?" represents a type wildcard, which is used to replace a specific type. It can only be used inside "<>". It can solve the problem when the specific type is uncertain.

Grammatical structures

public void showFlag(Generic<?> generic){  }

example

public class Generic<T> {

  private T  flag;

  public void setFlag(T flag){
    this.flag = flag;
 }

  public T getFlag(){
    return this.flag;
  }
}


public class ShowMsg {
  public void showFlag(Generic<?> generic){
  
  System.out.println(generic.getFlag());
 }
}


public class Test3 {
  public static void main(String[] args) {

    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new  Generic<>();
    generic.setFlag(20);
    showMsg.showFlag(generic);

    Generic<Number> generic1 = new  Generic<>();
    generic1.setFlag(50);
    showMsg.showFlag(generic1);

    Generic<String> generic2 = new Generic<>();
    generic2.setFlag("old");
    showMsg.showFlag(generic2);
 }
}

Real-time effect feedback
1. In generics, what symbol is used to represent unbounded wildcards?
A!
B?
C#
D*

Answer
1 => B

 Upper and lower limits of wildcards Upper
 and lower limits of wildcards

 Limitation on the upper limit of wildcards: <? extends type> ? The actual type can be the type agreed in the upper limit, or a subtype of the agreed type;

Grammatical structures

public void showFlag(Generic<? extends Number> generic){ }

example

public class ShowMsg {

  public void showFlag(Generic<? extends Number> generic){

        System.out.println(generic.getFlag());
  }
}


public class Test4 {

  public static void main(String[] args) {

    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new  Generic<>();
    generic.setFlag(20);

    showMsg.showFlag(generic);
    Generic<Number> generic1 = new  Generic<>();

    generic1.setFlag(50);
    showMsg.showFlag(generic1);
 }
}

Real-time effect feedback
1. The limit on the upper limit of wildcards means that
the actual type of A can only be the type agreed in the upper limit;
the actual type of B can only be a subtype of the type agreed in the upper limit;

C The actual type can be the type agreed in the upper limit, or it can be a subtype of the agreed type;
D The actual type can be the type agreed in the upper limit, or it can be the parent type of the agreed type;

Answer
1 => C

 wildcard lower limit

 Limitation on the lower limit of the wildcard: <? super type> ? The actual type can be the type agreed in the lower bound, or the supertype of the agreed type;

Grammatical structures

public void showFlag(Generic<? super Integer> generic){ }

example

public class ShowMsg {

  public void showFlag(Generic<? super Integer> generic){
  
     System.out.println(generic.getFlag());
   }
}


public class Test6 {

  public static void main(String[] args) {

    ShowMsg showMsg = new ShowMsg();
    Generic<Integer> generic = new Generic<>();
    generic.setFlag(20);
    showMsg.showFlag(generic);

    Generic<Number> generic1 = new Generic<>();
    generic1.setFlag(50);
    showMsg.showFlag(generic1);
 }
}

Real-time effect feedback

1. The lower limit of the wildcard means that
A’s actual type can only be the type agreed in the lower limit;
B’s actual type can only be a subtype of the type agreed in the lower limit;
C’s actual type can be the type agreed in the lower limit The type of D can also be the subtype of the agreed type;
D The actual type can be the type agreed in the lower limit limit, or the supertype of the agreed type;

Answer

1=>D

Generics limitations and common mistakes

 Generics are mainly used in the compilation phase, and the bytecode class files generated after compilation do not contain type information in generics. The type parameter will be replaced with Object after compilation, and the virtual machine does not know the generic type at runtime. Therefore, when using generics, the following situations are wrong:

 Real-time effect feedback 


1. Which of the following options is wrong to use generics?
A Generic
B Generic
C Generic
D Generic

Answer
1 => D

2. Container introduction

Container Introduction

Containers are used to accommodate objects and manage objects. In our daily life, we use all kinds of containers. Such as pots and pans, boxes and bags etc.

 The "container" in the program also has a similar function, used to hold and manage data. For example, the news list of the following news websites and the course list of education websites are managed by "containers":

In development and learning, we need to deal with data all the time. How to organize these data is an important part of our programming. We generally use "containers" to accommodate and manage data. In fact, the array we learned earlier is a container in which
objects or primitive data can be placed.
Advantages of arrays : It is a simple linear sequence, which can quickly access array elements and is highly efficient. From the perspective of query efficiency and type checking, arrays are the best.
Disadvantages of arrays : inflexible. Capacity needs to be defined in advance and cannot be expanded as demand changes. For example: in a user management system, we want to retrieve all the users registered today, how many such users are there? We can't be sure when we write a program. Therefore, arrays cannot be used here.

 Based on arrays cannot meet our "needs for managing and organizing data", so we need a more powerful, flexible, and expandable container to load our objects. This is the container we are going to learn today, also called Collection.

 Real-time effect feedback

1. What is the role of the container in Java?
A holds data
B processes data
C produces data
D destroys data

Answer
1 => A

 container structure

structure diagram

 singleton collection

 set of doubles

 Real-time effect feedback

1. Which of the following interfaces is not a container interface?
A List
B Set
C Map
D Comparable

Answer
1 => D

 singleton collection


Collection interface introduction

Collection represents a group of objects, which means concentration and collection. The two sub-interfaces of the Collection interface are the List and Set interfaces.

 

 Methods defined in the Collection interface

method  illustrate
boolean add(Object element) add element to container
boolean remove(Object element) remove element from container
boolean contains(Object element) Whether the element is contained in the container
int size() the number of elements in the container
boolean isEmpty() whether the container is empty
void clear() Clear all elements in the container
Iterator iterator() Get an iterator for traversing all elements
boolean containsAll(Collection c) Whether this container contains all the elements in the c container
boolean addAll(Collection c) Add all elements in container c to this container
boolean removeAll(Collection c) Remove the elements contained in both this container and container c
boolean retainAll(Collection c) Get the elements contained in both this container and container c, and remove non-intersecting elements
Object[] toArray() Convert to an Object array

Since List and Set are subinterfaces of Collection, it means that all implementation classes of List and Set have the above methods.

After JDK8, the new method of Collection interface (will be introduced in JDK new features and functional programming):

new method  illustrate
removeIf The function is to delete all elements in the container that meet the conditions specified by the filter
stream
parallelStream
stream and parallelStream respectively return the Stream view representation of the container, the difference is that parallelStream() returns a parallel Stream, which is the core class of Java functional programming
spliterator Dividable iterator, unlike previous iterators that require sequential iteration, Spliterator can be divided into several small iterators for parallel operation, which can realize multi-threaded operation and improve efficiency

Real-time effect feedback 

1. Which of the following interfaces is not a subinterface of the Collection interface?
A List
B Set
C Map
D Queue

Answer
1 => C

List interface introduction

 List interface features

List is an ordered, repeatable container.

Ordered : Ordered (the order in which elements are stored in the collection is the same as the order in which they are taken out). Each element in the List has an index mark. These elements can be precisely controlled by accessing elements based on their index tag (position in the List).

Repeatable : List allows repeated elements to be added. More precisely, List usually allows elements satisfying e1.equals(e2) to be repeatedly added to the container.

Common methods in the List interface

In addition to the methods in the Collection interface, List has more methods related to order (index), see the following table:

 

 Basic use of ArrayList container

 Basic use of ArrayList container

 ArrayList is the implementation class of List interface. It is the specific implementation of the List storage feature. The bottom layer of ArrayList is storage implemented by arrays. Features: High query efficiency, low addition and deletion efficiency, and thread insecurity.

public class ArrayListTest {
    public static void main(String[] args) {
        //实例化ArrayList容器
        List<String> list  = new ArrayList<>();
        //添加元素
        boolean flag1 = list.add("oldlu");
        boolean flag2 = list.add("itbz");
        boolean flag3 = list.add("sxt");
        boolean flag4 = list.add("sxt");
        System.out.println(flag1+"\t"+flag2+"\t"+flag3+"\t"+flag4);
        //删除元素
        boolean flag4 = list.remove("oldlu");
        System.out.println(flag4);
        //获取容器中元素的个数
        int size = list.size();
        System.out.println(size);
        //判断容器是否为空
        boolean empty = list.isEmpty();
        System.out.println(empty);
        //容器中是否包含指定的元素
        boolean value = list.contains("itbz");
        System.out.println(value);
        
        
        //清空容器
        list.clear();
        Object[] objects1 = list.toArray();
        System.out.println(Arrays.toString(objects1));
   }
}

Index operation of ArrayList container

public class ArrayListTest2 {
    public static void main(String[] args) {
        //实例化容器
        List<String> list = new ArrayList<>();

        //添加元素
        list.add("oldlu");
        list.add("itbz");

        //向指定位置添加元素
        list.add(0,"sxt");
        System.out.println("获取元素");
        String value1 = list.get(0);
        System.out.println(value1);
        System.out.println("获取所有元素方式一");

        //使用普通for循环
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
         }
        System.out.println("获取所有元素方式二");

        //使用Foreach循环
        for(String str:list){
            System.out.println(str);
       }
       System.out.println("元素替换");
        list.set(1,"kevin");
        for(String str:list){
            System.out.println(str);
       }
        System.out.println("根据索引位置删除元素);
        String value2 = list.remove(1);
        System.out.println(value2);
        System.out.println("----------------");
        for(String str:list){
            System.out.println(str);
       }
        System.out.println("查找元素第一次出现的位置");
        int value3 = list.indexOf("sxt");
        System.out.println(value3);
        System.out.println("查找元素最后一次出现的位置");
        list.add("sxt");
        for(String str:list){
            System.out.println(str);
       }
        int value4 = list.lastIndexOf("sxt");
        System.out.println(value4);
   }
}

 Union, intersection and difference of ArrayList

union

  //并集操作:将另一个容器中的元素添加到当前容器中
        List<String> a  = new ArrayList<>();
        a.add("a");
        a.add("b");
        a.add("c");

        List<String> b = new ArrayList<>();
        b.add("a");
        b.add("b");
        b.add("c");
        //a并集b
        a.addAll(b);
        for(String str :a){
            System.out.println(str);
       }

intersection

        //交集操作:保留相同的,删除不同的
        List<String> a1  = new ArrayList<>();
        a1.add("a");
        a1.add("b");
        a1.add("c");

        List<String> b1 = new ArrayList<>();
        b1.add("a");
        b1.add("d");
        b1.add("e");
        
        //交集操作
        a1.retainAll(b1);
        for(String str :a1){
            System.out.println(str);
       }

difference set

         //差集操作:保留不同的,删除相同的
        List<String> a2  = new ArrayList<>();
        a2.add("a");
        a2.add("b");
        a2.add("c");

        List<String> b2= new ArrayList<>();
        b2.add("b");
        b2.add("c");
        b2.add("d");
        a2.removeAll(b2);
        for(String str :a2){
            System.out.println(str);
       }

ArrayList source code analysis

The bottom layer of ArrayList is storage implemented by arrays.

Member variables

/**
* Default initial capacity.
*/
   private static final int DEFAULT_CAPACITY = 10;
/**
* The array buffer into which the elements of the ArrayList are stored.
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/

transient Object[] elementData; // nonprivate to simplify nested class access


/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/

private int size;

array initial size

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;

add element

/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  //Increments modCount!!
    elementData[size++] = e;
    return true;
}

Determine whether the array is expanded

//容量检查
private void ensureCapacityInternal(int minCapacity) {  
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//容量确认
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //判断是否需要扩容,数组中的元素个数-数组长度,如果大于0表明需要扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

Array expansion

/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
  // overflow-conscious code
    int oldCapacity = elementData.length;
  //扩容1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData,newCapacity);
}

Basic use of Vector containers

The bottom layer of Vector is implemented with an array, and the related methods have added synchronization checks, so it is "thread-safe and low-efficiency". For example, the indexOf method adds a synchronized synchronization flag.

 

 Use of Vector

The use of Vector is the same as that of ArrayList, because they both implement the List interface and implement the abstract methods in the List interface.

public class VectorTest {
    public static void main(String[] args) {
        //实例化Vector
        List<String> v = new Vector<>();
        v.add("a");
        v.add("b");
        v.add("a");
        for(int i=0;i<v.size();i++){
            System.out.println(v.get(i));
       }
        System.out.println("----------------------");
        for(String str:v){
            System.out.println(str);
       }
   }
}

Vector source code analysis

Member variables

/**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/

protected Object[] elementData;

    /**
     * The number of valid components in this {@code Vector} object.
     * Components {@code elementData[0]} through
     * {@code elementData[elementCount-1]} are the actual items.
     *
     * @serial
     */

protected int elementCount;
    
    /**
     * The amount by which the capacity of the vector is automatically
     * incremented when its size becomes greater than its capacity. If
     * the capacity increment is less than or equal to zero, the capacity
     * of the vector is doubled each time it needs to grow.
     *
     * @serial
     */
protected int capacityIncrement;

Construction method

public Vector() {
    this(10);
}

add element

/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

Array expansion

/**
* This implements the unsynchronized semantics of ensureCapacity.
* Synchronized methods in this class can internally call this
* method for ensuring capacity without incurring the cost of an
* extra synchronization.
*
* @see #ensureCapacity(int)
*/

private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
   //判断是否需要扩容,数组中的元素个数-数组长度,如果大于0表明需要扩容
    
if (minCapacity - elementData.length >0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;

   //扩容2倍
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);

    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

Guess you like

Origin blog.csdn.net/m0_58719994/article/details/131669654