[Java Basics] Collection

1. Collection overview

In order to facilitate the storage and operation of multiple objects, a collection is a Java container that can dynamically put multiple object references into the container

Features of array storage

  • Once initialized, the length cannot be changed, and the element type cannot be changed
  • There are few methods provided, which is very inconvenient for operations such as adding, deleting, and obtaining the actual number of elements
  • orderly, repeatable

two systems of sets

  • Collection interface : a single column of data, which defines a collection of methods for accessing a group of objects.
    • List: an ordered, repeatable collection
    • Set: unordered, non-repeatable collection
  • Map interface : double-column data, saving a set of "key-value" key-value pairs with a mapping relationship
    insert image description here

insert image description here

2. Collection interface

common method

public class CollectionTest {
    
    
	@Test
	public void test1(){
    
    
		Collection col1 = new ArrayList();

		// add(Object o)	添加元素
		col1.add("wanfeng");
		col1.add("jingyu");
		col1.add(123);

		// size()	元素个数
		System.out.println("col size = "+col1.size());

		// addAll(Collection c)	添加集合中的所有元素
		Collection col2 = new ArrayList();
		col2.add(false);
		col2.add(34.56);
		col2.add(29);
		col2.add("wanwan");
		Student s1 = new Student("wanfeng", 12);
		col2.add(s1);
		col1.addAll(col2);
		System.out.println(col1);

		// isEmpty()	判断集合是否有元素
		System.out.println(col1.isEmpty());

		// clear()	清空所有元素
		col1.clear();
		System.out.println(col1);

		// contains()	元素是否存在,ArrayList源码中调用的是Object类的equals方法(==比较地址值),
		// 若要比较内容需要在类中重写equals方法
		System.out.println(col2.contains(34.56));
		System.out.println(col2.contains("wanfeng"));
		System.out.println(col2.contains(s1));
		System.out.println(col2.contains(new Student("wanfeng", 12)));

		// containsAll()	集合中的元素是否全部存在
		Collection col3 = new ArrayList();
		col3.add("wanwan");
		col3.add(false);
		System.out.println(col2.containsAll(col3));

		// remove(Object o)	删除指定元素 若为自定义类也需要重写equals方法
		System.out.println(col2.remove("fengfeng"));
		System.out.println(col2.remove(new Student("wanfeng", 12)));

		// removeAll(Collection c) 删除c中包含的所有元素
		System.out.println(col2.removeAll(col3));
		System.out.println(col2);

		//retainAll(Collection c) 取交集
		Collection col4 = new ArrayList();
		col4.add(34.56);
		col4.add(true);
		col2.retainAll(col4);
		System.out.println(col2);

		// equals(Object o)	比较两个集合是否相同
		col2.add(true);
		Collection col5 = new ArrayList();
		col5.add(true);
		col5.add(34.56);
		System.out.println(col2.equals(col5));

		// hashCode()	返回哈希值
		System.out.println(col2.hashCode());

		// toArray()	转换为数组
		Object[] arr = col2.toArray();
		for(int i=0; i<arr.length; i++){
    
    
			if(i > 0) System.out.print(" ");
			System.out.print(arr[i]);
		}
		System.out.println();
		
		// Arrays.asList()数组转换为集合
		List<Object> list = Arrays.asList(arr);
		System.out.println(list);

		// iterator()	返回迭代器,用于集合遍历
	}

}

class Student{
    
    
	private String name;
	private int id;

	public Student() {
    
    
	}

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

	@Override
	public boolean equals(Object o) {
    
    
		System.out.println("Student.equals([o]): 执行成功~");
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		Student student = (Student) o;

		if (id != student.id) return false;
		return name != null ? name.equals(student.name) : student.name == null;
	}
}

iterator iterator

The Iterator object is called an iterator, which is mainly used to traverse the elements in the Collection collection. Iterator provides a way to access the individual elements of a container object without exposing the internal details of the object. The iterator pattern is born for containers.

/*
iterator()	返回迭代器,用于集合遍历
    iterator.next()		迭代器后移,并返回当前指向元素(未开始遍历时指向第一个元素的前面)
    iterator.hasNext() 	后面是否存在元素
*/
Iterator iterator = col2.iterator();
while (iterator.hasNext()){
    
    
    System.out.println(iterator.next());
}

foreach traverse

Collection col2 = new ArrayList();
col2.add(false);
col2.add(34.56);
col2.add(29);
col2.add("wanwan");
col2.add("jingyu");

