Java learning record (intermediate)-[3], collection framework

First, let’s take a simplified diagram of the collection framework: ↓ ↓ ↓ 

(1), Collection interface

Collection is the parent interface of List , Set , Queue (first in first out queue) , Deque (double linked list) and other interfaces.

[Note: There is no relationship between Collection and Map. Collection contains objects one by one, and Map contains key-value pairs.]
[Note: Deque inherits Queue and indirectly inherits Collection]

(2), Collections class

Collections is a class, a tool class for containers, just like Arrays is a tool class for arrays, it can also perform some operations on the container.

Method name keywords Features
reverse Reverse
shuffle Confusion (disorder the order)
sort Sort
swap Exchange data at the specified subscript position
rotate Scroll the data in the collection to the right by the length of the specified unit
synchronizedList Convert non-thread-safe collections to thread-safe collections
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollectionsTest {

	public static void main(String[] args) {
		// 初始化List
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i < 10; i++) {
			list.add(i+1);
		}
		// 原List
		System.out.println("原list:\t\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 反转
		Collections.reverse(list);
		System.out.println("反转后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 混淆
		Collections.shuffle(list);
		System.out.println("混淆后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 排序
		Collections.sort(list);
		System.out.println("排序后的list:\t\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 交换两个位置的数据
		Collections.swap(list, 0, 1);
		System.out.println("交换0和1下标的数据后的list:\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 先恢复原list
		Collections.swap(list, 0, 1);
		System.out.println("恢复后的list:\t\t" + list);
		// 滚动
		Collections.rotate(list, 3);
		System.out.println("向右滚动3个单位后的list:\t" + list);
		
		
		
		System.out.println("******************************");
		
		
		
		// 线程安全化
		List<Integer> newList = Collections.synchronizedList(list);
		// 把原来不是线程安全的list转换为了现在线程安全的newList
		
	}
	
}

Output result:

(3) List interface and ArrayList class

The objects in the List collection are arranged in a certain order, and the contents inside can be repeated;

The classes implemented by the List interface are: ArrayList (to implement dynamic arrays) , Vector (to implement dynamic arrays) , LinkedList (to implement linked lists) , Stack (to implement stacks) .

[1], the limitations of using arrays

If you want to store multiple objects, you can use arrays, but arrays have limitations! ! !

For example: if you declare an array with a length of 10, the unused array will be wasted, and the number of more than 10 will not fit! ! !

[2]、ArrayList

In order to solve the limitations of arrays, the concept of container classes is introduced. The most common container class is: The capacity "capacity" of the ArrayList 
container will automatically increase as the object increases.

[3] Common methods of ArrayList

Method name keywords Features
contains Determine if it exists
add Add object
addAll Add all objects in another container
remove Delete object
clear Empty
set Replace the object at a certain position (reassignment)
get Get the object at the specified location
indexOf Get the location of the object
toArray Convert to array
size Get size

[4], iterator traversal

Use Iterator to traverse the elements in the collection , the principle is as follows: ↓ ↓ ↓ 

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

public class IteratorTest {

	public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        
        for (int i = 0; i < 5; i++) {
			list.add("String " + i);
		}
        System.out.println("最初的list为:" + list);
        
        // 获取List的迭代器
        Iterator<String> iterator = list.iterator();
        
        //从最开始的位置判断"下一个"位置是否有数据
        //如果有就通过next取出来,并且把指针向下移动
        //直到"下一个"位置没有数据
        
        System.out.println("--------使用while的iterator-------");
        // 利用while循环遍历
        while(iterator.hasNext()) {
        	String str = iterator.next();
        	System.out.println(str);
        }
        
        System.out.println("--------使用for的iterator-------");
        // 利用for循环遍历
        for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
			String str = it.next();
			if(str.equals("String 2")) {
				it.remove();
				System.out.println(str + "(当字符串为“String 2”时从迭代器中删除它)");
			}else {
				System.out.println(str);
			}
		}
        System.out.println("删除“String 2”后的list为:" + list);
        
         
    }

}

Output result:

You can use iterators to delete elements in the list.

(4)、LinkedList

The sequence is divided into: first-in first-out FIFO , first- in -last-out FILO 
FIFO is also called Queue 
in Java, FILO is also called Stack in Java

[1] Like ArrayList, LinkedList also implements the List interface;

[2] But at the same time, LinkedList not only implements the List interface, but LinkedList also implements a doubly linked list structure Deque, which can easily insert and delete data at the beginning and end;

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

public class CollectionsTest {
	
	public static void main(String[] args) {
        
        //LinkedList是一个双向链表结构的list
        LinkedList<String> list =new LinkedList<>();
         
        //所以可以很方便的在头部和尾部插入数据
        //在最后插入新的字符串
        list.addLast("String 1");
        list.addLast("String 2");
        list.addLast("String 3");
        System.out.println("加入数据后的list:\t\t" + list);
         
        //在最前面插入新的字符串
        list.addFirst("String X");
        System.out.println("最前面插入新的字符串后的list:\t" + list);
         
        //查看最前面的字符串
        System.out.println("最前面的字符串:\t\t " + list.getFirst());
        //查看最后面的字符串
        System.out.println("最后面的字符串:\t\t " + list.getLast());
         
        //查看不会导致元素被删除
        System.out.println("再次查看list:\t\t" + list);
        //取出最前面的字符串
        System.out.println("取出来的最前面的字符串:\t " + list.removeFirst());
         
        //取出最后面的字符串
        System.out.println("取出来的最后面的字符串:\t " + list.removeLast());
         
        //取出会导致元素被删除
        System.out.println("再次查看list:\t\t" + list);
         
    }
	
}

Output result:

[3] In addition to implementing List and Deque , LinkedList also implements the Queue interface (queue)

Queue is a first-in-first-out queue FIFO, commonly used methods:

offer        在最后添加元素
poll         取出第一个元素
peek         查看第一个元素
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class CollectionsTest {

	public static void main(String[] args) {

		// 和ArrayList一样,LinkedList也实现了List接口
		List<String> list = new LinkedList<>();

		// 同时,LinkedList还实现了Deque接口
		// Deque代表双向链表
		Deque<String> deque = new LinkedList<>();

		// 同时,LinkedList也实现了Queue这个接口
		// Queue代表FIFO 先进先出的队列
		Queue<String> queue = new LinkedList<>();

		for (int i = 0; i < 2; i++) {
			queue.offer("String " + i); // 在最后添加元素
		}
		for (int i = 0; i < 3; i++) {
			queue.add("String " + (i + 2)); // 与offer()同样的效果,添加元素
		}    //
		System.out.println("利用offer()方法或add()方法添加元素。");
		System.out.println("添加元素后的queue为:\t" + queue);
		System.out.println();

		String first = queue.peek();    //
		System.out.println("利用peek()方法查看第一个元素。");
		System.out.println("查看第一个元素:\t\t " + first);
		System.out.println();

		queue.poll();    //
		System.out.println("利用poll()方法取出第一个元素。");
		System.out.println("取出第一个元素......");
		System.out.println("第一个元素取出后的queue为:\t" + queue);

	}

}

Output result:

(5) Binary tree

The binary tree is composed of various nodes. The characteristics of the
binary tree:
       each node can have a left child node, a right child node, and a value.

public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
    // 值
    public Object value;
}

[1], Binary Tree-Insert Data-Principle:

Suppose that the following 10 random numbers are sorted through a binary tree
67, 7, 30, 73, 10, 0, 78, 81, 10, 74.
The first step of sorting is to insert data into the binary tree. The
basic logic for inserting is, small , The same place on the left, the larger on the right
1. 67 on the root node
2. 7 is smaller than 67, the left node on 67 is
3. 30 is smaller than 67, the left node of 67 is found, and 30 is greater than 7, then Place the right node of
7. 4. 73 is greater than 67, place the right node of
67, 5. 10 is smaller than 67, find the left node of 67, 10 is greater than 7, and find the right node of 7, 30, 10 is smaller than 30, Place it on the left node of 30.
...
...
9.10 less than the 67 to find left node 67 7,10 larger than 7, find the right node 7 of 30, 10 than 30 hours to find the left node 30 as large as 10, 10 and 10, Put on the left

public class Node {

	/**
	 * 左子节点
	 */
	public Node leftNode;
	/**
	 * 右子节点
	 */
	public Node rightNode;
	/**
	 * 值
	 */
	public Object value;

	/**
	 * 插入数据
	 * @param v
	 */
	public void add(Object v) {
		// 如果当前节点没有值,就把数据放在当前节点上
		if (value == null) {
			value = v;
		} else { // 如果当前节点有值,就进行判断,新增的值与当前的值的大小关系
			// 新增的值,比当前值小或者相同
			if ((Integer) value - (Integer) v >= 0) {
				if (leftNode == null) {
					leftNode = new Node();
				}
				leftNode.add(v);
			}
			// 新增的值,比当前值大
			else {
				if (rightNode == null) {
					rightNode = new Node();
				}
				rightNode.add(v);
			}
		}
	}

	public static void main(String[] args) {

		int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
		Node roots = new Node();
		for (int number : randoms) {
			roots.add(number);
		}

	}

}

[2], Binary tree-traversal:

Through the insertion behavior of the previous step, the data is actually sorted. The next thing to do is to see, traverse these sorted data into our commonly used List or array form.

Binary tree traversal is divided into first order, middle order, and second order
[first order] ie: the middle number after traversal Put it on the left
[Middle Order]: The middle number is traversed and placed in the middle
[Post Order]: The middle number is traversed and placed on the right

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

public class Node {

	/**
	 * 左子节点
	 */
	public Node leftNode;
	/**
	 * 右子节点
	 */
	public Node rightNode;
	/**
	 * 值
	 */
	public Object value;

	/**
	 * 插入数据
	 * @param v
	 */
	public void add(Object v) {
		// 如果当前节点没有值,就把数据放在当前节点上
		if (value == null) {
			value = v;
		} else { // 如果当前节点有值,就进行判断,新增的值与当前的值的大小关系
			// 新增的值,比当前值小或者相同
			if ((Integer) value - (Integer) v >= 0) {
				if (leftNode == null) {
					leftNode = new Node();
				}
				leftNode.add(v);
			}
			// 新增的值,比当前值大
			else {
				if (rightNode == null) {
					rightNode = new Node();
				}
				rightNode.add(v);
			}
		}
	}

	// 先序遍历所有的节点
	public List<Object> valuesOfLeft() {
		
		List<Object> values = new ArrayList<>();
		
		// 当前节点
		values.add(value);
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfLeft());
		}
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfLeft());
		}
		
		return values;
		
	}

	// 中序遍历所有的节点
	public List<Object> valuesOfCenter() {
		
		List<Object> values = new ArrayList<>();
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfCenter());
		}
		
		// 当前节点
		values.add(value);
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfCenter());
		}
		
		return values;
		
	}

	// 后序遍历所有的节点
	public List<Object> valuesOfRight() {
		
		List<Object> values = new ArrayList<>();
		
		// 左节点的遍历结果
		if (leftNode != null) {
			values.addAll(leftNode.valuesOfRight());
		}
		
		// 右节点的遍历结果
		if (rightNode != null) {
			values.addAll(rightNode.valuesOfRight());
		}
		
		// 当前节点
		values.add(value);
		
		return values;
		
	}

	public static void main(String[] args) {

		int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
		Node roots = new Node();
		for (int number : randoms) {
			roots.add(number);
		}

		System.out.println("先序遍历的二叉树:\t" + roots.valuesOfLeft());
		System.out.println("中序遍历的二叉树:\t" + roots.valuesOfCenter());
		System.out.println("后序遍历的二叉树:\t" + roots.valuesOfRight());

	}

}

