Day2

tech2026-01-23  2

集合框架

集合框架定义:

集合框架是一种容器,用于存储对象信息的容器,并且长度是可变的。

1、因为对象是可以创建无数个的,而对象数组是开辟固定长度的存储空间,显然对象数组去存储对象是不合适的 2、对象数组长度不可变化并且无法保存具有映射关系的数据,集合可以用于存储数量不确定的数据,长度可变,以及可以保存具有映射关系的数据 3、数组元素既可以是基本类型的值,也可以是对象,集合只能保存对象(比如list.add(1)是把1变成包装类Integer类型)

所有的集合框架继承关系图:(掌握常用的即可)

如果觉得太麻烦,有简化版本的

** **

** **

各集合的使用

List接口下的集合

List接口代表一个有序、可重复的集合,集合每个元素都有其对应的顺序索引,List集合默认按照元素的添加顺序设置元素的索引,可以通过索引来访问指定位置的集合元素。 实现List接口的集合常用的有:ArrayList,LinkedList,Vector子类等,实现List接口的子类具体参考打开层级目录去看,不需要所有都学会。

a、ArrayList:

ArrayList是我们最常用于遍历数据的集合,底层是一个Object类型的数组,它允许任何符合规则的数据插入设置是null,该Object类型的数组集合默认长度是0,也可以自定义长度,每次调用list.add()方法的增加元素的同时对容器进行检查,当快溢出时,就会对该数组进行扩容。

如图:

list.get(i):直接获取数组的指定下标的位置的元素,查询快

@SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; }

ArrayLis时一个有序可扩容长度的数组,所以可以插入可重复的元素,优点是:可以快速通过下标获取到元素,遍历元素和查找元素快;缺点:由于插入、删除需要位移,所以插入和删除效率慢。

同时ArrayList是非同步的,是非线程安全的,效率高

案例1:

