目录
Collection接口遍历元素的方式 1-使用Interator(迭代器)
List的三种遍历方式[ArrayList,LinkedList,Vector]
集合主要包括:集合框架体系(在Java中的继承关系、接口和它的实现子类)、Collenction、Map、Collections
1、Collection接口,下面有两个重要的子接口:List接口(ArrayList、LinkedList、Vector)和Set接口(HashSet、LinkedHashSet、TreeSet)
2、Map接口,有5个常用的实现子类:HashMap、HashTable、LinkedHashMap、TreeMap、Properties.
3、Collections工具类。
注:了解底层机制、看源代码、看JDK的底层实现、应用场景。
集合的理解和好处:
-
数组:
- 长度开始时必须是指定的,而且一旦指定,不能修改。
- 保存的必须是同一类型的元素。
- 使用数组进行增加/删除元素比较麻烦。
写出Person数组扩容示意代码:
Person[] pers = new Person[1]; //长度为1
pers[0] = new Person();
//增加新的Person对象?
Person[] pers2 = new Person[pers.length+1]; // 创建一个新的数组
for(){}; //拷贝pers数组的元素到pers2数组中
pers2[pers2.length-1] = new Person(); //添加新的对象
-
集合
- 可以动态保存任意多个对象(不同的数据类型),使用比较方便!
- 提供了一系列方便的操作对象的方法:add,remove,set,get等。
- 使用集合添加,删除新元素的示意代码-简洁明了
相当于是将底层代码写好了,我们需要哪种操作(增删改查)直接调用就好了。
比如新加一个元素,不用先创建一个新的数组再拷贝,然后再把新加的元素赋值到最后索引处。
集合的框架体系
Java的集合类有很多,主要分为两大类:【背下来】
注意:实线是继承,虚线是实现接口,UML规定的。
Collection是单例集合:存放单个对象;Map是双例集合:存放k-v。
Collection有两个重要的子接口,List和Set,他们的实现子类都是单例的。
Map接口的实现子类,都是双例集合,存放k-v。
出现警告错误可以通过这个注解来抑制。
@SuppressWarnings({"all"})
Collection接口和常用方法
-
Collection接口实现类的特点
-
public interface Collection<E> extends Iterable<E>
-
- collection实现子类可以存放多个元素,每个元素可以是Object
- 有些Collection的实现类,可以存放重复的元素,有些不可以。
- 有些Collection的实现类,可以是有序的(List),也可以是无序的(Set)。
- Collection接口没有直接的实现子类,是通过的它的子接口Set和List来实现的。
-
常用方法
- add:添加单个元素。 //list.add(元素);
- remove:删除指定元素。 //list.remove(元素/索引);
- contains:查找元素是否存在。 //list.contains(元素);
- size:获取元素的个数。//list.size();返回个数
- isEmpty:判断是否为空。 //list.isEmpty(); true/false;
- clear:清空。 //list.clear(); 清空集合
- addAll:添加多个元素。//
- containsAll:查找多个元素是否存在。
- removeAll:删除多个元素。
注意:
List list = new ArrayList(); //这里的类型是父接口类型;
list.add("jack");
list.add(10); //这里会自动装箱成Integer类型:list.add(new Integer(10));
list.add(true); //同上,会自动装箱成布尔;
System.out.println(list);
我们可以知道,remove方法被重载了,当删除的是某个对象时,返回的是布尔型;
当删除的是索引,返回的是被删除索引处的值。
也就是当传int类型的5时,调用remove(int index);当传Integer类型的5时,是调用remove(Object o)
如果满足int类型就不会自动装箱成Integer。
可以将一个集合快速拷贝到另一个集合。
-
Collection接口遍历元素的方式 1-使用Iterator(迭代器)
- 基本介绍:
- Iterator对象成为迭代器,主要用于遍历Collection集合中的元素。
- 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
- Iterator的结构:(执行原理)
Interator interator = coll.iterator(); //得到一个集合的迭代器
//hasNext():判断是否有下一个元素
while(interator.hasNext()){
//next(): 1.指针下移;2.将下移以后该指针位置的元素返回
System.out.println(interator.next());
}
4.Iterator仅用于遍历集合,Iterator本身并不存放对象。
注意:
在调用iterator.next()方法之前,必须要调用iterator.hasNext()进行检测。否则,当下一条记录无效时,直接调用iterator.next()会抛出NoSuchElementException异常。
这里提一点,这里调用用iterator.remove()方法前,必须先调用iterator.next()越过要删除的元素。
案例:CollectionInterator.java
public class CollectionIterator {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//接口类型指向子类
Collection col = new ArrayList();
col.add(new Book("三国演义","罗贯中",10.1));
col.add(new Book("小李飞刀","古龙",10.1));
col.add(new Book("红楼梦","曹雪芹",10.1));
System.out.println("col = " + col);
//遍历col
//1.先得到 col 对应的 迭代器
Iterator iterator = col.iterator();
//2.使用while循环遍历即可。
while(iterator.hasNext()){ //判断是否还有数据
//返回下一个元素,类型是Object
Object obejct = iterator.next();
System.out.println("obejct = " + obejct);
//这里默认调用的是toString方法。动态绑定的那个机制就会找到真正运行的类型
//他的编译类型是Object,但是它的运行类型取决于真正存放时的类型。
//快捷键是itit,,,ctrl+j可以找到当前的所有快捷键都展示出来
//itco 迭代器定义和遍历
//iter 增强for循环,
//泛型只在编译器进行约束,在字节码看不出来。
}
//3.当退出while循环后,这时迭代器iterator指向最后一个元素
//4.如果希望再次遍历,需要重置我们的迭代器
iterator = col.iterator();
System.out.println("第二次遍历------------");
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println("next = " + next);
}
}
}
-
Collection接口遍历元素的方式 2-for循环增强
增强for循环,可以替代iterator迭代器,特点:增强for就是简化版的iterator,本质一样。
只能用于遍历集合或数组。
- 基本语法:
for(元素类型 元素名:集合名或数组名){
访问元素
}
案例:CollectionFor.java
快捷键:iter / 集合.for
public class CollectionFor {
@SuppressWarnings({"all"})
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(new Book("三国演义","罗贯中",10.1));
col.add(new Book("小李飞刀","古龙",10.1));
col.add(new Book("红楼梦","曹雪芹",10.1));
//1.使用增强 for循环遍历,在 Collection集合中
//2.增强 for,底层仍然是迭代器
//3.增强 for可以理解成简化版的 迭代器遍历
for (Object book : col) {
System.out.println("book = " + book);
}
//增强for,也可以直接在数组中使用
// int[] nums = {1,2,3,4,5};
// for (int num : nums) {
// System.out.println("num = " + num);
// }
}
}
练习:
请编写程序CollectionExercise.java
- 创建3个Dog{name,age}对象,放入到Array List对象中,赋值给list引用
- 用迭代器和增强for循环两种方式来遍历
- 重写Dog和toString方法,输出name和age。
so easy……
见案例:CollectionExercise.java
List接口和常用方法
-
List接口基本介绍
List接口是Collection接口的子接口 List.java
- List集合类中元素有序(即添加顺序和取出顺序一致)、元素且可重复。【案例】
- List集合中的每个元素都有其对应的顺序索引,即支持索引。【案例】
- List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
- JDK API中List接口的实现类有:
常用的有:ArrayList ,LinkedList和Vector.
-
List接口的常用方法:
ListMethod.java
List集合里添加了一些根据索引来操作集合元素的方法。
- void add(int index,Object ele):在index位置前插入ele元素。
- boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来。
- Object get(int index):获取指定index位置的元素。
- int indexOf(Object obj):返回obj在集合中首次出现的位置。
- int lastIndexOf(Object obj):返回obj在集合中末次出现的位置。
- Object remove(int index):移除指定index位置的元素,并返回此元素。
如果下标不存在,会抛出indexOutOfBoundsException;
- Object set(int index,Object ele):设置指定index位置的元素为ele,相当于是替换。
- List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的子集合。‘[fromIndex,toIndex)’
练习1:
ListExercise.java
添加10个以上的元素(比如:String,“hello”),在2号位插入一个元素“蔡文姬”,获取第5个元素,删除第6个元素,修改第7个元素,再使用迭代器遍历集合。要求:使用List的实现类ArrayList完成。
so easy!
-
List的三种遍历方式[ArrayList,LinkedList,Vector]
ListFor.java
- 方式一:使用iterator
- 方式二:使用增强for
- 方式三:使用普通for
说明:使用LinkedList完成,使用方式和ArrayList一样。
Stream遍历。 和list.foreach(e->sout(e));//foreach的简写
练习2:
ListExercise02.java
使用List的实现类添加三本图书,并遍历,打印如下效果;
名称:xx 价格:xx 作者:xx
名称:xx 价格:xx 作者:xx
名称:xx 价格:xx 作者:xx
要求:
- 按价格排序,从低到高。(使用冒泡法)
- 要求使用ArrayList、LinkedList、Vector三种集合实现。
实现Comparable<Book>,重写compareTo方法,调用Collections.sort(list);
ArrayList底层结构和源码分析
-
ArrayList的注意事项
ArrayDetail.java
- permits all elements,including null,ArrayList可以加入null,并且多个null都是可以的。
- ArrayList是由数组来实现数据存储的。
- ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码,在多线程情况下,不建议使用ArrayList。多线程考虑Vector。
public class ArrayDetail {
public static void main(String[] args) {
//ArrayList是线程不安全的,看源码,没有synchronized关键字,(线程互斥)
/**
* public boolean add(E e) {
* ensureCapacityInternal(size + 1); // Increments modCount!!
* elementData[size++] = e;
* return true;
* }
*/
ArrayList arrayList = new ArrayList();
arrayList.add(null);
arrayList.add("tom");
arrayList.add(null);
System.out.println("arrayList = " + arrayList);
}
}
-
ArrayList的底层操作机制源码分析(重点,难点)
ArrayListSource.java 先说结论,再分析源码
- ArrayList中维护了一个Object类型的数组elementData.java [debug 看源码]
transient Object[] elementData; //transient 表示瞬间,短暂的。表示该属性不会被序列化。 //序列化就是持续保持,保存到硬盘上 //Java序列化就是指把Java对象转换为字节序列的过程 //Java反序列化就是指把字节序列恢复为Java对象的过程。
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData的容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
- 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
-
ArrayList的底层操作机制分析案例
ArrayListSource.java
ArrayList arrayList = new ArrayList();
//使用for循环给list集合添加1-10个数据
for (int i = 0; i < 10; i++) {
arrayList.add(i);
}
//使用for循环给list集合添加11-15个数据
for (int i = 11; i < 15; i++) {
arrayList.add(i);
}
arrayList.add(100);
arrayList.add(200);
arrayList.add(null);
}
无参:
注意:
//注意:Idea默认情况下,Debug显示的数据是简化后的,即不显示为null的部分, //如果想要看到,需要做设置。
看到的信息就会比较全了。debug非常好用。
有参:
Vector底层结构和源码分析
-
Vector基本介绍
Vector_.java
- Vector类的定义说明
- Vector底层也是一个对象数组,proctected Object[] elementData;
- Vector是线程同步的,即线程安全。Vector类的操作方法带有synchronized(支持线程同步和互斥)
- 在开发中,需要同步安全时,考虑使用Vector。
除了List接口,它还实现了
开发一般用JUC包中绝对线程安全的集合,Vector只是相对安全,add、remove这些方法不是原子操作,所以还是别用Vector。
只有一个线程,建议使用ArrayList,因为效率高。如果多线程,建议使用Vector,因为它是安全的。
只有卷,才能筛!!!
-
Vector的源码解读
Vector和ArrayList的比较
Vector是线程同步的,所以每个方法都会做安全校验。
@SuppressWarnings({"all"})
public class Vector_ {
public static void main(String[] args) {
//无参构造
// Vector vector = new Vector();
//有参数的构造
Vector vector = new Vector(8);
for (int i = 0; i < 10; i++) {
vector.add(i);
}
vector.add(100);
System.out.println("vector = " + vector);
/**
* 1. public Vector() {
* this(10);
* }
*
* 补充:如果是 Vector vector = new Vector(8);
* 走的方法:
* public Vector(int initialCapacity) {
* this(initialCapacity,0);
* }
* 这个0的参数叫扩容增量,如果这个增量大于0,扩容后的容量就是 原容量+增量,否则就是 原容量+原容量
* 2.vector.add(i);
* 2.1 //下面这个方法是添加数据到vector集合
* public synchronized boolean add(E e) {
* modCount++;
* ensureCapacityHelper(elementCount + 1);
* elementData[elementCount++] = e;
* return true;
* }