Коллекция [Основы Java]

1. Обзор коллекции

Чтобы облегчить хранение и работу с несколькими объектами, коллекция представляет собой контейнер Java, который может динамически помещать в контейнер несколько ссылок на объекты.

Особенности хранения массива

  • После инициализации нельзя изменить длину и тип элемента.
  • Предусмотрено мало методов, что очень неудобно для таких операций, как добавление, удаление и получение фактического количества элементов
  • упорядоченный, повторяемый

две системы наборов

  • Интерфейс коллекции : один столбец данных, определяющий набор методов для доступа к группе объектов.
    • Список: упорядоченная, повторяемая коллекция
    • Набор: неупорядоченный, неповторяемый набор
  • Интерфейс карты : данные в два столбца, сохраняющие набор пар ключ-значение "ключ-значение" с отношением сопоставления.
    вставьте сюда описание изображения

вставьте сюда описание изображения

2. Интерфейс коллекции

общий метод

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 называется итератором, который в основном используется для обхода элементов в коллекции Collection. Итератор предоставляет способ доступа к отдельным элементам объекта-контейнера без раскрытия внутренних деталей объекта. Шаблон итератора создан для контейнеров.

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

для каждого прохода

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, а характеристики хранения данных все упорядочены и повторяемы.

разница:

  • ArrayList: основной класс реализации List. Поток небезопасен, высокая эффективность. Нижний слой использует хранилище Object[]
  • LinkedList: он очень эффективен, когда часто используются операции вставки и удаления, а нижний уровень использует двусвязный список для хранения.
  • Вектор: древний класс реализации List (JDK1.0). Потокобезопасный, низкая эффективность. Нижний слой использует хранилище Object[]

4. Список массивов

Анализ исходного кода: при использовании конструктора пустых параметров ArrayList() базовый элемент Object[] elementData инициализируется { } и вызывает увеличение для расширения при первом добавлении. (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() нижний слой объявляет первое и последнее свойства типа Node, а значение по умолчанию равно null.

常用方法与ArrayList基本一致

6. Установить интерфейс

Храните неупорядоченные, неповторяющиеся данные. Неупорядоченное не равно случайному.В качестве примера возьмем HashSet, когда данные добавляются, они добавляются не в порядке индекса, а в порядке хеш-значения данных. Неповторяемость означает, что когда добавленный элемент оценивается по равенству, он не может вернуть true, то есть может быть добавлен только один.

В интерфейсе Set нет новых методов, все они есть в Collection.

В практических приложениях Set часто используется для фильтрации повторяющихся данных.

Установить класс реализации интерфейса

  • HashSet: основной класс реализации Set, который не является потокобезопасным и может хранить null.
  • LinkedHashSet: подкласс HashSet. При обходе его можно пройти в порядке сложения
  • TreeSet: Нижний слой использует хранилище красно-черного дерева. Сохраняемые данные должны быть одного типа и могут быть отсортированы в соответствии с заданными свойствами добавляемого объекта.

Семь, Хэшсет

Нижний слой представляет собой массив (длина по умолчанию 16).

Механизм добавления элементов в HashSet

При добавлении данных получить хэш-значение и поместить его в позицию, указанную массивом, в соответствии с хеш-функцией. Если в этой позиции есть элемент, сравните hashCode двух (если hashCode в классе Object не перезаписывается в классе, hasCode, сгенерированный этим методом, является случайным), если он отличается, добавление прошло успешно, а существующий элемент находится в виде связанного списка connect. Если значения хэша совпадают, вызываем метод equals для сравнения, если false, то это означает, что дубликатов нет и добавление прошло успешно, иначе добавление не удается.
вставьте сюда описание изображения

Правила добавления данных в Set

  • Класс добавляемых данных должен переписать hashCode() и equals()

  • Атрибуты, используемые в equals, такие же, как и в hashCode.

Почему число 31 часто появляется в переписывании hashCode() в инструменте IDEA?

При выборе коэффициента старайтесь выбирать больший коэффициент, увеличивать хеш-адрес, уменьшать конфликты и повышать эффективность поиска. 31 занимает всего 5 бит, и вероятность переполнения данных, вызванного умножением, мала. i * 31 == (i<<5) - 1, во многих виртуальных машинах есть соответствующие оптимизации. 31 — простое число, и результат умножения других чисел на 31 может делиться только на само простое число и на это другое число, что уменьшает количество конфликтов.

8. LinkedHashSet

Базовая структура такая же, как у HashSet, оба являются массивами, но добавлена ​​структура двусвязного списка, и при обходе он проходит в виде связанного списка вместо массива, поэтому его можно проходить в порядке добавление

Девять, набор деревьев

Добавляемые данные должны быть объектами одного класса.После добавления они автоматически сортируются.Должен быть реализован интерфейс Comaprable, а реализованный при этом метод ComapreTo также используется для определения дублирования двух элементов.

  • Естественная сортировка: реализуйте интерфейс Comaprable, а критерием сравнения двух объектов является то, возвращает ли compareTo() 0.
  • Пользовательская сортировка: объявить объект анонимного подкласса интерфейса Comparator (реализуя метод сравнения). Когда объект используется в качестве параметра конструктора TreeSet, TreeSet будет использовать метод сравнения, чтобы сравнить, являются ли два объекта дубликатами.
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. Интерфейс карты

Хранить пары ключ-значение (ключ-значение)

Класс реализации интерфейса карты

  • HashMap: основной класс реализации интерфейса Map, небезопасный для потоков, высокая эффективность, может хранить null
    • LinkedHashMap: подкласс HashMap. Структура связанного списка добавляется на основе HashMap, которая проходится в порядке добавления. Для частых операций обхода эффективность выше, чем у HashMap.
  • TreeMap: Сортировка при добавлении пар ключ-значение (естественная сортировка по ключу, пользовательская сортировка). Нижний слой использует красно-черное дерево
  • Hashtable: древний класс реализации интерфейса Map, потокобезопасный, с низкой эффективностью, не может хранить null
    • Свойства: обработка конфигурационных файлов, ключ-значение имеют тип String

Общий метод сопоставления (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));
}