public class ArrayListTest01 { public static void main(String[] args) { List list = new ArrayList(); list.add(100); list.add("张三"); list.add(89.9); list.add(1,88.8); System.out.println("集合长度"+list.size()); System.out.println("是否包含"+list.contains("张三")); System.out.println(list.get(1)); //list.clear();//集合清空 for (int i = 0;i < list.size();i++){ System.out.println(list.get(i)); } System.out.println("-----------------"); for (Object object: list ) { System.out.println(object); } } }

案例2:

package collection; import java.util.ArrayList; import java.util.List; class Student{ private String name; private int age; private char sex; public Student() { } public Student(String name, int age, char sex) { this.name = name; this.age = age; this.sex = sex; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", sex=" + sex + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public void showStudent() { System.out.println(name+age+sex); } } public class ArrayListTest02 { public static void main(String[] args) { Student stu1 = new Student("杨幂",28,'女'); Student stu2 = new Student("胡歌",35,'男'); Student stu3 = new Student("张译",40,'男'); Student stu4 = new Student("郭德纲",48,'男'); List list = new ArrayList(); list.add(stu1); list.add(stu2); list.add(stu3); list.add(1, stu4); //list.add(”张三丰“);//因为add(object)类型可以插入任意类型 for (int i =0;i<list.size();i++){ Student student = (Student) list.get(i); student.showStudent(); } } }

案例3: 通过泛型约束集合的类型: 泛型作用:

用于约束集合中元素的类型

package collection; import java.util.ArrayList; import java.util.List; public class ArrayListTest03 { public static void main(String[] args) { Student stu1=new Student("杨幂",28,'女'); Student stu2=new Student("胡歌",35,'男'); Student stu3=new Student("张译",40,'男'); Student stu4=new Student("郭德纲",48,'男'); //<Student>泛型 用来约束集合中元素的类型 List<Student> list = new ArrayList<>(); list.add(stu1); list.add(stu2); list.add(stu3); list.add(1,stu4); //list.add("张三丰");因为定义集合的时候通过泛型约束了集合中的类型是Student类型,所以 //add()方法插入其他类型会报错! for (int i = 0;i<list.size();i++){ Student student = list.get(i); student.showStudent(); } System.out.println("==============="); for (Student student : list){ student.showStudent(); } } }

b、LinkedList:

LinkedList的实现机制与ArrayList的实现机制完全不同,ArrayList内部以数组形式保存集合的元素,所以查询和遍历元素速度快,但是插入和删除需要唯一性能低,LinkedList内部以链表式的形式保存集合的元素,所以查询和比那辆元素效率没有ArrayList效率高,但是插入和删除效率高

linkedList.add()源码: 把元素插入到集合容器中的同时,将该元素记录在元素的前后位置,所以插入和删除该元素不需要位移。

void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }

linkedList集合的get(i),是根据下标为参数,先将index位置化成两半,如果index是小于集合的一半就从第一个往后找,知道找到index的值赋给x返回,如果大于就从集合最后的值往前找,找到index的值赋给x返回,这样可以减少一部分不必要的遍历。但是还是没有ArrayList直接找下标位置的元素效率高!

if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }

上机案例

package collection; import java.util.LinkedList; public class ArrayListTest04 { public static void main(String[] args) { Student stu1 = new Student("杨幂", 28, '女'); Student stu2 = new Student("胡歌", 35, '男'); Student stu3 = new Student("张译", 40, '男'); Student stu4 = new Student("郭德纲", 48, '男'); //<Student>泛型 用来约束集合中元素的类型 LinkedList<Student> list = new LinkedList<>(); list.add(stu1); list.add(stu2); list.addFirst(stu3);//LinkedList的插入最前面的方法 list.addLast(stu4);//LinkedList的插入最后面的方法 //获取第一个和最后一个元素 //list.getFirst(); //Student lastStu= list.getLast(); //lastStu.showStudent(); //for (Student student:list){ // student.showStuent(); //} //for (int i = 0; i <list.size(); i++) { // // Student student= list.get(i); // // student.showStudent(); } }

c、Vector

vector的add()方法恶的源码:

public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }

synchronized修饰使方法同步,此集合线程安全

面试题:ArrayList和Vector的区别在哪里?

ArrayList集合和Vector集合底层数组储存,操作都是一样的。ArrayList非线程安全;效率更高;Vector是线程安全的。

B、Set接口下的集合

Set接口用于存储无序并元素不可重复的集合,如下图:

Set接口常用的实现子类有HashSet,LinkedHashSet,TreeSet类等。

a、HashSet

HashSet是Set集合中最常用的实现类,HashSet是按照哈希算法来存储的,因此具有很好的存取和查找性能

HashSet特点:

1、无序,不能保证元素的顺序 2、HashSet不是线程同步的,如果多线程操作HashSet集合,则应该通过代码来实现线程同步。 3.集合元素可以为null

案例1:

public class Test { public static void main(String[] args) { HashSet dest=new HashSet(); dest.add(1); dest.add(71); dest.add(23); dest.add(67); dest.add(98); for (Object obj : dest) { System.out.print(" "+obj); } System.out.println("\n--------------------"); //因为此集合是无序的,我们不能通过for循环遍历该集合 //我们可以通过迭代器让无序的集合"排队" Iterator it= dest.iterator(); while(it.hasNext()){ //it.hasNext()用于判断迭代器中后面有没有元素 //如果有就通过next()方法取到元素 Object obj= it.next(); System.out.print(" "+obj); } } }

结果:

1 98 67 71 23

b、LinkedHashSet

linkedHashSet是介于HashSet和TreeSet之间,内部是一个双向链表结构,所以它插入是有有序的。linkedHashSet是HashSet的一个子类,具有HashSet的特征,也是根据元素的hashCode值来决定元素的存储位置,但它使用链表维护元素的次序,元素的顺序月添加顺序一致,由于LinkedHashSet需要维护元素的插入,因此性能上略低于HashSet,但在迭代访问Set里面的全部元素的时候有很好的性能。

c、TreeSet集合

TreeSet是sortedSet接口的实现类,TreesSet可以保证元素处于排序状态,它采用红黑数的数据结构来存储集合元素,TreeSet支持两种排序方法:自然排序和定制排序,默认采用自然排序

自然排序:

TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素的大小,然后将元素按照升序排 列,这就是自然排序。

定制排序:

如果TreeSet集合插入的是对象,那么对象是无法去比较排序的,所以我们需要通过定制排序来定制对象之 间排序的规则, 需要再创建TreeSet集合对象时,提供一个Comparator对象与该TreeSet集合关联,由Comparator对象 负责集合元素的排序规则。

实现步骤:

1、在集合的元素的类里面实现Comparator接口 2、重写compareto(Object obj)方法自定义排序规则

各Set集实现类的性能分析:

HashSet的性能比TreeSet性能好,因为TreeSet需要额外通过红黑树算法来维护元素吃次序,如果需要 保持一个排序的Set时候用TreeSet,否则应该使用HashSet LinkedHashSet是HashSet的子类,由于需要维护链表的顺序,所以插入和删除操作比HashSet要慢,但 遍历比hasetSet要快。 EnumSet是所有的Set实现类中性能最好的,但它只能用于保存同一个枚举类的枚举值作为元素的集合。 以上几个Set实现类都是非线程安全的,如果需要多线程访问,必须手动包装集合的同步性

最新回复(0)