Output result:

(6)、HashMap

The way HashMap stores data is-key-value pairs

For HashMap, the key is unique and cannot be repeated. 
Therefore, inserting different values ​​into the Map with the same key will cause the old elements to be overwritten, leaving only the last inserted element. 
However, the same object can be inserted into the map as a value, as long as the corresponding key is different

(7)、HashSet

Elements in Set cannot be repeated

[1], no order

The elements in the set have no order. 
Strictly speaking,

the specific order of the HashSet is not arranged in the order of insertion of the elements , neither in the order of insertion nor in the order of hashcode.

In other words, the same is to insert 0-9 into HashSet, and the order of seeing is different in different versions of JVM.

import java.util.HashSet;

public class HashSetTest {

	public static void main(String[] args) {

		HashSet<String> set = new HashSet<>();
		
		set.add("hello");
		set.add("world");
		set.add("!!!");
		
		System.out.println(set);
		
	}

}

operation result:

[2], Traverse

Set does not provide get() to get the element at the specified position, 
so iterators or enhanced for loops are needed for traversal

[3] The relationship between HashSet and HashMap

By observing the source code of HashSet, it
can be found that HashSet itself does not have an independent implementation, but a Map is encapsulated in it.
HashSet exists as the key of the Map
and the value is a static Object object named PRESENT, because it is A class attribute, so there will only be one.

