一、 List集合特有的功能概述
因为List集合继承与Collection,所有有些方法类似。详细介绍一些List特有的功能。List也是一个接口。故不能新建对象,所以我们调用子类ArrayList
- void add(int index,E element)
在指定位置添加元素
List list =new ArrayList();
list.add("a"); //从0开始
list.add("b");
list.add("c");
list.add("d");
list.add(1,"e");
list.add(10,"f");//java.lang.IndexOutOfBoundsException,
//当存储时使用不存在的索引会存在数组越界。当然index可以小于等于size。
System.out.println(list);
效果如下:
———————————————————————————————————————
- E remove(int index)
在指定位置删除元素
List list =new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//记录被删除的元素
Object obj =list.remove(1);
System.out.println(obj);
System.out.println(list);
效果如下:
tips:remove方法传入的参数是索引,函数返回的是Object对象。
弊端:当我们传入的是数字的时候,他会把数字当成索引。
List list = new ArrayList();
list.add(111);
list.add(222);
list.add(333);
list.remove(111); //删除的时候不会自动装箱,把111当作索引
System.out.println(list);
效果如下:
———————————————————————————————————————
- E get(int index)
传入的参数是索引,我们可以通过索引获取单个元素。所以我们可以通过for循环来遍历List集合,这是List集合特有的遍历方式
List list =new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
//Object object1 =list.get(0);
//System.out.println(object1);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));
}
效果如下:
———————————————————————————————————————
- E set(int index,E element)
修改值,把指定位置的元素修改掉
List list =new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.set(1, "z");
System.out.println(list);
效果如下:
二、 List集合存储对象并遍历
在不传入泛型的情况下(需要进行向下转型,后面会引入泛型):
List list =new ArrayList();
list.add(new Student("张三",12));//Object obj =new Student("张三",12);
list.add(new Student("李四",13));
list.add(new Student("王二",14));
list.add(new Student("赵六",15));
for (int i = 0; i < list.size(); i++) {
//单纯的遍历
System.out.println(list.get(i));
//通过索引获取每一个元素
Student s = (Student) list.get(i);
System.out.println(s.getName()+" "+s.getAge());
}
效果如下:
三、 集合框架(并发修改异常产生的原因及解决方案)
需求:我有一个集合,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。
List list =new ArrayList();
list.add("a");
list.add("b");
list.add("world");
list.add("c");
list.add("d");
list.add("e");
Iterator it =list.iterator();
while (it.hasNext()) {
//进行强转的原因是因为list添加进去的元素被提升为Object类型
String str = (String) it.next();
if ("world".equals(str)) {
list.add("javaee");
}
System.out.println(list);
}
效果如下:
此为并发修改异常当放大检测到对象的并发修改,但不允许这种修改时,抛出异常。也就是说,集合在添加的时候并没有告诉迭代器,将要添加数据,而是迭代器自主突然想要添加数据。遍历的同时也在增加元素。并发修改,进行了报错异常。
———————————————————————————————————————
解决方案:
迭代器迭代元素,使用专门的迭代器添加元素(ListIterator())
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(); //List集合特有
while (lit.hasNext()) {
String str = (String)lit.next();
if ("world".equals(str)) {
lit.add("javaee");
}
}
System.out.println(list);
}
效果如下:
四、 ListIterator介绍(了解即可)
- boolean hasNext()是否有下一个
- boolean hasPrevious()是否有前一个
- Object next()返回下一个元素
- Object previous();返回上一个元素
List list = new ArrayList();
list.add("a");
//Object obj = new String();
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());
//获取元素并将指针向前移动
}
如果我们注释hasNext()方法,那么hasPrevious(),什么也遍历不出。因为我们只有先执行hasNext()方法之后,指针才会往后移动。随后hasPrevious()才会调出结果。
五、Vector—— List下的Vector
Vector类特有功能
- public void addElement(E obj)
- public E elementAt(int index)
- public Enumeration elements() //枚举
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());
//获取集合中的元素
}
}
六、 ArrayList——去除ArrayList中重复字符串元素方式
- 分析:
- 1.创建新集合
- 2.根据传入的集合(老集合获取迭代器)
- 3.遍历老集合
- 4.通过新集合判断是否包含老集合的元素,如果包含就不添加,如果不包含就添加
public class Demo1_ArrayList {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList list =new ArrayList();
list.add("a");
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("c");
ArrayList newList=getSingle(list);
System.out.println(newList);
}
public static ArrayList getSingle(ArrayList list) {
ArrayList newList =new ArrayList(); //1.创建新集合
Iterator it =list.iterator(); //2.根据传入的集合(老集合)获取迭代器
while (it.hasNext()) { //3.遍历老集合
Object obj =it.next(); //记录住每一个元素
if (!newList.contains(obj)) {
newList.add(obj);
}
}
return newList;
}
}
效果如下:
七、ArrayList—— 去除ArrayList中重复自定义对象元素(重点)
案例:
第一步:新建Bean集合
public class Person {
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 Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
//注意该处重写了equals方法
@Override
public boolean equals(Object obj) {
Person p =(Person)obj;
return this.name.equals(p.name) &&this.age == p.age;
}
}
public class Demo2_ArrayList {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList list =new ArrayList();
//创建集合对象
list.add(new Person("张三",12));
list.add(new Person("张三",12));
list.add(new Person("李四",13));
list.add(new Person("李四",13));
list.add(new Person("李四",13));
list.add(new Person("李四",13));
ArrayList newList =getSingle(list);
//调用方法去除重复
System.out.println(newList);
}
public static ArrayList getSingle(ArrayList list) {
ArrayList newList =new ArrayList();
//创建新集合
Iterator it =list.iterator();
//根据传入的集合(老集合)获取迭代器
while (it.hasNext()) {
//遍历老集合
Object object =it.next();
//记录住每一个元素
if (!newList.contains(object)) {
//如果新集合中不包含老集合中的元素
newList.add(object) ; //将该元素添加
}
}
return newList;
}
}
效果如下:
tips:注意该处
重写了父类的equals。因为父类中的方法的contains方法,里面进行判断用的是equals()方法,我们需要进行修改。当然如果我们调用remove()方法,依旧依赖于equals()方法,进行包含判断。
八、 LinkedList——LinkedList的特有功能
- public void addFirst(E e)及addLast(E e)
addFirst()是在数组的头部添加,addLast()是在数组的尾部添加。
LinkedList list =new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
list.addLast("e");
System.out.println(list);
效果如下:
———————————————————————————————————————
- public E getFirst()及getLast()
getFirst()获得第一个元素,getLast()获得最后一个元素
LinkedList list =new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
list.addLast("e");
System.out.println(list);
System.out.print("第一个是");
System.out.println(list.getFirst());
System.out.print("最后一个是");
System.out.println(list.getLast());
效果如下:
———————————————————————————————————————
- public E removeFirst()及public E removeLast()
removeFirst()删除第一个元素,removeLast删除最后一个元素
LinkedList list =new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
list.addLast("e");
System.out.print("删除第一个元素");
System.out.println(list.removeFirst());
System.out.print("删除第一个元素");
System.out.println(list.removeLast());
System.out.println(list);
效果如下:
———————————————————————————————————————
- public E get(int index);
参数传入的是索引,可以通过索引找出数
LinkedList list =new LinkedList();
list.addFirst("a");
list.addFirst("b");
list.addFirst("c");
list.addFirst("d");
list.addLast("e");
System.out.println(list.get(1));
效果如下:
———————————————————————————————————————
九、 用LinkedList模拟栈数据结构的集合并测试(重点)
分析我们使用LinkedList中的addLast()方法模拟进栈,removeLast()模拟出栈。因为我们是模拟栈,所以最好使用一个类,把LinkedList封装到类中,类的名字为栈。
public class Stack {
private LinkedList list =new LinkedList();
//模拟进栈方法
public void in(Object obj) {
list.addLast(obj);
}
//模拟出栈
public Object out() {
return list.removeLast();
}
//模拟栈结构是否为空
public boolean isEmpty() {
return list.isEmpty();
}
}
调用调试:
Stack stack = new Stack();
stack.in("a");
stack.in("b");
stack.in("c");
stack.in("d");
while (!stack.isEmpty()) {
System.out.println(stack.out());
}
在此基础上我们会可以模拟队列,队列是先进先出,只要修改removeLast()改为removeFirst()
十、 List三个子类的特点
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
Vector相对ArrayList查询慢(线程安全的)
Vector相对LinkedList增删慢(数组结构)
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
Vector和ArrayList的区别
Vector是线程安全的,效率低
ArrayList是线程不安全的,效率高
共同点:都是数组实现的
ArrayList和LinkedList的区别
ArrayList底层是数组结果,查询和修改快
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢
共同点:都是线程不安全的
List有三个儿子,我们到底使用谁呢?
查询多用ArrayList
增删多用LinkedList
如果都多ArrayList
Vector面试的时候用,其已经被ArrayList代替。线程安全一般用vector但是后面会使用工具类,把线程不安全的数组改成线程安全的。所以Vector用的比较少。
十一、 增强for(For-Each)的概述和使用
增强for概述
简化数组和Collection集合的遍历
格式:
for(元素数据类型 变量 : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
当我们遍历数组和集合
int arr[] = {11,22,33,44,55,66};
List<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) {
System.out.print(string);
}
System.out.println();
for (int i : arr) {
System.out.print(i);
}
当我们遍历对象的时候
List<Person> list =new ArrayList<Person>();
list.add(new Person("张三 ", 12));
list.add(new Person("李四 ", 13));
list.add(new Person("王五 ", 14));
for (Person person : list) {
System.out.println(person);
}
增强for循环底层依赖的是迭代器(Iterator)
十二、 三种迭代的能否删除
普通for循环
List<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("b");
list.add("d");
//1.普通for循环删除
for (int i = 0; i < list.size(); i++) {
if ("b".equals(list.get(i))) {
list.remove(i--);
//通过索引删除元素,应该改为remove(i--)使元素往后移动一位
}
}
System.out.println(list);
效果如下:
———————————————————————————————————————
迭代器删除
//方法一:
Iterator<String> iterator =list.iterator();
while (iterator.hasNext()) {
if ("b".equals(iterator.next())) {
//list.remove("b");
//不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
iterator.remove();
}
}
//方法二:
for (Iterator<String> iterator2 =list.iterator();iterator2.hasNext(); ) {
if ("b".equals(iterator.next())) {
//list.remove("b");
//不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
iterator.remove();
}
}
System.out.println(list);
tips:以上为两种不同的写法,并非不同的方法。
———————————————————————————————————————
增强for循环
该方法不能删除 只能遍历;
十三、 数组转集合以及集合转数组
数组转集合方法:Arrays工具类的asList()方法的使用
该方法用于将数组转换为集合,但是不能进行集合的增加和删除元素操作,但是可以运行一些迭代器进行遍历挑选。
String [] arr= {"a","b","c"};
List<String> list = Arrays.asList(arr);
list.add("d");
//该处不能添加
System.out.println(list);
//报错
———————————————————————————————————————
当我们存储一些int类型的基本类型数据的时候,将整个数组当成一个对象存储在集合中
注意该泛型应该是一个int型的数组
int [] arr= {11,22,33,44,55};
List<int []> list =Arrays.asList(arr);
//
System.out.println(list);
效果如下:
处理方法:
Integer[ ] arr= {11,22,33,44,55};
//数组必须是引用基本类型
List<Integer > list =Arrays.asList(arr);
System.out.println(list);
集合转数组方法:
Collection中toArray(T[] a)泛型版的集合转数组
ArrayList<String> list =new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
String[] arr=list.toArray(new String[0]);
//后面数组的0,当集合转换为数组时
//数组的长度如果是小于等于集合的size()时,转换后的数组长度等于集合size()
//如果数组长度大于集合长度,那么会输出null
for (String string : arr) {
System.out.println(string);
}
效果如下:
———————————————————————————————————————
十四、 集合嵌套之ArrayList嵌套ArrayList
学科为大集合,学科又分为若干个班级
ArrayList<ArrayList<Person>> list =new ArrayList<ArrayList<Person>>();
ArrayList<Person> list1 = new ArrayList<Person>();
list1.add(new Person("小明",12));
list1.add(new Person("小红",13));
ArrayList<Person> list2 = new ArrayList<Person>();
list2.add(new Person("张三",14));
list2.add(new Person("李四",15));
list.add(list1);
list.add(list2);
//遍历学科集合
for (ArrayList<Person> A : list) {
for (Person person : A) {
System.out.println(person);
}
}
效果如下: