List
1. List集合概述和特点
1.1 List 集合概述:
1、 List是个接口List
2、 List 集合也称为有序集合(序列)用户可以控制列表中每个元素插入到集合的位置,可以通过整数索引(列表中元素的位置)访问元素
3、 与Set集合不同,列表通常允许重复的元素
1.2 List 集合特点:
1、 有序:存储和取出的元素顺序一致
2、 可重复:存储的元素可以重复
public static void main(_String[] args) {
// 创建List集合对象,通过多态继承Collection的ArrayList
List<_String_> list = new ArrayList<_String_>()_;
// 添加List元素<br /> list.add_(_"hello"_)_;<br /> list.add_(_"world"_)_;<br /> // List集合的有序性<br /> list.add_(_"0101"_)_;<br /> // List集合的可重复性<br /> list.add_(_"java"_)_;<br /> list.add_(_"java"_)_;
// 输出集合<br /> System._out_.println_(_list_)_;<br /> /* 使用Collection中的迭代器方式遍历:<br /> 1.首先使用list调用iterator()迭代器的方法<br /> 2.在使用补全对象ctrl+alt+v生成实例对象 */<br /> Iterator_<_String_> _iterator = list.iterator_()_;<br /> while _(_iterator.hasNext_()){<br /> _String s = iterator.next_()_;<br /> System._out_.println_(_s_)_; _} }_
1.3 List 集合特有方法:
void add(int index, E element) 在集合中的指定位置插入指定的元素
E remove(int index) 删除指定索引处的元素,返回被删除的元素
E set(int index , E element) 修改指定索引处的元素,返回被修改的元素
E get(int index) 返回指定索引处的元素
public static void main(_String[] args) {
// 创建List集合对象,通过多态继承Collection的ArrayList
List<_String_> list = new ArrayList<_String_>()_;
// 添加List元素<br /> list.add_(_"hello"_)_;<br /> list.add_(_"world"_)_;<br /> list.add_(_"java"_)_;<br /> // void add(int index, E element) 在集合中的指定位置插入指定的元素<br /> list.add_(_1,"cainiao"_)_; // [hello, cainiao, world, java]<br /> // IndexOutOfBoundsException报错 只能添加现有索引<br /> list.add_(_11,"cainiao"_)_;<br /> // E remove(int index) 删除指定索引处的元素,返回被删除的元素<br /> System._out_.println_(_list.remove_(_1_))_;//cainiao ,[hello, world, java]<br /> // E set(int index , E element) 修改指定索引处的元素,返回被修改的元素<br /> System._out_.println_(_list.set_(_1,"javaee"_))_; //[hello, javaee, world, java]<br /> // E get(int index) 返回指定索引处的元素<br /> System._out_.println_(_list.get_(_1_))_; // world<br /> // 输出集合<br /> System._out_.println_(_list_)_; // [hello, world, java] _}_<br />_---------------------------------------_<br />_// 使用get()方法遍历集合_<br />public static void main_(_String_[] _args_) {<br /> _// 创建List集合对象,通过多态继承Collection的ArrayList<br /> List_<_String_> _list = new ArrayList_<_String_>()_;
// 添加List元素<br /> list.add_(_"hello"_)_;<br /> list.add_(_"world"_)_;<br /> list.add_(_"java"_)_;
// 遍历集合使用for循环,判断i小于集合的大小,因为不能超过总索引<br /> for _(_int i = 0; i < list.size_()_; i++_) {_<br />// 遍历集合使用get()方法__ _String s = list.get_(_i_)_;<br /> System._out_.println_(_s_)_; _} }_
案例: List 集合存储学生对象并遍历:
需求:创建一个存储学生对象的结合,存储3个学生对象,使用程序是现在控制台遍历该集合
思路:
1.定义学生类
2.创建list集合对象
3.创建学生对象
4.把学生添加到集合
5.遍历集合(迭代器方式,for循环方式)
// 创建一个学生类
public class Student {
_private String name;
private int age;
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 Student() { }
public Student(String name, int age) {
this.name = name;
this.age = age; } }
——————————————————————————-
// 创建集合类
public class ListDemo {
public static void main(String[] args) {
// 创建List集合对象,通过多态继承Collection的ArrayList
List<_Student_> list = new ArrayList<_Student_>();
// 创建学生对象
Student s = new Student(“李畅”, 12);
Student s1 = new Student(“赵明”, 22);
Student s2 = new Student(“唐明”, 23);
// 添加List元素
list.add(s);
list.add(s1);
list.add(s2);
// Iterator迭代器的泛型类一定要与集合保持一致,集合的泛型类
Iterator
while (iterator.hasNext()) {
Student next = iterator.next();
System._out.println(_next.getName() + “,” + next.getAge()); }
// 遍历集合使用get()方法
for (int i = 0; i < list.size(); i++) {
Student s3 = list.get(i);
System._out.println(_s3.getName() + “,” + s3.getAge()); } } }_
并发修改异常的源码分析:
ConcurrentModificationException异常:
public class com15 {
public static void main(String[] args) {
List<_String_> list = new ArrayList<_String_>()_;
list.add_(_"hello"_)_;<br /> list.add_(_"world"_)_;<br /> list.add_(_"java"_)_;
Iterator_<_String_> _it = list.iterator_()_;<br />/* while (it.hasNext()){<br /> // ConcurrentModificationException异常<br /> String s = it.next();<br /> // 通过String.equals()方法判断字符串是否相同<br /> if (s.equals("world")){<br /> // 通过list.add()方法<br /> list.add(1,"javaee");<br /> }<br /> }*/<br /> // 通过for循环,遍历list的大小,获取索引i<br /> for _(_int i = 0; i < list.size_()_; i++_) {<br /> _//通过list.get()索引i, 用实例化s接受在索引i上的元素<br /> String s = list.get_(_i_)_;<br /> // 通过String.equals()方法判断字符串是否相同<br /> if _(_s.equals_(_"world"_)){<br /> _list.add_(_1,"javaee"_)_;<br /> _}<br /> }<br /> _System._out_.println_(_list_)_; _} }_
并发修改异常的源码分析:
总结:通过源码看出list的方法中add()方法是有判断 modCount 实际修改集合的次数,和expectedModCount 预计修改集合的次数是否相等,不等则抛出异常ConcurrentModificationException
if (modCount != expectedModCount) throw new ConcurrentModificationException();
但是list.get()方法中并没有对此方法的校验
public interface List
// 因为是接口所以方法没法实现
Iterator
// list.add()
boolean add(E e);
// list.get()
E get(int index);
}
public abstract class AbstractList
// modCount:实际修改集合的次数
// expectedModCount:预计修改集合的次数
// 被protected修饰的成员对于本包和其子类可见,不同包的子类也可见
protected int modCount = 0;
}
public class ArrayList
public boolean add(E e) {<br /> ensureCapacityInternal(size + 1); // Increments modCount!!<br /> elementData[size++] = e;<br /> return true;<br /> }
public E get(int index) {<br /> rangeCheck(index);<br /> return elementData(index);<br /> }
public Iterator<E> iterator() {<br /> return new Itr();<br /> }
private class Itr implements Iterator<E> {<br /> int expectedModCount = modCount;
public E next() {<br /> checkForComodification();<br /> int i = cursor;<br /> if (i >= size)<br /> throw new NoSuchElementException();<br /> Object[] elementData = ArrayList.this.elementData;<br /> if (i >= elementData.length)<br /> throw new ConcurrentModificationException();<br /> cursor = i + 1;<br /> return (E) elementData[lastRet = i];<br /> }
final void checkForComodification() {<br /> if (modCount != expectedModCount)<br /> throw new ConcurrentModificationException();<br /> }<br /> }<br />}
修饰符回顾:
- 解释:
- private: 只能被基类访问
- 无修饰符: 被基类,子类和同package的类访问
- protected: 在无修饰符的基础上,加了与基类不同包,但是是子类的访问权限,这个访问权限只在子类访问自身的实例时才有,超类的实例还是不能访问的
- public: 全都可以访问
- 通俗解释:<br /> 包就相当于一个家族。不同包有可能有继承的分支,也有可能毫无关系。
- 类内的成员就相当于资源。
- private: 私有资源,只能自己使用
- default: 家族,我自己,我子孙可以用
- protected: 我可以开放,但是只给自己家族的但是嫁到或者入赘其它家族的后代使用
- public: 谁都可以用,水资源
1.4 ListIterator:
ListIterator(列表迭代器)
1. 通过List集合的listIterator()方法得到的, 所以是List集合特有的迭代器
1. public interface ListIterator<E> extends Iterator<E>
1. 列表迭代器继承迭代器, 同样列表迭代器可以使用迭代器所有的方法
1. 用于程序员沿任意方向遍历列表的列表迭代器, 在迭代期间修改增删列表,并获取迭代器的当前位置
ListIterator(列表迭代器)的常用方法
1. E **next**() : **返回第二代中的下一个元素**
1. boolean **hasNext**(): **如果迭代具有更多元素, 则返回true**
1. E **previous**(): **返回列表中的上一个元素**
1. boolean **previous**(): **如果该列表迭代器在相反方向时具有上一个元素, 则返回true**
1. void** add(E e)**: **将指定的元素插入列表**
public class ListIteratorDemo {
_public static void main(String[] args) {
// 创建一个集合对象
List<_String_> list = new ArrayList<_String_>();
// 添加列表元素
list.add(“hello”);
list.add(“world”);
list.add(“java”);
/ 通过list中的listIterator()方法得到ListIterator
List集合特有的迭代器,通过ctrl+alt+v 生成实例对象
使用listIterator集合迭代器中hasNext()以及next()方法遍历该集合
ListIterator
while(lit.hasNext()){
String s = lit.next();
System.out.println(s); // hello world java }
System.out.println(“———————————“);
// 使用listIterator集合迭代器中hasPrevious()以及previous()方法逆向遍历该集合
/ while (lit.hasPrevious()){
String s = lit.previous();
System.out.println(s); // java world hello
}/
// 获取列表列表迭代器,list的iterator迭代器无法直接使用add()方法,listIterator可以
ListIterator<_String_> lIt = list.listIterator();
while(lIt.hasNext()){
String s = lIt.next();
if (s.equals(“java”)){
// 因为list有对修改集合的次数做校验,只能通过ListItertor的add()添加 __ _lIt.add(“javaee”); } }
System._out.println(_list); } }_
1.5 增强for循环:
增强for: 简化数组和Collection集合的遍历
1、实现iterable接口的类允许其对象成为增强型for语句的目标,所以Collection体系的集合都可以使用增强for循环,
2、JDK1.5 以后新增功能,增强for循环的底层逻辑是封装了iterator()迭代器方法
Tips: 使用增强for循环大大减少代码的冗余。如果使用传统for i的循环,判断方式还要根据是集合还是数组进行循环,数组是arr.length()根据数组长度,集合是list.size()集合大小
增强for语句的格式
格式:
for(元素数据类型(int…) 变量名(自定义 i.. 遍历的每一个变量 ):数组或者Collection集合){
// 在此处使用变量即可,该变量就是元素
}
范例:
int[] arr = {1,2,3,4,5};
for(int i : arr){
sout(i);
}
int[] _arr = {1,2,3,4,5};
/
增强for循环
for(元素的数据类型 变量名 : 遍历的集合或者数组){
使用遍历的元素就是遍历出来的变量 }
/
// int 数组遍历
// int是元素类型,i是定义的变量代表每个元素,arr是遍历的数组
for (int i: arr){
System._out.println(_i);
// 1 2 3 4 5 } }_
案例: List 集合存储学生对象并用三种方式遍历:
需求:创建一个存储学生对象的结合,存储3个学生对象,使用程序是现在控制台遍历该集合
思路:
1.定义学生类
2.创建list集合对象
3.创建学生对象
4.把学生添加到集合
5.遍历集合—> 三种方式
1. 迭代器方式: list集合特有的遍历方式iterator
1. for循环方式: 普通for循环带索引遍历
1. 增强for循环方式: 增强for循环遍历 底层是迭代器遍历
代码实现:
public class Student {
_private String name;
private int age;
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 Student() { }
public Student(String name, int age) {
this.name = name;
this.age = age; } }
—————————————————————————————
public class SanBianLiDemo {
public static void main(String[] args) {
// 创建List集合对象,通过多态继承Collection的ArrayList
List<_Student_> list = new ArrayList<_Student_>();
// 创建学生对象
Student s = new Student(“李畅”, 12);
Student s1 = new Student(“赵明”, 22);
Student s2 = new Student(“唐明”, 23);
// 添加List元素
list.add(s);
list.add(s1);
list.add(s2);
// 迭代器循环方式:list集合特有的遍历方式iterator
Iterator<_Student_> it = list.iterator();
while (it.hasNext()){
Student iterator= it.next();
System._out.println(_iterator.getName()+”,”+iterator.getAge()); }
System._out.println(“—————————-“);
// 普通for循环,带索引循环遍历
for (_int i = 0; i < list.size(); i++) {
Student for1 = list.get(i);
System._out.println(_for1.getName()+”,”+for1.getAge()); }
System._out.println(“—————————-“);
// 增强for循环遍历该集合
for (_Student for2: list){
System._out.println(_for2.getName()+”,”+for2.getAge()); } } }_
2. List 集合子类特点
List 集合常用子类: ArrayList, LinkedList
2.1 ArrayList概述
ArrayList 实现List接口 可调整大小的数组实现
ArrayList集合底层数据结构是数组 , 数组查询快 , 但是增删慢
2.2 LinkedList概述
LinkedList 链表实现List接口, 实现所有可选列表操作
LinkedList 底层数据结构是链表, 链表查询慢 , 但是增删快
练习:
分别使用ArrayList 和 LinkedList 完成存储字符串并遍历
public class ListDemo {
_public static void main(String[] args) {
// 创建ArrayList集合对象
ArrayList<_String_> al = new ArrayList<_String_>();
al.add(“hello”);
al.add(“world”);
al.add(“java”);
// 使用增强for循环遍历该集合
for (String s : al){
System._out.println(_s); }
System._out.println(“————————“);
for (_int i = 0; i < al.size(); i++) {
String s = al.get(i);
System._out.println(_s); }
System._out.println(“———————-“);
// 列表al 调用 Iterator(迭代器)
Iterator<_String> it = al.iterator();
while (it.hasNext()){
String s = it.next();
System._out.println(_s); }
System._out.println(“————————“);
// 创建LinkedList集合
// 使用增强for循环遍历该集合
LinkedList<_String> ll = new LinkedList<_String_>();
ll.add(“hello”);
ll.add(“world”);
ll.add(“java”);
for (String s: ll){
System._out.println(_s); } } }_
2.3 LinkedList 集合特有功能
LinkedList 底层数据结构是链表,所以该集合有针对头结点(head)以及尾结点的操作方法
public void addFirst(E e) 在该列表头部插入指定的元素
public void addLast(E e) 将指定的元素追加到列表的末尾
public E getFirst(E e) 返回此列表中的第一个元素
public E getLast(E e) 返回此列表中的最后一个元素
public E removeFirst(E e) 从此列表中删除并返回第一个元素
public E removeLast(E e) 从此列表中删除并返回最后一个元素
// 创建LinkedList集合
// 使用增强for循环遍历该集合
LinkedList<_String> ll = new LinkedList<_String_>();
ll.add(“hello”);
ll.add(“world”);
ll.add(“java”);
System._out.println(_ll)_; // [hello, world, java]
// public void addFirst(E e) 在该列表头部插入指定的元素
// 该操作是直接将元素添加到索引0的位置就是添加到第一个元素
ll.addFirst(“你好”);
System.out.println(_ll)_; // [你好, hello, world, java]
// public void addLast(E e) 将指定的元素追加到列表的末尾
ll.addLast(“世界”);
System.out.println(_ll)_; // [你好, hello, world, java, 世界]
// public E getFirst(E e) 返回此列表中的第一个元素
System.out.println(_ll.getFirst())_; // 你好
// public E getLast(E e) 返回此列表中的最后一个元素
System.out.println(_ll.getLast())_; // 世界
// public E removeFirst(E e) 从此列表中删除并返回第一个元素
System.out.println(_ll.removeFirst())_; // 你好
// public E removeLast(E e) 从此列表中删除并返回最后一个元素
System.out.println(_ll.removeLast())_; // 你好