private static final Object PRESENT = new Object();
package collection;

import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, java.io.Serializable {
	// HashSet里封装了一个HashMap
	private HashMap<E, Object> map;

	private static final Object PRESENT = new Object();

	// HashSet的构造方法初始化这个HashMap
	public HashSet() {
		map = new HashMap<E, Object>();
	}

	// 向HashSet中增加元素,其实就是把该元素作为key,增加到Map中
	// value是PRESENT,静态,final的对象,所有的HashSet都使用这么同一个对象
	public boolean add(E e) {
		return map.put(e, PRESENT) == null;
	}

	// HashSet的size就是map的size
	public int size() {
		return map.size();
	}

	// 清空Set就是清空Map
	public void clear() {
		map.clear();
	}

	// 迭代Set,就是把Map的键拿出来迭代
	public Iterator<E> iterator() {
		return map.keySet().iterator();
	}

}

(8)、Set

HashSet Unordered
LinkedHashSet
Sorts according to the insertion order TreeSet from small to large

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;

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

        HashSet<String> numberSet1 =new HashSet<>();
        //HashSet中的数据不是按照插入顺序存放
        numberSet1.add("bbbbb");
        numberSet1.add("aaaaa");
        numberSet1.add("ccccc");
        System.out.println(numberSet1);
          
        LinkedHashSet<String> numberSet2 =new LinkedHashSet<>();
        //LinkedHashSet中的数据是按照插入顺序存放
        numberSet2.add("bbbbb");
        numberSet2.add("aaaaa");
        numberSet2.add("ccccc");
        System.out.println(numberSet2);

        TreeSet<String> numberSet3 =new TreeSet<>();
        //TreeSet 中的数据是进行了排序的
        numberSet3.add("bbbbb");
        numberSet3.add("aaaaa");
        numberSet3.add("ccccc");
        System.out.println(numberSet3);
          
    }

}