//本质也是用了iterator
//item是元素的拷贝,而不是元素本身
for(Object item : col2){
    
    
    System.out.println(item);
}

3. List interface

The List interface stores ordered, repeatable elements.

List interface implementation class

The same point: all three classes implement the List interface, and the characteristics of storing data are all ordered and repeatable

difference:

  • ArrayList: The main implementation class of List. Thread unsafe, high efficiency. The bottom layer uses Object[] storage
  • LinkedList: It is highly efficient when inserting and deleting operations are frequently used, and the bottom layer uses a doubly linked list for storage.
  • Vector: The ancient implementation class of List (JDK1.0). Thread safe, low efficiency. The bottom layer uses Object[] storage

4. ArrayList

Source code analysis: When using the empty parameter constructor ArrayList(), the underlying Object[] elementData is initialized to { }, and call grow for expansion at the first addition. (JDK8)

public class ListTest {
    
    
	@Test
	public void test1(){
    
    
		ArrayList list = new ArrayList(10);
		System.out.println(list.size());
		list.add(11);
		list.add(22);
		list.add(33);
		list.add("wanfeng");
		list.add(new Student("jingyu", 13));
		System.out.println(list);

		// add(int index, Object o)	将元素添加到索引位置
		list.add(1, "feng");
		System.out.println(list);

		// addAll(int index, Collection c)	将集合c中的所有元素添加到索引位置
		Collection col2 = new ArrayList();
		col2.add(false);
		col2.add(34.56);
		col2.add(22);
		col2.add("wanwan");
		col2.add("jingyu");
		list.addAll(2, col2);
		System.out.println(list);

		// size()	元素个数
		System.out.println(list.size());

		// get(int index)	获取索引位置的元素
		System.out.println(list.get(7));

		// indexOf(Object o)	元素首次出现的索引位置,找不到返回-1
		System.out.println(list.indexOf(22));
		System.out.println(list.indexOf(999));

		// lastIndexOf(Object o)	元素最后一次出现的索引位置
		System.out.println(list.lastIndexOf(22));

		// remove(int index) / remove(Object o)	删除元素
		Object remove = list.remove(1);
		list.remove(new Integer(22));
		System.out.println(list);

		// set(int index, Object o)	修改指定位置的元素为o
		list.set(1, new Integer(987));
		System.out.println(list);

		// subList(int start, int end)	返回指定范围的子集合,左闭右开
		List sub = list.subList(2, 8);
		System.out.println(sub);

		// iterator迭代器遍历
		Iterator iterator = list.iterator();
		while(iterator.hasNext()){
    
    
			System.out.println(iterator.next());
		}

		// foreach 增强for循环
		for(Object item : list){
    
    
			System.out.println(item);
		}
	}
}

5. LinkedList

Source code analysis: When using the empty parameter constructor LinkedList(), the bottom layer declares the first and last properties of the Node type, and the default value is null

常用方法与ArrayList基本一致

6. Set interface

Store unordered, non-repeatable data. Unordered is not equal to random. Taking HashSet as an example, when data is added, it is not added in the order of the index, but in the order of the hash value of the data. Non-repeatability means that when the added element is judged according to equals, it cannot return true, that is, only one can be added.

There are no new methods in the Set interface, they are all methods in Collection

In practical applications, Set is often used to filter duplicate data

Set interface implementation class

  • HashSet: The main implementation class of Set, which is not thread-safe and can store null
  • LinkedHashSet: A subclass of HashSet. When traversing, it can be traversed in the order of addition
  • TreeSet: The bottom layer uses red-black tree storage. The stored data must be of the same type and can be sorted according to the specified properties of the added object

Seven, HashSet

The bottom layer is an array (default length 16).

The mechanism of adding elements to HashSet

When adding data, get the hash value and put it into the position specified by the array according to the hash function. If there is an element at this position, compare the hashCode of the two (if the hashCode in the Object class is not rewritten in the class, the hasCode generated by this method is random), if it is different, the addition is successful, and the existing element is in the form of a linked list connect. If the hash values ​​are the same, call the equals method for comparison. If it is false, it means that there are no duplicates and the addition is successful, otherwise the addition fails.
insert image description here

Rules for adding data to Set

  • The class of the added data must rewrite hashCode() and equals()

  • The attributes used in equals are the same as those used in hashCode

Why does the number 31 often appear in the rewriting of hashCode() in the IDEA tool?

