JavaSE复习总结之集合

集合概述

集合实际上就是一个容器。可以来容纳其它类型的数据。数组其实就是一个集合。

Java 集合主要有 3 种重要的类型:

  • List:是一个有序集合,可以放重复的数据
  • Set:是一个无序集合,不允许放重复的数据
  • Map:是一个无序集合,集合中包含一个键对象(Key),一个值对象(Value)

Collection(单列集合)

Collection是最基本的集合接口。它继承自Iterable接口,Iterable表示可迭代的,所以所有的集合元素都是可迭代可遍历的。它有两个子接口:

  • List接口:有序可重复
  • Set接口:无序不可重复
    在这里插入图片描述

Collection中能存放什么元素 ?

没有使用泛型之前,Collection中可以存储Object的所有子类型。
使用了泛型之后,Collection中只能存储某个具体的类型。

Collection中的常用方法

返回值类型 方法名 描述
boolean add(Object e) 向集合中添加元素
int size() 获取集合中元素的个数
void clear() 清空集合
boolean contains(Object o) 判断当前集合中是否包含元素o
boolean remove(Object o) 删除集合中的某个元素
boolean isEmpty() 判断该集合中元素的个数是否为0
Object[] toArray() 调用这个方法可以把集合转换成数组

注意:集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址(或者说集合中存储的是引用)

//这里存进去的并不是int类型的1200
//这里使用了自动装箱机制 Integer x = new Integer(1200);
c.add(1200);

集合的迭代

Iterator常用方法

返回值类型 方法名 描述
boolean hasNext() 如果仍有元素可迭代就返回true
Object next() 返回迭代的下一个元素
void remove() 从集合中移除next()方法返回的最后一个元素

注意:在迭代集合元素的过程中,不能调用集合对象的remove方法删除元素。否则会造成java.util.ConcurrentModificationException异常。正确做法是使用迭代器Iterator提供的remove方法

public static void main(String[] args) {
    
    
	Collection c1  = new ArrayList();  // 创建集合对象
	c1.add(1);// 添加元素
	c1.add(2);// 添加元素
	c1.add(3);// 添加元素
	c1.add(4);// 添加元素
	c1.add(1);// 添加元素
	// 获取集合迭代器
	Iterator it = c1.iterator();
	while(it.hasNext()){
    
    
		Object obj = it.next();
		//c1.remove(obj);删除元素之后,集合的结构发生了变化,但是循环下一次的时候并没有重新获取迭代器
		it2.remove();// 迭代器去删除时,会自动更新迭代器,并且更新集合
		System.out.println(obj);
	}
}

List接口

List集合中的常用方法

返回值类型 方法名 描述
void add(int index,Object element) 将元素element插入到List集合的index索引处
Object get(int index) 返回列表index索引处的元素
Object remove(int index) 删除列表index索引处的元素
int indexOf(Object o) 返回对象o在List集合中出现的位置索引
int LastIndexOf(Object o) 返回对象o在List集合中最后一次出现的位置索引
List subList(int fromIndex,int toIndex) 返回从索引fromIndex(包括)到toIndex处(不包括)处的子集合

ArrayList

ArrayList集合底层是一个Object[]数组,默认初始化容量10。ArrayList集合是非线程安全的

  • 数组优点: 检索效率比较高。
  • 数组缺点:
    1、 随机增删元素效率比较低。向数组末尾添加元素效率不受影响
    2、另外数组无法存储大数据量。(很难找到一块非常巨大的连续的内存空间。)
public class ArrayListTest{
    
    
    public static void main(String[] args) {
    
    
        //List list = new ArrayList();默认初始化容量是10
        List list = new ArrayList(4); // 指定初始化容量4
        // 集合的size()方法是获取当前集合中元素的个数。不是获取集合的容量。
        System.out.println(list1.size()); // 0
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        // 再加一个元素
        list.add(5);//数组自动扩容,增长到原容量的1.5倍
    }
    //第一种遍历方式:fori
	for(int i = 0; i <list1.size(); i++){
    
    
		Object elem = list1.get(i);
		System.out.println(elem);
	}
	//第一种遍历方式:foreach
	for (Object elem : list1) {
    
    
		System.out.println(elem);
	}
	//第一种遍历方式:使用迭代器
	Iterator iterator = list1.iterator();
	while (iterator.hasNext()){
    
    
		Object next = iterator.next();
		System.out.println(next);
	}
}

