Java集合框架(Java Collections Framework)
  y9EYnC7aLifI 2023年12月06日 276 0

Java集合框架是一种提供了多种数据结构和算法的接口和类,位于java.util包中,使用集合框架时需要导入该包。集合框架的主要组成部分有:


Iterable

Iterable接口是Java集合框架的顶级接口,实现这个接口的类可以通过迭代器遍历自身元素。Iterable接口只有一个方法iterator(),它返回一个Iterator对象

ArrayList

ArrayList类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,可以添加或删除元素,它继承了 AbstractList,并实现了 List 接口,可以自动扩容

示例

import java.util.ArrayList;
public class ArrayListTest {
    public void Test1() {
        //新建对象
        ArrayList arrayList = new ArrayList();
        arrayList.add("Lowell");    //add()方法用于添加元素
        arrayList.add("is");
        arrayList.add(20);		   //可以存放不同的数据类型
        System.out.println(arrayList);

        System.out.println(arrayList.get(1));   //get()方法用于获取指定下表的元素
        System.out.println(arrayList.size());   //size()方法用于获取元素数量
        arrayList.set(2,19);                    //set()方法用于修改元素值,第一个为index,第二个为需要修改的值
        System.out.println("arrayList = " + arrayList);
        //remove()方法用于删除元素,提供两种
        arrayList.remove(1);              //根据指定的index删除
        System.out.println("arrayList = " + arrayList);
        arrayList.remove("Lowell");             //根据指定的Object删除
        System.out.println("arrayList = " + arrayList);
    }

输出结果:

[Lowell, is, 20]
is
3
arrayList = [Lowell, is, 19]
arrayList = [Lowell, 19]
arrayList = [19]

Java泛型

Java泛型是JDK 5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,即给类型指定一个或多个参数,这些参数可以用来限制该类型可以操作的数据类型。

泛型可以用在类、接口和方法上,例如:

  • 泛型类:在类定义时使用泛型参数,例如ArrayList<E>是一个泛型类,其中E是一个类型参数,可以在实例化时指定具体的类型,例如ArrayList<String>表示一个只能存储字符串的列表。
  • 泛型接口:是指在接口定义时使用泛型参数,例如List<E>是一个泛型接口,其中E是一个类型参数,可以在实现时指定具体的类型,例如LinkedList<String>表示一个实现了List<E>接口的链表类,其中元素类型为字符串。
  • 泛型方法:是指在方法定义时使用泛型参数,例如public static <T> void printArray(T[] inputArray)是一个泛型方法,其中T是一个类型参数,可以在调用时传入不同类型的数组作为参数。

泛型限定

Java泛型限定是指在使用泛型参数时,对其进行一定的约束,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。例如规定某类型参数必须是“扩展”了某个类或者实现了某个接口的。泛型限定可以用在类、接口和方法上,例如:

  • 有界的类型参数:是指在声明泛型参数时,使用extends关键字来指定其上界,即该类型参数必须是其上界或者其子类。例如public class Box<T extends Number>表示Box类的类型参数T必须是Number或者其子类。
  • 通配符:是指在使用泛型类型时,使用?符号来表示未知的类型参数,通配符可以有上界和下界,分别用? extends T? super T来表示。例如List<? extends Number>表示一个列表,其中元素的类型是未知的,但是必须是Number或者其子类。
  • 自限定类型:是指在定义泛型类或接口时,使用自身作为类型参数的边界,即该类型参数必须是自身或者其子类。例如public class SelfBounded<T extends SelfBounded<T>>表示SelfBounded类的类型参数T必须是SelfBounded<T>或者其子类

泛型示例

import java.util.ArrayList;
public class ArrayListTest {
    public void Test2() {
        ArrayList<String> arrayList0 = new ArrayList<>();	//只能存储字符串
        arrayList0.add("Lowell");
        arrayList0.add("here");
        System.out.println("arrayList0 = " + arrayList0);
        //也可用于存储自己定义的类
        ArrayList<Student> arrayList1 = new ArrayList<>();
        Student student = new Student("Tom",25);
        arrayList1.add(student);
        arrayList1.add(new Student("Lowell",20));
        System.out.println("arrayList1 = " + arrayList1);
    }
}

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

输出结果:

arrayList0 = [Lowell, here]
arrayList1 = [Student{name='Tom', age=25}, Student{name='Lowell', age=20}]

ArrayList其他方法

示例

import java.util.ArrayList;
public class ArrayListTest {
    public void Test3() {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        System.out.println("arrayList = " + arrayList);
        arrayList.add(0,4);     //add()方法还可以给指定的index添加元素
        System.out.println("arrayList = " + arrayList);

        ArrayList<Integer> arrayList_1 = new ArrayList<>();
        arrayList_1.add(4);
        arrayList_1.add(5);
        arrayList.addAll(arrayList_1);         //addAll()用于合并元素,将传入的对象合并到使用该方法的对象中
        System.out.println("arrayList = " + arrayList);

        Object[] array = arrayList.toArray();  //toArray()方法将对象以数组的形式返回,接收的为数组对象
        for (int i = 0; i < array.length; i++) {
            System.out.println("array = " + array[i]);  //遍历输出该数组
        }
        
        arrayList_1.clear();    //clear()方法用于清除元素
        System.out.println("arrayList_1 = " + arrayList_1);
        //contains()方法用于判断是否包含指定元素
        System.out.println("是否包含1:" + arrayList.contains(1));
        System.out.println("是否包含8:" + arrayList.contains(8));
    }
}

输出结果:

arrayList = [1, 2, 3]
arrayList = [4, 1, 2, 3]
arrayList = [4, 1, 2, 3, 4, 5]
array = 4
array = 1
array = 2
array = 3
array = 4
array = 5
arrayList_1 = []
是否包含1:true
是否包含8:false
import java.util.ArrayList;
public class ArrayListTest {
    public void Test4() {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("Lowell");
        arrayList.add("Tom");
        arrayList.add("Tim");
        arrayList.add("Tom");
        arrayList.add("Jerry");

        ArrayList<String> arrayList1 = new ArrayList<>();
        arrayList1.add("Lowell");
        arrayList1.add("Tim");
        arrayList1.add("Jerry");

        System.out.println(arrayList.isEmpty());            //isEmpty()判断是否为空
        System.out.println(arrayList.indexOf("Tom"));       //indexOf()方法用于查找元素首个下标
        System.out.println(arrayList.lastIndexOf("Tom"));//.lastIndexOf()方法用于查找元素最后一个下标
        arrayList.retainAll(arrayList1);
        System.out.println("arrayList = " + arrayList);     //retainAll()方法用于取交集
        //replaceAll()方法用于替换所有元素
        // toLowerCase()用于转换成小写
        // toUpperCase()用于转换成大写
        arrayList.replaceAll(e->e.toLowerCase(Locale.ROOT));
        System.out.println("arrayList = " + arrayList);
        arrayList.replaceAll(e->e.toUpperCase(Locale.ROOT));
        System.out.println("arrayList = " + arrayList);
        //remove()方法用于删除元素,同样提供两种
        arrayList.remove("LOWELL");  //根据对象删除
        arrayList.remove("TIM");
        System.out.println("arrayList = " + arrayList);
        arrayList.removeAll(arrayList);     //removeAll()用于删除全部的元素
    }
}

​ 输出结果:

false
1
3
arrayList = [Lowell, Tim, Jerry]
arrayList = [lowell, tim, jerry]
arrayList = [LOWELL, TIM, JERRY]
arrayList = [JERRY]

ArrayList遍历

示例

public class ArrayListTest {
	ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(86);
        arrayList.add(59);
        arrayList.add(5641);
        arrayList.add(369);
    	//fori 遍历
    	//get()方法获得集合里的元素,for循环遍历具有操作性,集合的长度要用size(),数组的长度用length()
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
    	//foreach遍历,也可以对元素进行操作
        System.out.println();
        for (Integer value : arrayList
        ) {
            System.out.println(value + 1);
        }
        System.out.println("arrayList = " + arrayList);

        Collections.sort(arrayList);	//sort()方法用于排序,默认从小到大
        System.out.println("arrayList = " + arrayList);
        Collections.reverse(arrayList);	//reverse()方法用于置反集合
        System.out.println("arrayList = " + arrayList);

        System.out.println(arrayList.subList(1, 3));
        System.out.println(arrayList.subList(1, 4));
    }

输出结果:

86
59
5641
369

87
60
5642
370
arrayList = [86, 59, 5641, 369]
arrayList = [59, 86, 369, 5641]
arrayList = [5641, 369, 86, 59]
[369, 86]
[369, 86, 59]

LinkedList

  • ArrayList数组集合,增删慢,查询快
  • LinkedList链表集合,增删快,查询慢
  • 即数据结构中的链表
  • 方法与ArrayList类似

迭代器Iterator和 for 循环

Java 迭代器是一种用于访问集合中的元素的方法,它可以在不暴露集合内部结构的情况下遍历集合。要使用 Java 迭代器,首先需要获取一个集合的迭代器对象,可以使用集合的 iterator() 方法。然后,可以使用迭代器的 hasNext() 方法判断是否还有下一个元素,如果有,就使用next()方法获取该元素并进行操作。如果需要删除元素,可以使用迭代器的 remove()方法。

Java 迭代器和 for 循环的区别