When selecting a coefficient, try to choose a larger coefficient, increase the hash address, reduce conflicts, and improve search efficiency. 31 only occupies 5 bits, and the probability of data overflow caused by multiplication is small. i * 31 == (i<<5) - 1, there are related optimizations in many virtual machines. 31 is a prime number, and the result of multiplying other numbers and 31 can only be divisible by the prime number itself and this other number, reducing conflicts.

8. LinkedHashSet

The underlying structure is the same as HashSet, both are arrays, but a doubly linked list structure is added, and when traversing, it is traversed in the form of a linked list instead of an array, so it can be traversed in the order of addition

Nine, TreeSet

The added data must be objects of the same class. After adding, they are automatically sorted. The Comaprable interface needs to be implemented, and the ComapreTo method implemented at the same time is also used to determine whether two elements are duplicated.

  • Natural sorting: implement the Comaprable interface, and the criterion for comparing whether two objects are duplicates is whether compareTo() returns 0
  • Custom sorting: Declare an object of an anonymous subclass of the Comparator interface (implementing the compare method). When the object is used as a parameter of the TreeSet constructor, the TreeSet will use the compare method to compare whether the two objects are duplicates
public class SetTest {
    
    
    // Tree自然排序
	@Test
	public void test3(){
    
    
		TreeSet set1 = new TreeSet();
		set1.add(10);
		set1.add(34);
		set1.add(6);
		set1.add(18);
		set1.add(-9);
		for(Iterator iterator= set1.iterator(); iterator.hasNext(); ){
    
    
			System.out.println(iterator.next());
		}

		TreeSet studentSet = new TreeSet();

		// Student需要实现Comparable接口
		studentSet.add(new Student("wanfeng", 12));
		studentSet.add(new Student("jingyu", 20));
		studentSet.add(new Student("wanwan", 15));
		studentSet.add(new Student("jingjing", 13));
		studentSet.add(new Student("jingjing", 34));
		for(Iterator iterator= studentSet.iterator(); iterator.hasNext(); ){
    
    
			System.out.println(iterator.next());
		}
	}

    // TreeSet定制排序
	@Test
	public void test4(){
    
    
		Comparator comparator = new Comparator() {
    
    
			@Override
			public int compare(Object o1, Object o2) {
    
    
				if(o1 instanceof Student && o2 instanceof Student){
    
    
					Student s1 = (Student) o1;
					Student s2 = (Student) o2;
					return s1.getId() - s2.getId();
				}else{
    
    
					throw new RuntimeException("类型不一致");
				}
			}
		};

		// 以comparator比较器作为比较标准
		TreeSet studentSet = new TreeSet(comparator);

		studentSet.add(new Student("wanfeng", 12));
		studentSet.add(new Student("jingyu", 20));
		studentSet.add(new Student("wanwan", 15));
		studentSet.add(new Student("jingjing", 13));
		studentSet.add(new Student("jingjing", 34));

		for(Iterator it=studentSet.iterator(); it.hasNext(); ){
    
    
			System.out.println(it.next());
		}
	}
}

10. Map interface

Store key-value pairs (key-value)

Map interface implementation class

  • HashMap: the main implementation class of the Map interface; thread unsafe, high efficiency; can store null
    • LinkedHashMap: A subclass of HashMap. A linked list structure is added on the basis of HashMap, which is traversed in the order of addition. For frequent traversal operations, the efficiency is better than HashMap
  • TreeMap: Sorting when adding key-value pairs (natural sorting by key sorting, custom sorting). The bottom layer uses a red-black tree
  • Hashtable: an ancient implementation class of the Map interface; thread-safe, low efficiency; cannot store null
    • Properties: processing configuration files, key-value are String type

Map common method (HashMap)

@Test
public void test2(){
    
    
    Map map1 = new HashMap();

    // put(Object key, Object value)	添加键值对
    map1.put("BB", 12);
    map1.put("AA", 23);
    map1.put("CC", 34);
    System.out.println(map1);

    // putAll(Map m)	将m中的键值对全部添加
    Map map2 = new HashMap();
    map2.put("wanfeng", 23);
    map2.put("jingyu", 21);
    map1.putAll(map2);
    System.out.println(map1);

    // remove(Object key)	根据key删除键值对,返回value
    Object remove_value = map1.remove("AA");
    System.out.println("remove_value: "+remove_value);
    System.out.println(map1);

    // clear()	删除所有键值对
    map2.clear();
    System.out.println("map2 size: "+map2.size());
    System.out.println(map2);

    // get(Object key)	获取key对应的value
    Object get_value = map1.get("wanfeng");
    System.out.println("get_value: "+get_value);

    // containsKey(Object key)	是否包含key
    System.out.println(map1.containsKey("jingyu"));

    // containsValue(Object value)	是否包含value
    System.out.println(map1.containsValue(23));

    // size()	获取键值对个数
    System.out.println("map1 size: "+map1.size());

    // isEmpty()	map是否为空
    System.out.println(map1.isEmpty());
    System.out.println(map2.isEmpty());

    // equals(Map m)	判断两个map是否相同
    System.out.println(map1.equals(map2));
}