注意:并不是一创建ArrayList容器对象就初始化容量。底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10

LinkedList

LinkedList集合底层采用了双向链表的数据结构
LinkedList集合中常用的方法

返回值类型 方法名 描述
void addFirst(Object o) 将元素o添加到集合的开头
void addLast(Object o) 将元素o添加到集合的结尾
Object getFirst() 返回集合的首元素
Object getLast() 返回集合的尾元素
Object removeFirst() 移除并返回集合的首元素
Object removeLast() 移除并返回集合的尾元素
public class LinkedListTest01 {
    
    
    public static void main(String[] args) {
    
    
        // LinkedList集合底层也是有下标的。
        // LinkedList集合有初始化容量吗?没有。
        List<String> list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
		//第一种遍历方式:fori
        for(int i = 0; i <list.size(); i++){
    
    
            String str = list.get(i);
            System.out.println(str);
        }
        //第一种遍历方式:foreach
        for (String str : list) {
    
    
            System.out.println(str);
        }
        //第一种遍历方式:使用迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
    
    
            String nextStr = iterator.next();
            System.out.println(nextStr);
        }
    }
}
  • 链表的优点:
    由于链表上的元素在空间存储上内存地址不连续。所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。

  • 链表的缺点:
    不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率较低。

Vector

  • 底层是数组
  • Vector初始化容量是10
  • 扩容为原容量的2倍
  • Vector底层是线程安全的
public class VectorTest {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个Vector集合
        List vector = new Vector();
        vector.add(1);
        vector.add(2);
        vector.add(3);
        vector.add(4);
        vector.add(5);
        Iterator it = vector.iterator();
        while(it.hasNext()){
    
    
            Object obj = it.next();
            System.out.println(obj);
        }
}

如何将非线程安全的集合转换成线程安全的集合

List myList = new ArrayList(); // 非线程安全的。
// 变成线程安全的
Collections.synchronizedList(myList);
// myList集合就是线程安全的了。
myList.add("111");
myList.add("222");
myList.add("333");

Set接口

Set集合存储元素的特点:无序不可重复
Set集合没有下标不能使用fori的方式遍历

HashSet

HashSet集合在new的时候底层实际上new了一个HashMap集合,向HashSet集合中存放元素实际上存储到HashMap集合的key部分、HashMap集合底层是一个哈希表。

public class HashSetTest01 {
    
    
    public static void main(String[] args) {
    
    
        // 演示一下HashSet集合特点
        Set<String> hashSet= new HashSet<>();
        //String类已经重写了hashCode()方法和equals()方法
        hashSet.add("hello3");// 添加元素
        hashSet.add("hello4");
        hashSet.add("hello1");
        hashSet.add("hello2");
        hashSet.add("hello3");
        hashSet.add("hello3");
        hashSet.add("hello3");
        hashSet.add("hello3");
        //第一种遍历方式:foreach
        for(String s : hashSet){
    
    
            System.out.println(s);
        }
        //第二种遍历方式:迭代器
        Iterator<String> iterator = hashSet.iterator();
        while(iterator.hasNext()){
    
    
            System.out.println(iterator.next());
        }
    }
}

【运行结果】

hello1
hello4
hello2
hello3

Process finished with exit code 0

【结论】
1、存储时顺序和取出的顺序不同。
2、不可重复。
3、放到HashSet集合中的元素实际上是放到HashMap集合的key部分了。

HashSet集合是如何保证添加元素时不出现重复的 ?
保证不重复的关键在于出入对象的hashCode()方法和equals()方法。向HashSet集合中存入对象时,首先调用对象的hashCode()方法获取对象的哈希值,然后根据哈希值计算处存储位置。如果该位置上没有元素就将元素存入,如果该位置上已有元素则调用equals()方法比较两个元素是否相同,如果不相同则通过探测再散列的方法找到一个新的位置将元素存入,如果相同就不存入元素

