对象数组的概述和使用
先来看一个案例,这个案例用来演示利用数组存储学生信息并遍历输出。
eg: 我有3个学生,请把这个3个学生的信息存储到数组中,并遍历数组,获取得到每一个学生信息。
学生:Student
成员变量:name,age
构造方法:无参,带参
成员方法:getXxx()/setXxx()
public class Demo1 {
public static void main(String[] args) {
// 创建三个学生
Student s1 = new Student("张三", 19);
Student s2 = new Student("李四", 29);
Student s3 = new Student("王五", 39);
// 创建一个用来存储学生的数组
Student[] students = new Student[3];
students[0] = s1;
students[1] = s2;
students[2] = s3;
// 遍历数组
for (Student s : students) {
System.out.println("姓名是:" + s.getName() + " 年龄是:" + s.getAge());
}
}
}
//首先来创建学生类
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.age = age;
this.name = name;
}
}
思考: 数组作为容器,可以存储基本数据类型元素,也可以存储引用类型元素。可是我们都知道,引用类型存储的只能是对象,我们明显感觉到利用数组来操作对象不是很方便。为了方便对多个对象的操作,java给我们提供了集合类。
集合的由来及集合继承体系图
上述已经提到,面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,Java给我们提供了集合类。那么数组和集合有什么区别呢?
数组和集合的区别
长度区别:数组的长度是固定的,而集合的长度是可变的
存储数据类型的区别:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能村存储引用数据类型
内容区别:数组只能存储同种数据类型的元素,而集合可以存储不同类型的元素。
集合继承体系图
Collection集合的功能概述
添加功能
- boolean add(Object obj):
添加一个元素 - boolean addAll(Collection c):
添加一个集合的元素 (给一个集合添加进另一个集合中的所有元素)
删除功能
- void clear():
移除所有元素 - boolean remove(Object o):
移除一个元素 - boolean removeAll(Collection c):
移除一个集合的元素(移除一个以上返回的就是true)移除的元素是两个集合的交集元素
如果没有交集元素 则删除失败 返回false
判断功能
- boolean contains(Object o):
判断集合中是否包含指定的元素 - boolean containsAll(Collection c):
判断集合中是否包含指定的集合元素(这个集合 包含 另一个集合中所有的元素才算包含 才返回true)
比如:1,2,3 containsAll 12=true 1,2,3 containsAll 2,3,4=false - boolean isEmpty():
判断集合是否为空
获取功能
- Iterator iterator()
迭代器
长度功能
- int size():
元素的个数
交集功能
- boolean retainAll(Collection c):
获取两个集合的交集元素(交集:两个集合都有的元素)
例如:A集合对B集合取交集,获取到的交集元素在A集合中。返回的布尔值表示的是A集合是否发生变化
把集合转换为数组
- Object[] toArray()
Collection集合的基本功能测试
import java.util.ArrayList;
import java.util.Collection;
/*
* 集合类的基本功能测试
* boolean add(E e)
* boolean remove(Object o)
* void clear()
* boolean contains(Object o)
* boolean isEmpty()
* int size()
*/
public class Demo2 {
public static void main(String[] args) {
//首先来创建一个集合
Collection collection = new ArrayList();//多态
//添加元素的方法:add() 返回值可以用来判断是否添加成功
collection.add("张三");
collection.add("李四");
collection.add("王五");
collection.add("赵六");
System.out.println(collection);
//[张三, 李四, 王五, 赵六]
boolean b = collection.add("鬼脚七");
System.out.println(b);//true
System.out.println(collection);
//[张三, 李四, 王五, 赵六, 鬼脚七]
System.out.println("----------------------------");
/*boolean addAll(Collection c):
添加一个集合的元素 (给一个集合添加进另一个集合中的所有元素)*/
Collection collection2 = new ArrayList();
boolean b1 = collection2.addAll(collection);
System.out.println(b1);//true
System.out.println(collection2);
System.out.println("----------------------------");
/*删除:boolean remove(Object o) 返回值可以用来判断是否删除成功*/
boolean b2 = collection.remove("鬼脚七");
//collection.remove(4); 也可以通过索引来删除
/*void clear():移除所有元素*/
collection.clear();
System.out.println("----------------------------");
/* boolean removeAll(Collection c):
* 移除一个集合的元素(移除一个以上返回的就是true)
* 删除的元素是两个集合的交集元素
* 如果没有交集元素 则删除失败 返回false*/
Collection collection3 = new ArrayList();
Collection collection4 = new ArrayList();
collection3.add("1");
collection3.add("2");
collection3.add("3");
collection4.add("2");
collection4.add("3");
System.out.println(collection3);//[1, 2, 3]
System.out.println(collection4);//[2, 3]
boolean b3 = collection3.removeAll(collection4);
System.out.println(b3);//true
System.out.println(collection3);//[1]
System.out.println(collection4);//[2, 3]
System.out.println("----------------------------");
// 集合可以存储多种数据类型
Collection collection5 = new ArrayList();
collection5.add(10);
collection5.add(100);
collection5.add("abc");
// size()可以获取集合的大小
int size = collection5.size();
System.out.println(size); //3
// isEmpty()方法可以判断这个集合是否是空集合
collection5.clear();
System.out.println(collection5.isEmpty());//true
// boolean contains(Object o):判断集合中是否包含指定的元素
collection5.add(1);
collection5.add(2);
collection5.add(3);
boolean contains = collection5.contains(3);
System.out.println(contains);
// boolean containsAll(Collection c):判断集合中是否包含指定的集合元素
Collection collection6 = new ArrayList();
collection6.add(1);
collection6.add(2);
collection5.containsAll(collection6);//true
}
}
Collection集合的高级功能测试
import java.util.ArrayList;
import java.util.Collection;
/*A集合retainAll(B集合); 取交集,A集合最后只保留交集元素*/
public class Demo3 {
public static void main(String[] args) {
Collection collection = new ArrayList();
Collection collection1 = new ArrayList();
collection.add(1);
collection.add(2);
collection.add(3);
collection.add(4);
collection1.add(1);
collection1.add(5);
collection1.add(6);
boolean b = collection.retainAll(collection1);
System.out.println(b);
System.out.println(collection);
System.out.println(collection1);
//true
//[1]
//[1, 5, 6]
}
}
集合的遍历之转化成数组遍历
import java.util.ArrayList;
import java.util.Collection;
public class Demo3_1 {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(1);
collection.add(2);
collection.add(3);
collection.add(4);
//把集合转换成数组
Object[] objects = collection.toArray();
for (int i = 0; i < objects.length; i++) {
//System.out.println(objects[i]);
Integer integer = (Integer) objects[i];
int i1 = integer.intValue();
System.out.println(i1);
}
}
}
集合的遍历之迭代器遍历
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 案例演示:迭代器的使用
* boolean hasNext ()
* 如果仍有元素可以迭代,则返回 true。
* E next ()
* 返回迭代的下一个元素。
*/
public class Demo4 {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(1);
collection.add(2);
collection.add(3);
collection.add(4);
collection.add(5);
// 获取迭代器
Iterator iterator = collection.iterator();
//人为移动指针
//System.out.println(iterator.next());//1
//System.out.println(iterator.next());//2
// 使用迭代器遍历集合
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
Collection存储自定义对象并遍历
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection存储自定义对象并用迭代器遍历
*/
public class Demo5 {
public static void main(String[] args) {
Collection collection = new ArrayList();
collection.add(new Teacher("钢铁侠",20));
collection.add(new Teacher("绿巨人", 20));
collection.add(new Teacher("美国队长", 20));
Iterator iterator = collection.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj.toString());
}
/*Teacher{name='钢铁侠', age=20}
Teacher{name='绿巨人', age=20}
Teacher{name='美国队长', age=20}*/
}
}
class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
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;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
迭代器的原理及源码解析
Iterator(迭代器)是集合输出操作中最为常用的接口,而在Collection接口中也提供了直接为Iterator接口实例化的方法(iterator(),所以在任何集合类型都可以转换为Iterator接口输出。
所谓迭代器就好比排队点名一样,从前往后开始,一边判断是否有人,一边进行操作。
Iterator接口中定义了两个方法,hasNext()和next()方法,前者用来判断是否还有内容,后者用来取出当前内容。
实际上Scanner类也是Iterator接口的子类(想想Scanner类中的hasNextXxx()和nextXxx())。
- 迭代器原理: 为什么迭代器不定义成一个类 , 而是定义成一个接口?
我们试想一下,如果Iterator迭代器是一个类。那么我们就可以直接创建一个迭代器,并且使用它的遍历方法了,这样是不是很方便? 但是呢,Java给我们提供了很多不同的集合类,然而这些不同的集合都有不同的数据结构。所以,它们的存储方式和遍历的方式也应该是不同的。
无论是哪种集合,我们都应该具备相应的获取元素的功能(Iterator.next()),并且,最好配合一个辅助判断的功能方法(Iterator.hasNext()),这样在获取集合元素前进行判断是否有元素在集合中,更利于操作。于是java定义一个接口去定义这两个方法,这样,所有实现了这个接口的集合类都可以使用迭代器。
那么,真正的具体的实现类在哪里呢?
当然是在具体的子类中实现了,具体看源码:
- 迭代器源码解析
迭代器接口
public interface Iterator {
boolean hasNext();
Object next();
}
获取迭代器的接口
public interface Iterable {
Iterator iterator();
}
Collection继承了获取迭代器接口的接口
public interface Collection extends Iterable {
Iterator iterator();
}
List接口,继承了Collection接口,并继承了获取迭代器的抽象方法
public interface List extends Collection {
Iterator iterator();
}
ArrayList具体的实现接口类,实现了获取Iterator的功能方法
public class ArrayList implements List {
public Iterator iterator() {
return new Itr();
}
Itr是Iterator的具体实现类,在ArrayList以内部类的形式
并且实现了Iterator的功能方法:hasNext(),next(),remove()
private class Itr implements Iterator {
public boolean hasNext() {}
public Object next(){}
}
}
List概述及特点
元素有序,并且每一个元素都存在一个索引.元素可以重复.
- void add(int index,E element):
在指定索引处添加元素 - E remove(int index):
移除指定索引处的元素 返回的是移除的元素 - E get(int index):
获取指定索引处的元素 - E set(int index,E element):
更改指定索引处的元素 返回的而是被替换的元素
import java.util.ArrayList;
import java.util.List;
/**
* A:List集合的特有功能概述
* void add(int index,E element): 在指定索引处添加元素
* E remove(int index):移除指定索引处的元素 返回的是移除的元素
* E get(int index):获取指定索引处的元素
* E set(int index,E element):更改指定索引处的元素 返回的而是被替换的元素
* B:案例演示: 特有功能测试
*/
public class Demo6 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(100);
list.add(200);
list.add(300);
list.add(0, 500);
// 在指定的索引出添加元素,原索引处的元素不会被覆盖,而是朝后位移
System.out.println(list);
//[500, 100, 200, 300]
//通过索引来删除元素
//E remove(int index):移除指定索引处的元素 返回的是移除的元素
list.remove(0);
System.out.println(list);
//[100, 200, 300]
//可是如果我想要直接删除100这个元素,传参的时候就要把100包装成Integer的实例,否则就会默认为删除索引为100的元素
list.remove(Integer.valueOf(100));
System.out.println(list);
//[200, 300]
//获取指定索引处的元素: E get ( int index)
Object o = list.get(0);
Object o1 = list.get(1);
System.out.println(o);//200
System.out.println(o1);//300
//更改指定索引处的元素 返回的而是被替换的元素:E set(int index,E element)
Object set = list.set(0, 100);
System.out.println(set); //200
System.out.println(list);
//[100, 300]
}
}
List集合的特有遍历功能(双向迭代)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
* A:案例演示: 使用for循环 通过size()和get()方法结合使用遍历。
*/
public class Demo6_1 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
list.add("abc5");
//现在我们来尝试遍历这个list集合
//方法1——使用父接口中的迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//方法2——List 集合中的迭代器
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//方法3——采用for循环
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
System.out.println(o);
}
//还有一个很有意思的功能:反向遍历,这是ListIterator(双向迭代)的特有功能
//需要注意指针的位置,前面我们已经进行了正向遍历,指针的位置就在最后
//注意使用同一迭代器,如果不是同一迭代器,反向遍历没有效果
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
}
List集合存储学生对象并遍历
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Dmeo6_2 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Student("张三",19));
list.add(new Student("李四", 20));
list.add(new Student("王五", 21));
list.add(new Student("赵六", 22));
list.add(new Student("鬼脚七", 23));
//遍历1 采用父接口中的迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().toString());
}
System.out.println("----------------------------");
//遍历2 采用list中的迭代器
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next().toString());
}
System.out.println("----------------------------");
//遍历3 for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).toString());
}
}
}
并发修改异常产生的原因及解决方案
A:案例演示
需求:我有一个集合,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javase"元素,请写代码实现。
B:ConcurrentModificationException出现
我们用Iterator这个迭代器遍历采用hasNext方法和next方法,集合修改集合 会出现并发修改异常
C:解决方案 我们用ListIterator迭代器遍历 用迭代器自带的add方法添加元素 那就不会报错了
a:迭代器迭代元素,迭代器修改元素(ListIterator的特有功能add)
b:集合遍历元素,集合修改元素
解决方案2 使用for循环遍历集合 添加元素 不会报错
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class Demo7 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("PHP");
list.add("Linux");
list.add("Hello");
list.add("world");
//思路是遍历集合,只要发现world,就往里面加javaee
/*
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
if (listIterator.next()=="world"){
list.add("javase");
}
}
*/
//我们的思路并没有错,但是这里一旦运行就会报错
//ConcurrentModificationException 并发修改异常
//产生这个异常的原因是当我们创建好一个集合后,然后去使用迭代器
// 这个时候集合中的元素对于迭代器来说是相对固定的
// 迭代器中所有的操作都是针对这些元素
// 冒然的往集合里面添加元素就会使迭代器产生异常
// 但是如果不能往里面添加元素又显然不太人性化
// 如果要添加元素就必须使用迭代器自带的方法listIterator.add()
// 把上述代码稍稍修改就不会报错了
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()) {
if (listIterator.next() == "world") {
listIterator.add("javase");
}
}
System.out.println(list);
//[PHP, Linux, Hello, world, javaee]
//当然我们也可以使用for循环来完成这个功能
for (int i = 0; i < list.size(); i++) {
if (list.get(i)=="world"){
list.add("javaee");
}
}
}
List的三个子类的特点
- ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。 - Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。 - LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
数据结构
数据结构其实就是存储数据的格式
分类: 栈 , 队列 , 数组 , 链表 , 树 , 哈希表
-
栈特点: 先进后出 (弹夹)
-
队列: 先进先出
-
数组特点: 查询快 , 增删慢
-
链表特点: 查询慢 , 增删快