Map traversal (HashMap)

@Test
public void test3(){
    
    
    Map map1 = new HashMap();
    map1.put("BB", 12);
    map1.put("AA", 23);
    map1.put("CC", 34);
    System.out.println(map1);

    // 遍历key:拿到keySet再用iterator遍历
    Set keyset = map1.keySet();
    for(Iterator it=keyset.iterator(); it.hasNext(); ){
    
    
        System.out.println(it.next());
    }

    // 遍历value,拿到Collection,再用iterator或增强for循环遍历
    Collection values = map1.values();
    for(Object value : values){
    
    
        System.out.println(value);
    }

    // 第一种方式:遍历key-value拿到EntrySet,使用iterator遍历,
    // 每一个Entry调用 getKey() 和 getValue() 获取。
    // 第二种方式,遍历key的时候调用get(Object key)同时遍历value
    Set entrySet = map1.entrySet();
    for(Iterator it=entrySet.iterator(); it.hasNext(); ){
    
    
        Object o = it.next();
        Map.Entry entry = (Map.Entry) o;
        System.out.println(entry.getKey() + " --> " + entry.getValue());
    }

}

Eleven, HashMap

Before JDK7, the underlying structure was an array + linked list, and after JDK8, a red-black tree was added

Map structure

  • key: unordered, non-repeatable, use Set to store all keys (the class where the key belongs to should rewrite hashCode and equals)
  • value: unordered, repeatable, use Collection to store all keys
  • key-value: an Entry object, unordered and non-repeatable, use Set to store all Entry

insert image description here

The underlying implementation principle of HashMap

JDK7

  • After creating the HashMap object, the underlying layer creates an array Entry[] table with a length of 16
  • put(key1, value1) When adding a key-value pair, call the hashCode of the class where key1 belongs to get the hash value and get the storage location of this Entry through indexFor (and the array length -1 operation). If there is no data in this location, the addition is successful. If there is already data at this location, compare the hash value of key1 with the hash value of the existing data
    • If the hash values ​​are not the same, the addition is successful (linked list storage)
    • If the hash values ​​are the same, call equals for comparison
      • If it returns false, the addition is successful (linked list storage)
      • If true, replace the value of the existing data with value1
  • In the process of continuous addition, when the threshold value (threshold) is exceeded and there are already elements in the added position, the capacity will be doubled to the original

JDK8

  • After creating the HashMap object, the underlying layer does not create an array of length 16
  • The type of the array is Node[], not Entry[]
  • When the put method is called for the first time, the underlying layer creates an array with a length of 16
  • When the number of elements at an index position (linked list) of the array is > 8 and the current array length is > 64, the linked list at this index position is changed to red-black tree storage
  • Constants and variables in HashMap
    • DEFAULT_INITIAL_CAPACITY = 16: default capacity
    • DEFAULT_LOAD_FACTOR = 0.75: default load factor
    • threshold: expansion threshold = capacity * load factor
    • TREEIFY_THRESHOLD = 8: When the length of the linked list in the Bucket is greater than the default value, it will be converted into a red-black tree
    • MIN_TREEIFY_CAPACITY = 64: The minimum hash table capacity when the linked list is converted into a red-black tree

insert image description here

12. LinkedHashMap

Unlike HashMap when adding data, when adding key-value pairs to an array or a linked list, a new Entry object is created (rewriting the newNode method of HashMap), this Entry class has two pointers before and after pointing to the front and back elements, forming a doubly linked list.

insert image description here

Thirteen, TreeMap

Adding key-value to TreeMap requires that the keys must all be objects of the same class, because they must be sorted according to the key (natural sorting, custom sorting)

void showTreeMap(TreeMap tm){
    
    
    if(tm == null)	return;
    Set keyset = tm.keySet();
    for(Iterator it=keyset.iterator(); it.hasNext(); ){
    
    
        Student key = (Student) it.next();
        System.out.println(key + " --> " + tm.get(key));
    }
}

@Test
public void TreeMapTest(){
    
    
    //自然排序
    TreeMap map1 = new TreeMap();
    map1.put(new Student("wanfeng", 23), 11);
    map1.put(new Student("jingyu", 21), 55);
    map1.put(new Student("wanwan", 25), 44);
    map1.put(new Student("fengfeng", 18), 22);
    showTreeMap(map1);

    //定制排序(与TreeSet原理相同,此处用的是Comparator接口的匿名实现类的匿名对象)
    TreeMap map2 = new TreeMap(new Comparator() {
    
    
        @Override
        public int compare(Object o1, Object o2) {
    
    
            if(o1 instanceof Student && o2 instanceof Student){
    
    
                Student s1 = (Student) o1;
                Student s2 = (Student) o2;
                // name倒序
                return -s1.getName().compareTo(s2.getName());
            }
            throw new RuntimeException("类型不匹配");
        }
    });
    map2.put(new Student("wanfeng", 23), 11);
    map2.put(new Student("jingyu", 21), 55);
    map2.put(new Student("wanwan", 25), 44);
    map2.put(new Student("fengfeng", 18), 22);
    showTreeMap(map2);
}

14. Properties

A subclass of Hashtable that handles property files. Key-value pairs are of String type

@Test
public void propertiesTest(){
    
    
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
    
    
        Properties properties = new Properties();
        // 得到文件输入流
        fis = new FileInputStream("src/com/lzh/Map/mypro.properties");
        // 将文件输入流加载进Properties对象中
        properties.load(fis);
        // 获取属性
        System.out.println(properties.getProperty("username"));
        System.out.println(properties.getProperty("password"));

        //设置属性
        properties.setProperty("id", "27");
        fos = new FileOutputStream("src/com/lzh/Map/mypro.properties");

        properties.store(fos, "comment");
    } catch (IOException e) {
    
    
        e.printStackTrace();
    } finally {
    
    
        try {
    
    
            if(fis != null)	fis.close();
            if(fos != null) fos.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
}

15. Collections tool class

@Test
public void test1(){
    
    
    ArrayList list = new ArrayList(10);
    list.add("wanfeng");
    list.add("zhipeng");
    list.add("jingyu");
    list.add("xinxin");
    System.out.println(list.size());
    System.out.println(list);

    //reverse(list)	反转List
    Collections.reverse(list);
    System.out.println("reverse: " + list);

    // shuffle(list)	随机排序List
    Collections.shuffle(list);
    System.out.println("shuffle: "+ list);

    // sort(list)	自然排序,升序
    Collections.sort(list);
    System.out.println("自然排序:"+list);

    // sort(list, Comparator c)	定制排序
    Collections.sort(list, new Comparator<Object>() {
    
    
        @Override
        public int compare(Object o1, Object o2) {
    
    
            if(o1 instanceof String && o2 instanceof String){
    
    
                String s1 = (String) o1;
                String s2 = (String) o2;
                return -s1.compareTo(s2);
            }
            throw new RuntimeException("类型不匹配");
        }
    });
    System.out.println("定制排序:"+list);

    // swap(index1, index2)	交换两个索引位置的元素
    Collections.swap(list, 0, 2);
    System.out.println("swap:"+list);

    // max(Collection)	获取最大值(自然排序)
    // max(Collection, Comparator)	获取最大值(定制排序)
    // min(Collection)	获取最小值(自然排序)
    // min(Collection, Comparator)	获取最小值(定制排序)

    //frequency(Collection, Object)	返回集合中指定元素的出现次数
    System.out.println(Collections.frequency(list, "wanfeng"));

    // copy(List list1, List list2)	将list2对应索引位置的元素复制到list1中
    // 		list2.size() > list1.size()	抛出IndexOutOfBoundsException
    ArrayList list2 = new ArrayList();
    list2.add("345");
    list2.add("111");
    Collections.copy(list, list2);
    System.out.println(list);

    // replaceAll(List list, Object oldVal, Object newVal)	将list中的所有旧值改为新值
    Collections.replaceAll(list, "zhipeng", "newval");
    System.out.println(list);

    // Collection同步控制
    // synchronizedCollection(Collection)
    // synchronizedList(List)	ArrayList线程不安全
    // synchronizedMap(Map)		HashMap线程不安全
    List syncList = Collections.synchronizedList(list);	//返回线程安全的List
}

Guess you like

Origin blog.csdn.net/Dae_Lzh/article/details/130510536