  • Java 迭代器是一种抽象的遍历机制,它可以适用于任何实现了 Iterable 接口的集合,而 for 循环是一种具体的循环结构,它需要知道数组或者集合的长度或者索引。
  • Java 迭代器可以在遍历过程中删除元素,而 for 循环不能直接删除元素,否则会引发 ConcurrentModificationException 异常。如果需要在 for 循环中删除元素,可以使用迭代器的 remove()方法或者集合的 removeIf()方法。
  • Java 迭代器只能从前往后遍历集合中的元素,而 for 循环可以根据需要改变遍历的方向或者顺序。
  • Java 迭代器对于顺序访问的集合(如 LinkedList)效率较高,而 for 循环对于随机访问的集合(如 ArrayList)效率较高。

示例

import java.util.ArrayList;
import java.util.Iterator;
public class IteratorDemo {
    public void Demo() {
        // 创建集合
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Zhihu");
        // 获取迭代器
        Iterator<String> it = sites.iterator();
        // 输出集合中的所有元素
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

输出结果:

Google
Runoob
Taobao
Zhihu

什么是Hash

Hash 是一种将任意长度的输入转换为固定长度的输出的方法,也叫做散列、杂凑或哈希。Hash 的输出称为 Hash 值,也叫做散列值、杂凑值或哈希值。Hash 的作用是可以快速地判断两个输入是否相同,或者将输入映射到一个有限的范围内。

Hash 有很多种算法,不同的算法有不同的特点和应用场景。一般来说,一个好的 Hash 算法应该具备以下特点:

  • 正向快速:给定输入和 Hash 算法,能在有限时间和资源内计算出 Hash 值。
  • 逆向困难:给定 Hash 值,在有限时间内很难推出原始输入。
  • 输入敏感:原始输入发生任何变化,都会导致 Hash 值发生很大变化。
  • 冲突避免:很难找到两个不同的输入,使得它们的 Hash 值相同。

Set

Java 中 Set 是一个接口,表示一个不包含重复元素的集合,无序且互异。它继承了 Collection 接口,有不同的实现类,例如 HashSetTreeSet,和 LinkedHashSet

HashSet

HashSet 是一种基于 HashMap 实现的集合,它不允许有重复的元素,也不保证元素的顺序,即无序的。HashSet 可以存储 null 值,但是只能存储一个 null 值。HashSet 的基本操作(如添加、删除、判断是否包含等)都是常数时间的,但是遍历 HashSet 需要时间与 HashSet 的大小和容量成正比。

HashSet 实现了 Set 接口,所以它可以使用 Set 接口中的方法,如 add()、remove()、contains()、size() 等。HashSet 还提供了一些特有的方法,如 unionWith()、intersectWith()、exceptWith() 等,用于对两个 HashSet 进行集合运算。

HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。

示例

import java.util.HashSet;
public class HashSetExample {
    public static void main(String[] args) {
        // 创建一个 HashSet 对象
        HashSet<String> set = new HashSet<String>();
        // 添加元素
        set.add("Java");
        set.add("Python");
        set.add("C++");
        set.add(null);
        // 重复的元素不会被添加
        set.add("Java");
        // 输出集合的内容
        System.out.println(set);
        // 判断集合是否包含某个元素
        System.out.println(set.contains("Python"));
        // 删除集合中的某个元素
        set.remove(null);
        System.out.println(set);
        // 计算集合的大小
        System.out.println(set.size());
        // 清空集合
        set.clear();
        System.out.println(set);
    }
}

输出结果如下:

[null, Java, Python, C++]
true
[Java, Python, C++]
3
[]

HashSet示例

import java.util.HashSet;
public class SetTest {
    public void Test0() {
        HashSet<String> hashSet = new HashSet();
        hashSet.add("Lowell");
        hashSet.add("Frank");
        hashSet.add("Tom");
        hashSet.add("Lowell");
        hashSet.add("Jerry");
        hashSet.add("Tim");
        System.out.println("hashSet = " + hashSet);

    }

输出结果:

hashSet = [Tom, Lowell, Tim, Jerry, Frank]

LinkedHashSet

它继承了HashSet类,实现了Set接口,提供了哈希表和双向链表的功能。它可以存储不重复的元素,并保持插入顺序,即有序的。

LinkedHashSet示例

import java.util.LinkedHashSet;
public class SetTest {
	public void Test1() {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet();
        linkedHashSet.add("Lowell");
        linkedHashSet.add("Frank");
        linkedHashSet.add("Tom");
        linkedHashSet.add("Jerry");
        linkedHashSet.add("Tim");
        linkedHashSet.add("Lowell");
        System.out.println("linkedHashSet = " + linkedHashSet);                
    }
}

输出结果:

linkedHashSet = [Lowell, Frank, Tom, Jerry, Tim]

Map

Java 中 Map 是一个接口,表示一个键值对的集合。它允许你根据键来存储和获取值。有不同的 Map 接口的实现类,例如 HashMap,TreeMap,和 LinkedHashMap

HashMap

HashMap是一个实现了Map接口的类,存储键值对(key-value)映射,HashMap的特点是:

  • 根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。
  • 无序的,即不会记录插入的顺序。
  • 继承了AbstractMap类,实现了Map、Cloneable、java.io.Serializable接口。
  • 键和值的类型可以相同也可以不同,可以是字符串(String)类型的键和值,也可以是整型(Integer)的键和字符串(String)类型的值。
  • 使用一个Entry数组来存储键值对,每一个Entry实体是一个单向链表结构,它具有next指针,可以连接下一个Entry实体。

示例

public class MapTest {
    public void Test0() {
        //映射关系,key->value,一个key对应一个value
        HashMap<String, String> hashMap = new HashMap();
        //使用put()方法赋值
        hashMap.put("0629", "Lowell");
        hashMap.put("0405", "Tom");
        hashMap.put("0603", "Tim");
        hashMap.put("0809", "Jerry");
        //输出hashMap
        System.out.println("hashMap = " + hashMap);

        //获取某个key对应的value,并输出
        System.out.println(hashMap.get("0629"));
        System.out.println(hashMap.get("0809"));

        //判断是否包含某个key或者value
        System.out.println(hashMap.containsKey("0629"));
        System.out.println(hashMap.containsKey("0609"));
        System.out.println(hashMap.containsValue("Lowell"));
        System.out.println(hashMap.containsValue("lowell"));

        //使用replace()方法替换Key对应的Value
        hashMap.replace("0629", "Mike");
        System.out.println(hashMap);

        //使用remove()方法移除某个key和value
        hashMap.remove("0629");
        System.out.println("hashMap = " + hashMap);
    }
}

输出结果:

hashMap = {0809=Jerry, 0629=Lowell, 0405=Tom, 0603=Tim} //可见,一个key对应一个value,且无序
Lowell
Jerry
true
false
true
false
{0809=Jerry, 0629=Mike, 0405=Tom, 0603=Tim}
hashMap = {0809=Jerry, 0405=Tom, 0603=Tim}

HashMap不能使用迭代器Iterator

Key以集合形式输出,.keySet()方法返回值是HashMapKey值的集合

HashMap以集合形式输出,.entrySet()方法的返回值也是Set集合

示例

public class MapTest {
	public void Test2() {
        HashMap<String, String> hashMap = new HashMap();
        //使用put()方法赋值
        hashMap.put("0629", "Lowell");
        hashMap.put("0405", "Tom");
        hashMap.put("0603", "Tim");
        hashMap.put("0809", "Jerry");
        hashMap.put("0605", "Lowell");
        System.out.println("hashMap = " + hashMap);

        //使用keySet()方法将hashMap中的key放在一个set中
        Set<String> keys = hashMap.keySet();
        System.out.println("keys = " + keys);
        ArrayList<String> arrayList = new ArrayList<>();

        Set<Map.Entry<String,String>> entrySet = hashMap.entrySet();
        System.out.println("entrySet = " + entrySet);

        //Entry是用来管理键值对对象的,将对象包裹起来,提供遍历的方式
        //获取迭代器,读取entrySet对象
        Iterator<Map.Entry<String,String>> iterator = entrySet.iterator();
        while(iterator.hasNext()) {
            String value = iterator.next().getValue();	//将获得的值放在一个变量中
            if(value == "Lowell") {
                arrayList.add(value);
            }
        }
        System.out.println("arrayList = " + arrayList);
    }
}
  

输出结果:

hashMap = {0809=Jerry, 0629=Lowell, 0605=Lowell, 0405=Tom, 0603=Tim}
keys = [0809, 0629, 0605, 0405, 0603]
entrySet = [0809=Jerry, 0629=Lowell, 0605=Lowell, 0405=Tom, 0603=Tim]
arrayList = [Lowell, Lowell]

已经存在的键值对,再次.put()会替换原来的,.get()不存在的值会返回null

示例

public class MapTest {
	public void Test3() {
        HashMap<String, String> hashMap = new HashMap();
        //使用put()方法赋值
        hashMap.put("0629", "Lowell");
        hashMap.put("0405", "Tom");
        hashMap.put("0603", "Tim");
        hashMap.put("0809", "Jerry");

        hashMap.put("0629","Frank");
        System.out.println("hashMap = " + hashMap);
        System.out.println(hashMap.get("7833"));
    }
}

输出结果:

hashMap = {0809=Jerry, 0629=Frank, 0405=Tom, 0603=Tim}
null

[JDK9 ArrayList](ArrayList (Java SE 9 & JDK 9 ) (oracle.com))

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月06日 0

暂无评论

推荐阅读
y9EYnC7aLifI