TreeSet

TreeSet集合在new的时候底层实际上new了一个TreeMap集合,向TreeSet集合中存放元素实际上存储到TreeMap集合的key部分。TreeMap集合底层是一个二叉树。
TreeSet集合存储元素特点:
1、无序不可重复的,但是存储的元素可以自动按照大小顺序排序!
2、无序:这里的无序指的是存进去的顺序和取出来的顺序不同。并且没有下标。

TreeSet中定义的方法

返回类型 方法名 描述
Object first() 返回集合中的最低元素
Object last() 返回集合中的最高元素
Comparator<? super E> comparator() 返回对此集合中元素进行排序的比较器
public class TreeSetTest01 {
    
    
    public static void main(String[] args) {
    
    
        // 创建集合对象
        Set<String> strs = new TreeSet<>();
        // 添加元素
        strs.add("A");
        strs.add("B");
        strs.add("Z");
        strs.add("Y");
        strs.add("Z");
        strs.add("K");
        for(String s : strs){
    
    
            System.out.print(s+" ");//从小到大自动排序
        }
    }
}

【输出结果】

A B K M Y Z

Process finished with exit code 0

TreeSet集合中自定义类型元素可排序的二种方式

//1、实现Comparable接口并且重写compareTo方法
public class Customer implements Comparable<Customer>{
    
    
    int age;
    public Customer(int age){
    
    
        this.age = age;
    }
    public int compareTo(Customer c) {
    
    
        return c.age - this.age;
    }
}
//2、使用比较器
public class TreeSetTest {
    
    
    public static void main(String[] args) {
    
    

        // 给构造方法传递一个比较器。(匿名内部类)也可以单独编写一个比较器
        TreeSet<Customer> customerList = new TreeSet<>(new Comparator<WuGui>() {
    
    
            @Override
            public int compare(Customer c1, Customer c2) {
    
    
                return c1.age - c2.age;
            }
        });

        customerList.add(new Customer(20));
        customerList.add(new Customer(30));
        customerList.add(new Customer(18));
        for(Customer customer: customerList){
    
    
            System.out.println(customer);
        }
    }
}

Comparable和Comparator怎么选择呢 ?

  • 当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议实Comparable接口。
  • 如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。

Map(双列集合)

  • Map和Collection没有继承关系
  • Map集合以key和value的方式存储数据:键值对
    key和value都是引用数据类型。
    key和value都是存储对象的内存地址。
    在这里插入图片描述

Map接口中常用方法

返回值类型 方法名 描述
void put(K key, V value) 向Map集合中添加键值对
Object get(Object key) 通过key获取value
void clear() 清空Map集合
boolean containsKey(Object key) 判断Map中是否包含某个key
boolean containsValue(Object value) 判断Map中是否包含某个value
boolean isEmpty() 判断Map集合中元素个数是否为0
V remove(Object key) 通过key删除键值对
int size() 获取Map集合中键值对的个数。
Collection<V> values() 获取Map集合中所有的value,返回一个Collection
Set<K> keySet() 获取Map集合所有的key(所有的键是一个set集合)
Set<Map.Entry<K,V>> entrySet() 将Map集合转换成Set集合

Map集合的遍历

public class MapTest {
    
    
    public static void main(String[] args) {
    
    
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "zhangsan");
        map.put(2, "lisi");
        map.put(3, "wangwu");
        map.put(4, "zhaoliu");
        
        // 第一种方式:获取所有的key,通过遍历key,来遍历value
        Set<Integer> keys = map.keySet();
        for(Integer key : keys){
    
    // foreach遍历,当然也可以使用迭代器遍历
            System.out.println(key + "=" + map.get(key));
        }
        
        // 第二种方式:Set<Map.Entry<K,V>> entrySet()
        // 这个方法是把Map集合直接全部转换成Set集合。
        // Set集合中元素的类型是:Map.Entry
        Set<Map.Entry<Integer,String>> set = map.entrySet();
        for(Map.Entry<Integer,String> node : set){
    
    // foreach遍历,当然也可以使用迭代器遍历
            System.out.println(node.getKey() + "--->" + node.getValue());
        }
    }
}