operation result:

(9) The difference between ArrayList and LinkedList

ArrayList is the structure of [Sequence List], [Search data fast], [Insert and delete data is slow];
LinkedList is [Linked List] structure, [Search data is slow], [Insert and delete data fast].

(10) The difference between ArrayList and HashSet

ArrayList has order and data can be repeated;
HashSet has no order and data cannot be repeated.

HashSet repetition judgment criterion is:
first look at whether the hashcode is the same.
If the hashcode is different, it is considered different data.
If the hashcode is the same, then compare equals. If equals are the same, it is the same data, otherwise it is different data.

(11) The difference between HashMap and HashTable

 

Both HashMap and Hashtable implement the Map interface, both are key-value pairs to store data.
Difference 1: 
HashMap can store null values,
Hashtable cannot store null values.
Difference 2:
HashMap is not a thread-safe class
Hashtable is a thread-safe class

import java.util.HashMap;
import java.util.Hashtable;

public class MapTableTest {

	public static void main(String[] args) {

		// HashMap 可以存放 null 值
		HashMap<String, Integer> map = new HashMap<>();
		map.put("first", null);
		System.out.println(map);

		// Hashtable 不能存放null 值
		Hashtable<String, Integer> table = new Hashtable<>();
		table.put("first", null);
		System.out.println(table);

	}

}

operation result:

(12) Principle of HashCode

[1], efficiency comparison

The differences brought by HashCode are as follows:

[2], HashCode principle

For example, if you want to find the corresponding Chinese meaning of a word in an English-Chinese dictionary, suppose the word is Lengthdary, first find Lengthdary in the directory on page 555. 

Then, turn to page 555. There is not only one word on this page, but the amount is very small. Compare them one by one, and quickly locate the target word Length.

555 is equivalent to the hashcode corresponding to Lengendary

[3], analyze the reasons for the excellent performance of HashMap

-----Hashcode concept-----
All objects have a corresponding hashcode (hash value). For
example, the string "gareen" corresponds to 1001 (actually not, here is a convenient value for understanding, hypothetical value) ) For
example, the string "temoo" corresponds to 1004. For
example, the string "db" corresponds to 1008. For
example, the string "annie" corresponds to 1008.

-----Save the data -----
Prepare an array whose length is 2000, and set a special hashcode algorithm, so that the hashcode corresponding to all strings will fall between
0 and 999. To store the hero whose name is "gareen", the hero and the name form a key-value pair and store it in
To store the hero whose name is "temoo" in position 1001 of the array, store the hero in position 1004 of the array.
To store the hero whose name is "db", store the hero in position 1008 of the array.
To store the hero whose name is "annie", but there is already a db hero in the location corresponding to the hashcode 1008 of "annie", then create a linked list here and store annie after the db hero

