一 引入
对象数组不能适应变化的需求,因为数组的长度是固定的,这个时候,Java就提供了集合类供我们使用。
数组和集合的区别?
* A:长度区别
* 数组的长度固定
* 集合长度可变
* B:内容不同
* 数组存储的是同一种类型的元素
* 而集合可以存储不同类型的元素
* C:元素的数据类型问题
* 数组可以存储基本数据类型,也可以存储引用数据类型
* 集合只能存储引用类型
二 Collection类
1 Collection的功能概述:
* 1:添加功能
* boolean add(Object obj):添加一个元素
* boolean addAll(Collection c):添加一个集合的元素
* 2:删除功能
* void clear():移除所有元素
* boolean remove(Object o):移除一个元素
* boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)
* 3:判断功能
* boolean contains(Object o):判断集合中是否包含指定的元素
* boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
* boolean isEmpty():判断集合是否为空
* 4:获取功能
* Iterator<E> iterator()(重点)
* 5:长度功能
* int size():元素的个数
* 面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?
* 6:交集功能
* boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
* 7:把集合转换为数组
* Object[] toArray()
2集合的遍历
代码如下:
Iterator it = c.iterator();
while (it.hasNext()) {
// System.out.println(it.next());
String s = (String) it.next();
System.out.println(s);
}
注意:
1 for循环改写
for(Iterator it = c.iterator();it.hasNext(); ){
Student s = (Student) it.next();
System.out.println(s.getName() + "---" + s.getAge());
}
可以使it在for循环里,跳出循环体后,it便可以被垃圾回收了,更好
2 it.next() 慎用
如果上面的代码写成
for(Iterator it = c.iterator();it.hasNext(); ){
System.out.println(it.next().getName() + "---" + it.next().getAge());
}
看起来似乎没问题,但其实出错了。
因为it.next()会自动指向下一个,所以it.next().getName()与it.next().getAge()得到的不是同一个学生的姓名和年龄。
三List类
1 List集合的特有功能
因为List是有序的,所以可以指定位置
* A:添加功能
* void add(int index,Object element):在指定位置添加元素
* B:获取功能
* Object get(int index):获取指定位置的元素
* C:列表迭代器
* ListIterator listIterator():List集合特有的迭代器
* D:删除功能
* Object remove(int index):根据索引删除元素,返回被删除的元素
* E:修改功能
* Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
2 特有的遍历方式
for (int x = 0; x < list.size(); x++) {
Student s = (Student) list.get(x);
System.out.println(s.getName() + "---" + s.getAge());
}
因为List有get()方法,可以获取特定位置的元素,所以可以这样遍历
3 listIterator()方法介绍
特有功能:
* Object previous():获取上一个元素
* boolean hasPrevious():判断是否有元素
逆向遍历代码:
ListIterator lit = list.listIterator();
while (lit.hasPrevious()) {
String s = (String) lit.previous();
System.out.println(s);
}
System.out.println("-----------------");
而这样子是不会输出任何结果的。因为一开始的时候,lit是指向该对象的第一个的,所以lit.hasPrevious()是false。
即ListIterator可以实现逆向遍历,但是必须先正向遍历,到达末尾,才能逆向遍历。所以一般无意义,不使用。
listIterator()的其他使用
问题描述:判断一个集合里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素代码实现:
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// if ("world".equals(s)) {
// list.add("javaee");
// }
// }
这段代码看似没问题,却会报错如下:
ConcurrentModificationException 当方法检测到对象的并发修改,不允许这种修改
解决办法如下:
方式1:迭代器
// Iterator迭代器没有添加功能,但其子接口ListIterator有
ListIterator lit = list.listIterator();
while(lit.hasNext()){
String s = (String)lit.next();
if("world".equals(s)){
lit.add("javaee");
}
}
直接在lit(迭代器)上增加(或进行其他修改)
方式2:get()
for (int x = 0; x < list.size(); x++) {
String s = (String) list.get(x);
if ("world".equals(s)) {
list.add("javaee");
}
}
因为遍历方式有两种,而get()方法不涉及并发修改,所以可以直接在集合上增加(或进行其他修改)
4 list的子类特点(重点)
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
List有三个儿子,我们到底使用谁呢?
要安全吗?
要:Vector(即使要安全,也不用这个了,后面有替代的)
不要:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
如果你什么都不懂,就用ArrayList。
四 List子类
1 Vector类
特有功能:
* 1:添加功能
* public void addElement(Object obj) -- add()
* 2:获取功能
* public Object elementAt(int index) -- get()
* public Enumeration elements() -- Iterator iterator()
* boolean hasMoreElements() hasNext()
* Object nextElement() next()
因为它出现的早,所以有其特有的函数。但是功能是类似的,右边的是对应的在Collection中的函数名称(实现功能相同)
2 LinkedList类
特有功能:
* 1: 添加功能
* public void addFirst(Object e)
* public void addLast(Object e)
* 2: 获取功能
* public Object getFirst()
* public Obejct getLast()
* 3: 删除功能
* public Object removeFirst()
* public Object removeLast()
因为LinkedList类是基于链表的存储结构,所以可以比较容易的对首尾进行修改,所以如上所示
3易混点:
array.add(10);
这句话没有错。集合只能作用于对象,但是jdk5会把这句话转成:
array.add(new Integer(100));
五 案例
1 ArrayList去除集合中字符串的重复值(字符串的内容相同)
for(int i = 0; i < array.size(); i++){
String s = array.get(i);
array.remove(i);
if(!array.contains(s)){
array.add(i, s);
i++;
}
i--;
}
2 去除集合中自定义对象的重复值(对象的成员变量值都相同)
直接用上面的代码会出错。因为contains()方法的底层依赖的是equals()方法。
所以要按照我们自己的需求,重写equals()。
3 集合的嵌套遍历
比如ArrayList<ArrayList<Student>>,可以代表一个班里有很多学生(ArrayList<Student>),有很多班(ArrayList<ArrayList<Student>>)。像数组中的二维数组。
如果多层嵌套,就像是多维数组。
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();
ArrayList<Student> firstArrayList = new ArrayList<Student>();
firstArrayList.add(new Student("唐僧", 30));
firstArrayList.add(new Student("孙悟空", 29));
firstArrayList.add(new Student("猪八戒", 28));
firstArrayList.add(new Student("沙僧", 27));
firstArrayList.add(new Student("白龙马", 26));
bigArrayList.add(firstArrayList);
ArrayList<Student> secondArrayList = new ArrayList<Student>();
secondArrayList.add(new Student("诸葛亮", 30));
secondArrayList.add(new Student("司马懿", 28));
secondArrayList.add(new Student("周瑜", 26));
bigArrayList.add(secondArrayList);
for(ArrayList<String> big: bigArrayList){
for(Student s: big){
System.out.println(s.getName() + "---" + s.getAge());
}
}
增强for循环
4 键盘录入多个数据,以0结束,并在控制台输出最大值
/*
* 键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
*
* 分析:
* D:把集合转成数组
* E:对数组排序
* F:获取该数组中的最大索引的值
*/
public class ArrayListDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ArrayList<Integer> array = new ArrayList<Integer>();
while (true) {
System.out.println("请输入数据:");
int number = sc.nextInt();
if (number != 0) {
array.add(number);
} else {
break;
}
}
Integer[] i = new Integer[array.size()];
array.toArray(i);
Arrays.sort(i);
System.out.println("数组是:" + arrayToString(i) + "最大值是:"
+ i[i.length - 1]);
}
public static String arrayToString(Integer[] i) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int x = 0; x < i.length; x++) {
if (x == i.length - 1) {
sb.append(i[x]);
} else {
sb.append(i[x]).append(", ");
}
}
sb.append("]");
return sb.toString();
}
}