Обход карты (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());
    }

}

Одиннадцать, HashMap

До JDK7 базовой структурой был массив + связанный список, а после JDK8 было добавлено красно-черное дерево

Структура карты

  • ключ: неупорядоченный, неповторяемый, используйте Set для хранения всех ключей (класс, которому принадлежит ключ, должен переписать hashCode и приравнять)
  • значение: неупорядоченное, повторяемое, используйте коллекцию для хранения всех ключей
  • ключ-значение: объект Entry, неупорядоченный и неповторяемый, используйте Set для хранения всех Entry

вставьте сюда описание изображения

Основной принцип реализации HashMap

JDK7

  • После создания объекта HashMap нижележащий слой создает таблицу Entry[] массива длиной 16 символов.
  • put(key1, value1) При добавлении пары ключ-значение вызовите hashCode класса, к которому принадлежит key1, чтобы получить хеш-значение и получить место хранения этой записи через indexFor (и операцию длины массива -1). нет данных в этом месте, добавление прошло успешно. Если в этом месте уже есть данные, сравните хэш-значение key1 с хэш-значением существующих данных.
    • Если значения хешей не совпадают, добавление прошло успешно (связное хранилище списков)
    • Если значения хэша совпадают, вызовите equals для сравнения
      • Если он возвращает false, добавление выполнено успешно (хранилище связанных списков)
      • Если верно, замените значение существующих данных значением1.
  • В процессе непрерывного добавления, при превышении порогового значения (порога) и наличии уже элементов в добавленной позиции, емкость будет удвоена до исходной

JDK8

  • После создания объекта HashMap нижележащий слой не создает массив длиной 16
  • Тип массива — Node[], а не Entry[]
  • Когда метод put вызывается в первый раз, нижележащий слой создает массив длиной 16 символов.
  • Когда количество элементов в позиции индекса (связный список) массива > 8 и текущая длина массива > 64, связанный список в этой позиции индекса изменяется на хранилище красно-черного дерева
  • Константы и переменные в HashMap
    • DEFAULT_INITIAL_CAPACITY = 16: емкость по умолчанию
    • DEFAULT_LOAD_FACTOR = 0,75: коэффициент загрузки по умолчанию.
    • порог: порог расширения = мощность * коэффициент нагрузки
    • TREEIFY_THRESHOLD = 8: Когда длина связанного списка в Bucket больше значения по умолчанию, он будет преобразован в красно-черное дерево.
    • MIN_TREEIFY_CAPACITY = 64: Минимальная емкость хеш-таблицы при преобразовании связанного списка в красно-черное дерево.

вставьте сюда описание изображения

12. LinkedHashMap

В отличие от HashMap при добавлении данных, при добавлении пар ключ-значение в массив или связанный список создается новый объект Entry (переписывая метод newNode HashMap), этот класс Entry имеет два указателя до и после, указывающих на передний и задний элементов, образующих двусвязный список.

вставьте сюда описание изображения

Тринадцать, TreeMap

Добавление ключа-значения в TreeMap требует, чтобы все ключи были объектами одного и того же класса, потому что они должны быть отсортированы в соответствии с ключом (естественная сортировка, пользовательская сортировка).

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. Свойства

Подкласс Hashtable, который обрабатывает файлы свойств. Пары ключ-значение имеют тип String.

@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. Инструментальный класс коллекций

@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
}

Acho que você gosta

Origin blog.csdn.net/Dae_Lzh/article/details/130510536
Recomendado
Clasificación