集合框架· ArrayList 和 Vector
对象数组的概述和使用
* A:案例演示
* 需求:我有5个学生,请把这5个学生的信息存储到数组中,并遍历数组,获取到每个学生的信息
Student[] arr = new Student[5]; arr[0] = new Student("张三", 23); arr[1] = new Student("李四", 24); arr[2] = new Student("王五", 25); arr[3] = new Student("赵六", 26); arr[4] = new Student("周七", 27); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); }
* B:画图演示
* 把学生数组的案例画图讲解
* 数组和集合存储引用数据类型,存的都是地址值
package com.heima.collection; import com.heima.bean.Student; public class Demo1_Array { public static void main(String[] args) { // int[] arr = new int[5]; // 创建基本数据类型数组 Student[] arr = new Student[5]; // 创建引用数据类型数组 arr[0] = new Student("张三", 23); // 创建一个学生对象,存储在数组的第一个位置 arr[1] = new Student("李四", 24); arr[2] = new Student("王五", 25); for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); // 默认调用toString的方法,如果Student类没有重写toString方法,则默认调用Object类的方法 } } }
集合的由来及集合继承体系图
* A:集合的由来
* 数组的长度是固定的,当添加的元素超过了数组的长度时需要对数组重新定义
* Java内部给我们提供了集合类,能存储任意对象,长度可以改变,随着元素的增加而增加
* B:数组和集合的区别
* 区别一:
* 数组 既可以存储基本数据类型,又可以存储引用数据类型;基本数据类型存储的是值,引用数据类型存储的是地址值
* 集合 只能存储引用数据类型;如果要存储基本数据类型,就需要进行装箱
* 区别二:
* 数组的长度是固定的,不能自动增长
* 集合的长度是可变的,可以根据元素的增加而增长
* C:数组和集合什么时候用
* 如果元素的个数是固定的,推荐用数组
* 如果元素的个数不是固定的,推荐用集合
* D:集合继承体系图
Collection集合的基本功能测试
* A:案例演示
基本功能演示 boolean add(E e) boolean remove(Object o) void clear() boolean contains(Object o) boolean isEmpty() int size()
* B:注意
* collectionXxx.java 使用了未经检查或不安全的操作
* 要了解详细信息,请使用 -Xlint:inchecked 重新编译
* java编译器认为该程序存在安全隐患
public String toString() { Iterator<E> it = iterator(); if (! it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); if (! it.hasNext()) return sb.append(']').toString(); sb.append(',').append(' '); } }
package com.heima.collection; import java.util.ArrayList; import java.util.Collection; import com.heima.bean.Student; @SuppressWarnings({ "rawtypes", "unchecked" }) public class Demo2_Collection { public static void main(String[] args) { Collection c = new ArrayList(); // 父类引用指向子类对象 // demo1(c); demo2(c); } public static void demo2(Collection c) { c.add("a"); c.add("b"); c.add("c"); c.add("d"); c.remove("c"); // 删除指定元素 System.out.println(c); System.out.println(c.contains("a")); // 判断是否包含指定元素 c.clear(); // 彻底清空集合 System.out.println(c); System.out.println(c.isEmpty()); // 判断是否是空集合 System.out.println(c.size()); // 获取集合中包含的元素的个数,类似于字符串中的length()方法 } public static void demo1(Collection c) { // add方法: 如果是List集合,一直都返回true,因为List集合中是可以存储重复元素的 // 如果是set 集合,当存储重复元素时,就会返回false boolean b1 = c.add("abc"); // 可以添加任意对象,任意对象都是Object的子类 boolean b2 = c.add(true); // 自动装箱 new Boolean(true); boolean b3 = c.add(100); // 自动装箱 new Integer(100); boolean b4 = c.add(new Student("张三", 23)); boolean b5 = c.add("abc"); // 都是true System.out.println(b1); System.out.println(b2); System.out.println(b3); System.out.println(b4); System.out.println(b5); System.out.println(c); // ArrayList的爷爷类重写了toString方法 } }
集合转数组遍历
* A:集合的遍历
* 其实就是依次获取集合中的每一个元素
* B:案例演示
* 把集合转换成数组,可以实现集合的遍历
* toArray()
Collection c = new ArrayList(); c.add(new Student("张三", 23)); // Object obj = new Student("张三", 23) c.add(new Student("李四", 24)); c.add(new Student("王五", 25)); c.add(new Student("赵六", 26)); Object[] arr = coll.toArray; // 将集合转换为数组 for (int i = 0; i < arr.length; i++) { Student s = (Student)arr[i]; // 强转成Student System.out.println(s.getName() + "," + s.getAge()); }
package com.heima.collection; import java.util.ArrayList; import java.util.Collection; import com.heima.bean.Student; @SuppressWarnings({ "rawtypes", "unchecked" }) public class Demo3_Collection { public static void main(String[] args) { // demo1(); // demo2(); } public static void demo2() { Collection c = new ArrayList(); c.add(new Student("张三", 23)); // 向数组内存入自定义的引用对象 c.add(new Student("李四", 24)); c.add(new Student("王五", 25)); c.add(new Student("赵六", 26)); Object[] arr = c.toArray(); // 向上转型 提升为Object类 for (int i = 0; i < arr.length; i++) { // System.out.println(arr[i]); Student s = (Student) arr[i]; // 强制向下转型 System.out.println(s.getName() + "..." + s.getAge()); } } public static void demo1() { Collection c = new ArrayList(); c.add("a"); c.add("b"); c.add("c"); c.add("d"); Object[] arr = c.toArray(); // 将集合转换成数组 for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); } } }
Collection集合的带All功能测试
* A:案例演示
带All的功能演示
boolean addAll(Collection c) boolean removeAll(Collection c) boolean containsAll(Collection c) boolean retainAll(Collection c)
package com.heima.collection; import java.util.ArrayList; import java.util.Collection; public class Demo4_Collection { public static void main(String[] args) { // demo1(); // 整体添加 // demo2(); // 删除交集 // demo3(); // 是否包含 // demo4(); // 取交集 } public static void demo4() { Collection c1 = new ArrayList(); c1.add("a"); c1.add("b"); c1.add("c"); c1.add("d"); Collection c2 = new ArrayList(); c2.add("a"); c2.add("b"); c2.add("z"); c2.add("c"); c2.add("d"); boolean b = c1.retainAll(c2); // 取交集,如果调用的集合改变就返回true,如果调用的集合不变就返回false System.out.println(b); System.out.println(c1); } public static void demo3() { Collection c1 = new ArrayList(); c1.add("a"); c1.add("b"); c1.add("c"); c1.add("d"); Collection c2 = new ArrayList(); c2.add("a"); c2.add("b"); c2.add("z"); boolean b = c1.containsAll(c2); // 判断调用的集合是否包含传入的集合,如果出现一个元素不包含就返回false,可以有重复 System.out.println(b); } public static void demo2() { Collection c1 = new ArrayList(); c1.add("a"); c1.add("b"); c1.add("c"); c1.add("d"); Collection c2 = new ArrayList(); c2.add("a"); c2.add("b"); c2.add("z"); boolean b = c1.removeAll(c2); // 如果有交集,就删除并返回true; 如果没有交集就不删除并且返回false System.out.println(b); System.out.println(c1); } public static void demo1() { Collection c1 = new ArrayList(); c1.add("a"); c1.add("b"); c1.add("c"); c1.add("d"); Collection c2 = new ArrayList(); // alt + shift + r 可以整体改名 c2.add("a"); c2.add("b"); c2.add("c"); c2.add("d"); c1.addAll(c2); // 将c2中的每一个元素都 添加到c1中 c1.add(c2); // 将c2整个集合看成 一个对象 添加到c1中 System.out.println(c1); } }
迭代器遍历
* A:迭代器概述
* 集合是用来存储元素的,存储的元素要查看,那么就需要迭代(遍历)
* 案例演示
迭代器的使用
Collection c = new ArrayList(); c.add("a"); c.add("b"); c.add("c"); c.add("d"); Iterator it = c.iterator(); while (it.hasNext()) { System.out.println(it.next()); }
package com.heima.collection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import com.heima.bean.Student; public class Demo5_Collection { public static void main(String[] args) { // demo1(); // demo2(); } public static void demo2() { // 迭代自定义类 Collection c = new ArrayList(); c.add(new Student("张三", 23)); // 自动提升为Object类 c.add(new Student("李四", 24)); c.add(new Student("王五", 25)); c.add(new Student("赵六", 26)); // 获取迭代器 Iterator it = c.iterator(); while (it.hasNext()) { // System.out.println(it.next()); Student s = (Student) it.next(); // 向下转型,注意next方法调用时的指针位置变化 System.out.println(s.getName() + "..." + s.getAge()); } } public static void demo1() { Collection c = new ArrayList(); c.add("a"); c.add("b"); c.add("c"); c.add("d"); // 对集合中的元素进行迭代(遍历) Iterator it = c.iterator(); // 获取迭代器 /* * boolean b1 = it.hasNext(); // 判断集合中是否有元素 * System.out.println(b1); // * Object obj1 = it.next(); // next方法获取相应元素,并且将指针向后移动一位 * System.out.println(obj1); */ while (it.hasNext()) { System.out.println(it.next()); } } }
迭代器的原理和源码解析
* A:迭代器原理
* 迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以没一个集合的存和取的方式都是不一样的
* 那么这就需要在每一个类中定义hasNext() 和 next() 方法,这样做可以但是会使集合体系过于臃肿
* 迭代器就是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己的迭代方法
* 好处:1、规定了整个集合体系的遍历方式都是hasNext() 和next() 方法;2、代码由底层内部实现,使用者不用管怎么实现,会用即可
* B:迭代器源码分析
* 1、在eclipse 中ctrl + shift + t 找到ArrayList类
* 2、ctrl + o 查找 iterator() 方法
* 3、查看返回值类型是new Itr(), 说明Itr这个类实现 Iterator接口
* 4、查找 Itr这个内部类,发现重写了 Iterator中的所有抽象方法
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; // prevent creating a synthetic constructor Itr() {} public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
List集合的特有功能概述和测试
* A:List集合的特有功能概述
void add(int index, E element) E remove(int index) E get(int index) E set(int index, E element)
package com.heima.list; import java.util.ArrayList; import java.util.List; public class Demo1_List { public static void main(String[] args) { // demo1(); // 元素添加 // demo2(); // 元素删除 // demo3(); // remove 注意点 // demo4(); // 通过索引获取元素 // demo5(); // 指定元素修改 } public static void demo5() { List list = new ArrayList(); list.add(0, "a"); list.add(0, "b"); list.add(0, "c"); list.add(0, "d"); list.set(1, "z"); // 将指定位置的元素修改 System.out.println(list); } public static void demo4() { List list = new ArrayList(); list.add(0, "a"); list.add(0, "b"); list.add(0, "c"); list.add(0, "d"); // Object obj1 = list.get(0); // System.out.println(obj1); // 通过索引遍历List集合 for (int i = 0; i < list.size(); i++) { // 用 size() 方法 System.out.println(list.get(i)); } } public static void demo3() { List list = new ArrayList(); list.add(111); list.add(222); list.add(333); list.add(444); Object obj1 = list.remove(111); // 删除的时候不会自动装箱,111被当成索引,下标就越界了 System.out.println(obj1); } public static void demo2() { List list = new ArrayList(); list.add(0, "a"); list.add(0, "b"); list.add(0, "c"); list.add(0, "d"); Object obj1 = list.remove(0); // 通过索引删除元素,将被删除的元素返回 System.out.println(obj1); System.out.println(list); } public static void demo1() { List list = new ArrayList(); // 多态,有弊端,不能访问子类的特有属性 list.add("a"); list.add("b"); list.add(0, "c"); // index是元素添加后所在的位置 list.add(0, "d"); // list.add(5, "e"); // 注意索引越界异常,0<=index<=size System.out.println(list); } }
List集合存储学生对象并遍历
* A:案例演示
* 通过size() 和get() 方法结合使用遍历
package com.heima.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.heima.bean.Student; public class Demo2_List { public static void main(String[] args) { List list = new ArrayList(); list.add(new Student("张三", 23)); // 自动向上转型为Object list.add(new Student("李四", 24)); list.add(new Student("王五", 25)); list.add(new Student("赵六", 26)); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); // 通过索引获取每一个元素 Student stu = (Student) list.get(i); System.out.println(stu.getName() + "..." + stu.getAge()); } } }
并发修改异常
* A:案例演示
* 需求:如果有一个集合,判断集合内是否有 "world" 这个元素,如果有,就添加一个 "javaee" 元素
List list = new ArrayList(); list.add("a"); list.add("b"); list.add("world"); list.add("c"); list.add("d"); list.add("e"); ListIterator it = list.listIterator(); while (it.hasNext()) { Object object = it.next(); System.out.println(object); if (object.equals("world")) { list.add("javaee"); it.add("javaee"); } }
* B:ConcurrentModificationException出现
* 迭代器遍历,集合修改集合
* C:解决方案
* a:迭代器迭代元素,迭代器修改元素 (ListIterator的特有功能 add)
* b:集合遍历元素,集合修改元素
ListIterator lit = list.listIterator; // 如果向在遍历的过程中添加元素,可以用ListIterator中的add方法 while(lit.hasNext()) {
String str = (String)lit.next; if(str.equals("world")) { lit.add("javaee"); }
}
package com.heima.list; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class Demo3_List { public static void main(String[] args) { List list = new ArrayList(); list.add("a"); list.add("b"); list.add("world"); list.add("c"); list.add("d"); list.add("e"); ListIterator it = list.listIterator(); // 获取迭代器 while (it.hasNext()) { // 判断集合中是否有元素 String object = (String) it.next(); // 向下转型 if (object.equals("world")) { // list.add("javaee"); // 遍历的同时在增加元素,产生并发修改异常 it.add("javaee"); } } System.out.println(list); } }
ListIterator
boolean hasNext() boolean hasPrevious() Object next() Object previous()
package com.heima.list; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class Demo4_ListIterator { public static void main(String[] args) { List list = new ArrayList(); list.add("a"); list.add("b"); list.add("world"); list.add("c"); list.add("d"); list.add("e"); ListIterator lit = list.listIterator(); // 获取迭代器 while (lit.hasNext()) { System.out.println(lit.next()); // 获取元素,并将指针向后移动 } System.out.println("-----------"); while (lit.hasPrevious()) { System.out.println(lit.previous()); // 获取元素,并将指针向前移动 } } }
Vector的特有功能
* A:Vector类概述
* B:Vector类特有功能
public void addElements(E obj) public E elementAt(int index) public Enumeration elements()
* C:案例演示
* Vector迭代
package com.heima.list; import java.util.Enumeration; import java.util.Vector; public class Demo5_Vector { public static void main(String[] args) { Vector v = new Vector(); v.addElement("a"); v.addElement("b"); v.addElement("c"); v.addElement("d"); Enumeration en = v.elements(); // 获取枚举 while (en.hasMoreElements()) { // 判断集合中是否有元素 System.out.println(en.nextElement()); // 获取集合中的元素 } } }
数据结构之数组和链表
* A:数组
* 查询快,修改也快
* 增删慢
* B:链表
* 查询慢,修改野蛮
* 增删快
Node<E> node(int index) { // assert isElementIndex(index); 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; } }
List的三个子类的特点
* A:List的三个子类的特点
* ArrayList:
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
* Vector:
底层数据结构是数组,查询快,增删慢
线程安全,效率低
Vector相对ArrayList查询慢(线程安全)
Vector相对LinkedList增删满(数据结构)
* LinkedList:
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
* Vector和ArrayList的区别
Vector是线程安全的,效率低
ArrayList是线程不安全的,效率高
共同的:都是数组实现的
* ArrayList和LinkedList的区别
ArrayList底层是数组结构,查询和修改快
LinkedList底层是链表结构,查询慢修改快
共同的:都是线程不安全的
* List的三个儿子的使用
* 查询多 -> ArrayList
* 增删多 -> LinkedList
* 都多 -> ArrayList
* Vector一般只在面试的时候会问