HashMap

  • HashMap集合底层是哈希表/散列表的数据结构
  • HashMap集合的key部分特点:无序,不可重复。 如果key重复了,value会覆盖
  • 放在HashMap集合key部分的元素其实就是放到HashSet集合中了
  • HashMap集合的默认初始化容量是16,默认加载因子是0.75
    这个默认加载因子是当HashMap集合底层数组的容量达到75%的时候,数组开始扩容,扩容2倍
  • HashMap集合初始化容量必须是2的倍数,这也是官方推荐的
  • 放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法
  • HashMap允许key和value为null,但key null值只能有一个
public class HashMapTest {
    
    
    public static void main(String[] args) {
    
    
        // Integer是key,它的hashCode和equals都重写了。
        Map<Integer,String> map = new HashMap<>();
        map.put(1, "zhangsan");
        map.put(6, "lisi");
        map.put(7, "wangwu");
        map.put(2, "zhaoliu");
        map.put(2, "king"); //key重复的时候value会自动覆盖。
        System.out.println(map.size()); // 4
        // 遍历Map集合
        Set<Map.Entry<Integer,String>> set = map.entrySet();
        for(Map.Entry<Integer,String> entry : set){
    
    
            // 验证结果:HashMap集合key部分元素:无序不可重复。
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}

HashTable

  • Hashtable和HashMap一样,底层都是哈希表数据结构
  • Hashtable的初始化容量是11,默认加载因子是:0.75f
  • Hashtable的扩容是:原容量 * 2 + 1
  • Hashtable的key和value都是不能为null的
Map map = new Hashtable();
map.put(null, "123");//NullPointerException
map.put(100, null);//NullPointerException

Properties

  • Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型
  • Properties是线程安全的
public class PropertiesTest {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个Properties对象
        Properties pro = new Properties();
        // 需要掌握Properties的两个方法,一个存,一个取。
        pro.setProperty("url", "jdbc:mysql://localhost:3306/whydb");
        pro.setProperty("driver","com.mysql.jdbc.Driver");
        pro.setProperty("username", "root");
        pro.setProperty("password", "123");
        // 通过key获取value
        String url = pro.getProperty("url");
        String driver = pro.getProperty("driver");
        String username = pro.getProperty("username");
        String password = pro.getProperty("password");

        System.out.println(url);
        System.out.println(driver);
        System.out.println(username);
        System.out.println(password);
    }
}

TreeMap

TreeMap集合也是用来存储键值映射关系的,TreeMap不允许出现重复的键,该映射关系根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparator进行排序。TreeMap的底层采用了二叉树这种数据结构

public class HashtableTest01 {
    
    
    public static void main(String[] args) {
    
    
	    Map<Integer,String > treeMap = new TreeMap<>();
        treeMap.put(1,"张三");
        treeMap.put(9,"李四");
        treeMap.put(8,"王五");
        treeMap.put(2,"赵六");
        Set<Map.Entry<Integer, String>> entries = treeMap.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
    
    
            System.out.println(entry.getKey()+"=="+entry.getValue());
        }
	}
}

【运行结果】

1==张三
2==赵六
8==王五
9==李四

Process finished with exit code 0

Collections工具类

Collections常用方法

返回类型 方法名 描述
static boolean addAll(Collection<? super T>,T…elements) 将所有指定元素添加到Collection中
static void reserve(List<?> list) 反转指定列表中的元素
static void shuffle(List<?> list) 使用默认随机源对指定列表进行置换
static void sort(List<?> list) 根据元素的自然顺序进行升序排序
static void swap(List<?> list,int i,int j) 将指定列表中i处元素和j处元素进行交换
static int binarySearch(List<?> list,Object key) 使用二分查找搜索指定列表
static Object max(Collection col) 根据元素的自然顺序返回给定集合中的最大元素
static Object min(Collection col) 根据元素的自然顺序返回给定集合中的最小元素
static boolean replaceAll(List list,Object oldVal,Object newVal) 使用newVal替换列表中所有的oldVal
static List<T> synchronizedList(List<T> list) 将指定集合转换成线程安全

猜你喜欢

转载自blog.csdn.net/m0_60117382/article/details/123759352