-----find data-- ---For
example, to find gareen, first calculate the hashcode of "gareen" to be 1001, and locate it in the array according to the subscript of 1001. (Locating according to the subscript of the array is very fast). It is found that there is only one position of 1001 Hero, then the hero is gareen.
For example, to find annie, first calculate the hashcode of "annie" to be 1008. According to the subscript of 1008, locate in the array and find that there are two heroes at position 1008, then compare the names of the two heroes one by one (equals) , Because the amount to be compared at this time is much less, and the target hero can be found soon.
This is the use of hashmap for query, which is very fast.


This is a way of thinking that uses space for time

åæHashMapæ§è½åè¶çåå 

[4], HashSet judges whether it is repeated

The data of HashSet cannot be repeated. The same data cannot be stored together. How to judge whether it is repeated?
According to the relationship between HashSet and HashMap, we learned that because HashSet does not have its own implementation, but instead encapsulates a HashMap, it essentially determines whether the key of the HashMap is duplicated.

Through the previous step of learning, whether the key is repeated is judged by two steps:
Whether the hashcode is the same.
        If the hashcode is different, it is in a different pit.
        If the hashcode is the same, it is in the same pit. Also need to compare
                equals. If equals is the same, it is duplicate data.
                If equals is not the same, it is different data.

(13) Comparator

The Collections.sort() method can sort the elements in the collection

However, if there is a collection, the elements in it are all Person type objects, and its attributes are name, age, address, etc., according to which attribute to sort?

This requires a comparator! ! !

[1], Method One

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class ComparatorTest {

	public static void main(String[] args) {

		Random r = new Random();
		List<Person> persons = new ArrayList<>();

		for (int i = 0; i < 10; i++) {
			persons.add(new Person("张" + i, r.nextInt(20) + 20, "西安"));
		}
		System.out.println("初始化后的集合:");
		System.out.println(persons);

		// 直接调用sort会出现编译错误,因为Person有各种属性
		// 到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
		// Collections.sort(persons);

		// 引入Comparator,指定比较的算法
		Comparator<Person> c = new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				// 按照hage进行排序
				if (p1.age >= p2.age)
					return 1; // 正数表示p1比hp2要大
				else
					return -1;
			}
		};
		Collections.sort(persons, c);
		System.out.println("按照年龄排序后的集合:");
		System.out.println(persons);

	}

}

class Person {
	public String name;
	public int age;
	public String address;

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

	@Override
	public String toString() {
		return "\n" + "Name : " + name + "\tAge : " + age + "\tAddress : " + address;
	}

}

Results of the:

[2], method two

Make the Person class implement the Comparable interface
. Provide the comparison algorithm
Collections.sort in the class to have enough information for sorting, and there is no need to provide an additional comparator Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

public class ComparatorTest {

	public static void main(String[] args) {

		Random r = new Random();
		List<Person> persons = new ArrayList<>();

		for (int i = 0; i < 10; i++) {
			persons.add(new Person("张" + i, r.nextInt(20) + 20, "西安"));
		}
		System.out.println("初始化后的集合:");
		System.out.println(persons);

		// 直接调用sort会出现编译错误,因为Person有各种属性
		// 到底按照哪种属性进行比较,Collections也不知道,不确定,所以没法排
		// Collections.sort(persons);

		// 引入Comparator,指定比较的算法
		Comparator<Person> c = new Comparator<Person>() {
			@Override
			public int compare(Person p1, Person p2) {
				// 按照hage进行排序
				if (p1.age >= p2.age)
					return 1; // 正数表示p1比hp2要大
				else
					return -1;
			}
		};
		
		//Person类实现了接口Comparable,即自带比较信息。
        //Collections直接进行排序,无需额外的Comparator
		Collections.sort(persons);
		System.out.println("按照年龄排序后的集合:");
		System.out.println(persons);

	}

}

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

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

	@Override
	public String toString() {
		return "\n" + "Name : " + name + "\tAge : " + age + "\tAddress : " + address;
	}

	@Override
	public int compareTo(Person o) {
		if (age > o.age) {
			return 1;
		}
		return -1;
	}

}

operation result:

Guess you like

Origin blog.csdn.net/qq_37164975/article/details/82688248