ArrayList
成员方法ListIterator()
ArrayList中listIterator()方法-----也是通过内部类创建ListIterator接口的子对象
源代码如下
***********************************************************************************************
***********************************************************************************************
***********************************************************************************************
ListIterator接口
1------有别于Iterator接口的方法:add(E ,e),set(E,e),hasPrevious(),previous(),remove()
2------逆向遍历的两种方法:hasPrevious(),previous()
3------继承自List接口的方法:next(),hasNext(),remove()
注:逆向遍历依赖于正向遍历
理解iterator()与listIterator()方法从产生机理和此方法返回值类型,也即对应的接口去理解比较
实例1 关于add()和remove()方法的使用
package 测试集;
import java.util.ArrayList;
import java.util.ListIterator;
//说明:强化对remove的理解
public class Test {
public static void main(String[] args) {
ArrayList list = new ArrayList();
String regex = "hello";
list.add("hello");
list.add("java");
list.add("hello");
list.add("hello");
list.add("world");
System.out.println(list);
// 迭代器
ListIterator listit = list.listIterator();
/*
* 预期解决问题:删除重复的元素
* 解决问题中出现新问题:结果与预期的不同
* 思考后,又看了一下API,此代码说明的问题:remove()方法
* */
while (listit.hasNext()) {
int count = 0;
if (listit.next().equals(regex)) {
count++;
}
if (count == 1) {
continue;
}
listit.remove();//(1)
list.set("javaSE");//(2)
// 返回的最后一个元素(可选操作)。
}
//影响到list集合的元素---猜想迭代器对象和集合对象是不是指向同一个引用?
System.out.println(list);
}
}
编译结果(将2注释)
编译结果(将1注释)
换句话说,remove()删除并返回的是next()和previous()这个位置的的元素;set(E,e)是在next()和previous()这个位置处添加元素,其它元素顺延,理解这两点就理解上面代码产生的原因。
ArrayList类
特点:1底层数据结构是数组的形式,满足数组结构的特点→查询快、增删慢
2从线程安全问题来看:线程不安全的、不同步、执行效率高
3它元素可以重复,并且存储和取出一致(对象按照索引位置排序)
Vector类
特点:1底层数据结构是数组的形式, 查询慢、增删慢2从 线程角度看:线程安全的类、同步、执行效率低
二者联系:
Vector是在集合框架未出现之前的jdk1.0版本就已经有了,与ArrayList(jdk1.2出现)重复,被ArrayList替代;常用ArrayList,即使不安全可以通过加锁的方式实现安全
特有方法
public void addElement(E obj)------->相当于add(Object e)
public Enumeration<E> elements()----->相当于Iterator iterator() ;
枚举方法(遍历过程使用到)
Enumeration<E>接口---向量的组件枚举有两个方法
boolean hasMoreElements()------>相当于hasNext()
Object nextElement()----------->相当于next();
源码
关键字---synchronized------同步锁(多线程中讲)-----它就可以保证线程安全!
public synchronized void addElement(E obj) {//由同步代码块演变过来的同步方法
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
实例2 Vector方法的使用
package org.westos_02;
import java.util.Enumeration;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
//创建一个Vector集合对象
Vector v = new Vector() ;
//添加元素
//public void addElement(E obj)
v.addElement("hello");
v.addElement("hello");
v.addElement("world");
v.addElement("Java");
//public Enumeration<E> elements()----->相当于:Iterator iterator() ;
Enumeration en = v.elements() ;
//遍历元素
/**
* boolean hasMoreElements():------>相当于:hasNext()
Object nextElement():----------->相当于:next();
*/
while(en.hasMoreElements()){
//获取元素
String s = (String)en.nextElement() ;//向下转型
System.out.println(s);
}
}
}
问题1:为什么集合println的不是地址而是内容?
答:因为Collection接口的子实现类的重写了toString()方法
实例2.5 toString()源码及实例
package org.westos_07;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
问题:为什么集合println的不是地址而是内容?
因为Collection接口的子实现类的重写了toString()方法
下面看Collection集合中关于:toString()方法的源码
查找方法注意事项:
如果在一个类中没有找到该方法,继续往它的父类中找;
public String toString() {
Iterator<E> it = iterator();//等价this.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();//拼接右中括号,转换String类型输出
sb.append(',').append(' '); //中间每一个元素拼接逗号和空格
}
}
//结果:[hello, world, Java]
*/
public class CollectionDemo {
public static void main(String[] args) {
//创建Collection集合对象:
Collection<String> c = new ArrayList<String>() ;
//添加元素
c.add("hello") ;
c.add("world") ;
c.add("Java") ;
System.out.println(c);
//为什么输出的不是地址而是内容:看Collection接口的子实现类的toString()方法
}
}
LinkedList类
特点
底层数据结构是链接列表,特点--查询慢、增删快
从线程角度看:线程不安全的一个类,不同步、执行效率高
说明:链表结构(回头补充,以图的形式,单链表和双链表)
特有方法
1添加功能:
public void addFirst(E e)将指定元素插入此列表的开头。
public void addLast(E e)将指定元素添加到此列表的结尾。
2获取功能:
public Object getFirst()返回此列表的第一个元素
public Object getLast()返回此列表的最后一个元素。
3删除功能:
public Object removeFirst()移除并返回此列表的第一个元素。
public Object removeLast()移除并返回此列表的最后一个元素。
实例3
package org.westos_03;
import java.util.LinkedList;
/**
* LinkedList:
底层数据结构是链接列表,特点:查询慢,增删快
从线程角度看:线程不安全的一个类,不同步,执行效率高
特有功能:
添加功能:
public void addFirst(E e)将指定元素插入此列表的开头。
public void addLast(E e)将指定元素添加到此列表的结尾。
获取功能:
public Object getFirst()返回此列表的第一个元素
public Object getLast()返回此列表的最后一个元素。
删除功能:
public Object removeFirst()移除并返回此列表的第一个元素。
public Object removeLast()移除并返回此列表的最后一个元素。
* @author Apple
*/
public class LinkedListDemo {
public static void main(String[] args) {
//创建LinkedList集合
LinkedList link = new LinkedList() ;
/* 1
* public void addFirst(E,e)将指定元素插入此列表的开头
* 添加元素
* */
link.addFirst("hello") ;
link.addFirst("world") ;
link.addFirst("Java") ;
System.out.println(link);
/* 2---有疑问?
* public Object getFirst()返回此列表的第一个元素
* public Object getLast()返回此列表的最后一个元素
*/
Object obj = link.getFirst();
System.out.println(obj);//打印的为何不是地址?
Object obj2 = link.getLast();
System.out.println(obj2);
/* 3
* public Object removeFirst()移除并返回此列表的第一个元素。
* public Object removeLast()移除并返回此列表的最后一个元素。
*/
System.out.println("removeFirst:"+link.removeFirst());
System.out.println("removeLast:"+link.removeLast());
//输出集合
System.out.println("link:"+link);//只剩中间元素了
}
}
实例4 LinkedList遍历集合元素
package org.westos_05;
import java.util.Iterator;
import java.util.LinkedList;
//使用addFirst()方法
public class LinkedListDemo {
public static void main(String[] args) {
//1---首先创建LinkedList集合的对象
LinkedList link = new LinkedList() ;
//LinkedList集合的特有功能:addFirst(Object e)
//2---添加元素
//联想栈特点:先进后出
link.addFirst("hello") ;
link.addFirst("world") ;
link.addFirst("java") ;
System.out.println("回顾addFirst()方法的特点:"+link);
//创建迭代器对象
Iterator it = link.iterator() ;
while(it.hasNext()){
String s = (String)it.next() ;
System.out.println(s);
}
}
}
练习1 ArrayList去除集合中字符串的重复元素
方法1:创建新集合
package org.westos_04;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 需求:ArrayList去除集合中字符串的重复元素
* 1)首先创建一个集合
* 2)给集合中添加很多重复元素
* 3)再次创建一个新集合(重点:在思想上)
* 4)获取迭代器遍历
* 5)获取到该集合中的每一个元素
* 判断新集合中是否包含这些有素
* 有,不搭理它
* 没有.说明不重复,添加进来
* 6)遍历新集合
* @author Orange
*/
public class ArrayListTest {
public static void main(String[] args) {
//1)创建一个集合
ArrayList array = new ArrayList() ;
//2)给集合中添加多个重复元素
array.add("hello") ;
array.add("hello") ;
array.add("hello") ;
array.add("world") ;
array.add("world") ;
array.add("world") ;
array.add("Java") ;
array.add("Java") ;
array.add("hello") ;
array.add("Javaweb") ;
array.add("JavaEE") ;
array.add("JavaEE") ;
//3)创建一个新的集合
ArrayList newArray = new ArrayList() ;
//4)遍历旧集合,获取当前迭代器对象
Iterator it = array.iterator() ;
while(it.hasNext()){
String s = (String) it.next() ;
//拿到了每一个字符串元素
//判断新集合是否包含旧集合中的元素
if(!newArray.contains(s)){//重要的方法
//不包含,就将元素直接添加到新集合中
newArray.add(s) ;//为何没有并发修改异常?(在新的集合添加元素,不是原来的集合)
}
}
//遍历新集合
Iterator it2 = newArray.iterator() ;
while(it2.hasNext()){
String s = (String) it2.next() ;//向下转型
System.out.println(s);
}
}
}
方法2 快速排序思想
package org.westos_04;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 需求:ArrayList去除集合中字符串的重复元素,
* 附件条件:不能创建新集合!
* @author Apple
*/
public class ArrayListTest2 {
public static void main(String[] args) {
//创建一个集合,添加重复元素
ArrayList array = new ArrayList() ;
array.add("hello") ;
array.add("hello") ;
array.add("hello") ;
array.add("world") ;
array.add("world") ;
array.add("world") ;
array.add("Java") ;
array.add("Java") ;
array.add("hello") ;
array.add("Javaweb") ;
array.add("JavaEE") ;
array.add("JavaEE") ;
System.out.println(array);
/**
* 由选择排序的逻辑想到:
* 拿0索引对应的元素依次和后面索引对应的元素进行比较
* 同理,1索引对应的元素和后面.....
* 前面的索引对应的元素如果和后面索引对应的元素重复了,从集合移出后面索引的对应的元素
*/
for(int x = 0 ;x <array.size() -1 ; x ++){
for(int y= x +1 ; y <array.size() ;y++){
//判断
if(array.get(x).equals(array.get(y))){//equals()方法
array.remove(y) ;
y -- ;//很重要的一步----→要理解可变长数组
}
}
}
//遍历集合
Iterator it = array.iterator() ;
while(it.hasNext()){
String s = (String) it.next() ;
System.out.println(s);
}
}
}
现在需求变了:ArrayList
去除集合中自定义对象的重复值(对象的成员变量值都相同理解为重复)
练习2
自定义学生类
package org.westos_04;
public class Student {
private String name ;
private int age ;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = 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;
}
/*
//自动生成(1)
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
*/
}
测试类
package org.westos_04;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 需求:ArrayList去除集合中自定义对象的重复值(对象的成员变量值都相同)
*
* 发现问题:
* 使用刚才创建新集合的思想,逻辑步骤和去除集合中重复的字符串是一样,但是出现了并没有将自定义对象的重复值(成员变量值一样)并没有去除掉
* contains()底层依赖于一个equals()方法,equals()方法是Object类的中的方法,该法默认比较的是对象的地址值是否相同,必须要重写Object中的eqauls()
* 方法,才能比较内容是否相同;
* 在自定义对象的类中重写Object中的equasl()方法,才能比较成员变量的值是否相同
* 看源码:
*
* ArrayList集合的Contains()源码
* public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
*
* @author Apple
*/
public class ArrayListTest3 {
public static void main(String[] args) {
//创建一个ArrayList集合对象
ArrayList array = new ArrayList() ;
//2)创建学生对象
Student s1 = new Student("高圆圆", 27) ;
Student s2 = new Student("高圆圆", 20) ;
Student s3 = new Student("邓超老了", 29) ;
Student s4 = new Student("邓超", 29) ;
Student s5 = new Student("黄晓明", 30) ;
Student s6 = new Student("高圆圆", 27) ;
//将学生对象添加到array集合中
array.add(s1) ;
array.add(s2) ;
array.add(s3) ;
array.add(s4) ;
array.add(s5) ;
array.add(s6) ;
//3)创建一个新集合
ArrayList newArray = new ArrayList() ;
//遍历旧集合,获取迭代器对象
Iterator it = array.iterator() ;
while(it.hasNext()){
Student s = (Student) it.next() ;
//判断新集合中是否包含这些对象
if(!newArray.contains(s)){
//不包含的对象才能添加新集合
newArray.add(s) ;
}
}
//遍历新集合
Iterator it2 = newArray.iterator() ;
while(it2.hasNext()){
Student s = (Student) it2.next() ;
System.out.println(s.getName()+"---"+s.getAge());
}
}
}
思考:从结果上来看,并没有达到预期目标
分析:从contains()的源码入手
**************************************************************************************************
发现contains()调用了equals()方法,由于其本身没有重写equals()方法,调用了Object的equals()方法,导致比较的是地址(而不是对象),所以出现与预期不符的结果。
解决方法:重写equals()方法,即在Student类中重写,快捷键----shift+shift+s+h
此时编译结果
ok,问题完美解决
练习3 使用LinkedList模拟一个栈结构的特点(自定义栈集合类,然后使用LinkedList的一些特有功能模拟栈结构特点)
package org.westos_05;
import java.util.LinkedList;
/**
* 自定义的栈集合类
* @author Orange
*/
public class MyStack {
//成员变量
private LinkedList link ;
//无参构造
//通过无参构造方法对成员方法进行初始化(即:创建LinkedList集合对象)
public MyStack(){
link = new LinkedList() ;
}
//添加功能
public void add(Object obj){//涉及到向上转型(从add的参数类型可以看出)
//向集合中列表插入到第一个元素
link.addFirst(obj) ;
}
//获取功能
public Object get(){
return link.removeFirst() ;//删除集合列表中的第一个元素,返回值是被删除的元素
}
//定义判断集合是否为空
public boolean isEmpty(){
return link.isEmpty() ;
}
}
测试类
package org.westos_05;
/**
* 自定义栈集合的测试类
* @author Orange
*/
public class MyStackDemo {
public static void main(String[] args) {
//创建自定义栈集合类的对象
MyStack ms = new MyStack() ;
//调用添加功能
ms.add("hello") ;//等价于------link.addFier("hello"),---先进
ms.add("world") ;
ms.add("java") ;
/* 输出元素:
* 目的:想通过get()方法得到它的元素
* System.out.println(ms.get());
* System.out.println(ms.get());
* System.out.println(ms.get());
* System.out.println(ms.get());(3)也即此时ms.get()==null抛出异常
* 方法报错:java.util.NoSuchElementException-----没有元素
* 解决思路:判断当前集合对象是否为空(用循环判断,用if只能输出一次)
*/
while(!ms.isEmpty()){
System.out.println(ms.get());
}
}
}
异常:java.lang.ClassCastException---类转换异常(常发生在向下转型的过程中)
解决方法:后续会提到(泛型)
未完待续.....补充大牛的博客