一、集合简介
Java是面向对象的语言,对事物的描述都是以对象的形式。为了方便对多个对象的操作就需要对对象进行存储。但是使用数组存储对象与一些弊端,这时就出现了集合。
集合就像是一个对象的容器,可以动态地存储多个对象,还可以对多个对象进行操作。
Java的集合类可以存储数量不等的多个对象,还可以用于保存具有映射关系的关联数组。
数组在内存存储方面的缺点:
数组初始化后,长度确定。
数组声明的类型,就决定了进行元素初始化时的类型。
总结来说就是,长度固定,类型单一
数组在存储数据时的弊端:
数组初始化以后,长度就不可变了,不便于扩展
数组中提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高。同时无法直接获取存储元素的个数
数组存储的数据是有序的、可以重复的。对于无序的不可重复的需求不能满足。存储数据的特点单一。
总结来说:存储数据类型单一,操作性差、不利于扩展
二、集合框架简介
集合框架的设计成要满足以下几个目标。
该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
对一个集合的扩展和适应必须是简单的。
因此,整个集合框架就围绕一组标准接口而设计。你可以直接使用这些接口的标准实现,诸如: LinkedList, HashSet, 和 TreeSet 等,除此之外你也可以通过这些接口实现自己的集合。
- 集合框架体系
img
从上面的集合框架图可以看出,Java 集合可分为 Collection 和 Map 两种体系:
Collection接口:单列数据,定义了存取一组对象的方法的集合
List接口:
元素有序、可重复的集合。
List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>
Set接口:
元素无序、不可重复的集合。
Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
Map接口:双列数据,保存具有映射关系key-value对的集合
Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框架位于java.util包中, 所以当使用集合框架的时候需要进行导包。
- 集合框架的逻辑
所有的集合框架都包含如下内容:
接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
img
定义接口,具体类实现了接口,重写接口类中的抽象方法,使其具备对应的功能。而重写这些方法运用到了一些算法。
三、Collection接口
Collection接口是Java集合框架的一大分支体系。
Collection 接口是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)实现。
在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
- Collection接口中的方法
功能 方法 作用 - 添加 add(Object obj) 为集合中添加一个对象obj
addAll(Collection coll) 添加集合coll中的所有对象到现有集合 - 获取有效元素的个数 int size() 返回该集合内元素的个数
- 清空集合 void clear() 清空集合内所有元素
- 是否是空集合 boolean isEmpty() 判断该集合是否是空集合
- 是否包含某个元素 boolean contains(Object obj) 判断该集合中是否含有对象obj
boolean containsAll(Collection c) 判断该集合中是否含有集合c中的所有对象 - 删除 boolean remove(Object obj) 删除集合中的元素obj
boolean removeAll(Collection coll) 删除该集合中所有和集合coll中相同的元素 - 取两个集合的交集 boolean retainAll(Collection c) 取当前集合和集合c的交集,结果放在当前集合中,不影响集合c内的元素
- 集合是否相等 boolean equals(Object obj) 判断该集合和obj是否相等
- 转成对象数组 Object[] toArray() 将该集合转换为数组,数组内每个元素都是对象
- 获取集合对象的哈希值 hashCode() 返回集合对象的哈希值
- 遍历 iterator() 返回迭代器对象,用于集合遍历
import java.util.;
public class Demo01 {
public static void main(String[] args) {
//创建一个ArrayList类,ArrayList类实现了集合Collection接口及其子接口
Collection coll = new ArrayList();
//1. add(Object obj):将obj添加到当前集合中
coll.add(123); //这里相当于自动装箱,转为了包装类对象,因为集合里的元素都是对象而不是数值类型
coll.add(456);
coll.add(789);
coll.add(new String(“Tom”));
coll.add(false);
coll.add(new Person(“Jerry”,18));
System.out.println(coll);
//2.size():返回当前集合中元素的个数
System.out.println(“当前集合中元素的个数:” + coll.size());
//3. isEmpty(): 判断当前集合是否是空集合
System.out.println(“当前集合是否是空集合:” + coll.isEmpty());
System.out.println("“);
//4. contains(Object obj):判断当前集合中是否包含obj
boolean con = coll.contains(123);
System.out.println(con);
//contains方法判断集合内是否含有obj,会调用obj所在类的equals方法进行比较。String类重写了Object类中的equals方法,因此比较的是字面值(内容),这里的返回结果是true
System.out.println(coll.contains(new String(“Tom”)));
//Person类没有重写Object类中的equals方法,因此比较的是地址值,因此这里的返回结果是false
System.out.println(coll.contains(new Person(“Jerry”, 18)));
//总结:向Collection接口的实现类的对象中添加obj对象时,应该重写obj所在类的equals方法
//5. containsAll(collection coll):判断形参coll所有元素是否在当前集合中
Collection coll2 = Arrays.asList(123,456);
System.out.println(coll.containsAll(coll2));
Collection coll3 = Arrays.asList(123,4567);
System.out.println(coll.containsAll(coll3));
System.out.println(”“);
//6. remove(Object obj):移除集合中的obj对象
//既然要移除obj,肯定会先进行判断,判断集合中的哪个元素是obj,因此也会调用obj所在类的equals方法。因此也应进行重写
coll.remove(123);
System.out.println(coll);
//当没有重写Person类中的equals方法时,该语句不能将集合中的Person{name=‘Jerry’, age=18}删除,重写后则可以
coll.remove(new Person(“Jerry”, 18 ));
System.out.println(”“);
//7. removeAll(Collection c):移除集合中所有和集合c中相同的元素,c中可以含有和该集合不同的元素(相当于求差集操作)
//同样会用到集合中各对象的equals方法,需要重写
Collection coll4 = Arrays.asList(456,true);
coll.removeAll(coll4);
System.out.println(coll);
System.out.println(”");
//8. retainAll(Collection c):将该集合和集合c有的元素提取出来赋给当前集合(相当于求交集操作),不会影响集合c里的元素
//同样用到了equals方法,需要重写.这里没有进行重写,所以把原集合中的 Person{name=‘Jerry’, age=18}也去掉了
Collection coll5 = Arrays.asList(789,“Tom”,new Person(“Jerry”, 18));
coll.retainAll(coll5);
System.out.println(coll);
System.out.println("“);
//9. equals(Object obj):要想返回true,需要原集合和形参obj的所有元素都相同
//对于List接口的实现类的对象,还要求元素顺序都相同;
//对于Set接口的实现类的对象,则只用所有元素相同即可,顺序不做要求
//10. hashcode():返回当前对象的哈希值
System.out.println(coll.hashCode());
System.out.println(”“);
//11. toArray():将该集合转换为数组,数组内每个元素都是对象,数组类型根据元素类型确定
Object[] arr = coll.toArray();
for (int i = 0; i < arr.length;i++) {
System.out.println(arr[i]);
}
//扩展:数组转化为集合:调用Array类的静态方法asList()
//注意形参应该是包装类对象
List list = Arrays.asList(new String[]{“aa”, “bb”, “cc”});
System.out.println(list);
System.out.println(”********************");
//12. clear():清空数组
coll.clear();
System.out.println(coll);
//13.iterator():返回Iterator接口的实例,用于遍历集合元素
}
}
class Person {
//创建私有属性
private String name;
private int age;
//提供一个无参构造器
public Person() {
}
//提供一个有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写toString方法,使其返回属性值
@Override
public String toString() {
return “Person{” +
“name='” + name + ‘’’ +
“, age=” + age +
‘}’;
}
//提供访问和设定私有属性的public方法getter和setter
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;
}
}
运行结果:
[123, 456, 789, Tom, false, Person{name=‘Jerry’, age=18}]
当前集合中元素的个数:6
当前集合是否是空集合:false
*********************
true
true
false
true
false
*********************
[456, 789, Tom, false, Person{name=‘Jerry’, age=18}]
*********************
[789, Tom, false, Person{name=‘Jerry’, age=18}]
*********************
[789, Tom]
*********************
109694
*********************
789
Tom
[aa, bb, cc]
*********************
[]
注意点:
集合中删除、相等、取交集、取差集等操作会调用集合中对象所在类的equals方法,因此应该重写集合内元素所在类的equals方法,使其比较内容值,而不是地址。
- Interator接口(迭代器)
2.1 迭代器简介
Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。
GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
迭代器模式,就是为容器而生。
Iterable接口有一个iterator()方法,Collection接口继承了Iterable接口,因此,所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建Iterator 对象,则必须有一个被迭代的集合。
集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
2.2 迭代器的方法
hasNext()方法与next()方法:
import java.util.*;
public class Demo01 {
public static void main(String[] args) {
//创建一个ArrayList类,ArrayList类实现了集合Collection接口及其子接口
Collection coll = new ArrayList();
coll.add(123); //这里相当于自动装箱,转为了包装类对象,因为集合里的元素都是对象而不是数值类型
coll.add(456);
coll.add(789);
coll.add(new String(“Tom”));
coll.add(false);
coll.add(new Person(“Jerry”, 18));
//为该集合创建一个迭代器Iterator
//如果需要创建Iterator 对象,则必须有一个被迭代的集合。
Iterator iterator = coll.iterator();
//调用迭代器的hasNext()方法和next()方法;
//生成迭代器对象,相当于创建了一个指针,指针指向集合中第一个元素的前边
//hasNext()方法:判断是否还有下一个元素
while (iterator.hasNext()) {
//next()方法:指针下移,将下移义后的集合位置上的元素返回
System.out.println(iterator.next());
}
}
}
class Person {
//创建私有属性
private String name;
private int age;
//提供一个无参构造器
public Person() {
}
//提供一个有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写toString方法,使其返回属性值
@Override
public String toString() {
return “Person{” +
“name='” + name + ‘’’ +
“, age=” + age +
‘}’;
}
//提供访问和设定私有属性的public方法getter和setter
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;
}
}
运行结果:
123
456
789
Tom
false
Person{name=‘Jerry’, age=18}
迭代器的原理:
生成迭代器对象,相当于创建了一个指针,指针指向集合中第一个元素的前面
hasNext()方法:判断是否还有下一个元素
next()方法:指针下移,将下移义后的集合位置上的元素返回
迭代器的错误使用:
Iterator iterator = coll.iterator();
//这样相当于指针下移两次,将会跳着输出,还会报异常
while (iterator.Next() != null) {
System.out.println(iterator.next());
}
//集合每次调用iterator()方法,都会返回一个新的迭代器对象,这样每次都会出现一个新指针,指向集合第一个元素的前面,因此该语句块直回不停输出集合内的第一个元素。
while (coll.iterator().hasNext() != null) {
System.out.println(iterator.next());
}
remove()方法:
import java.util.*;
public class Demo01 {
public static void main(String[] args) {
//创建一个ArrayList类,ArrayList类实现了集合Collection接口及其子接口
Collection coll = new ArrayList();
coll.add(123); //这里相当于自动装箱,转为了包装类对象,因为集合里的元素都是对象而不是数值类型
coll.add(456);
coll.add(789);
coll.add(new String(“Tom”));
coll.add(false);
coll.add(new Person(“Jerry”, 18));
System.out.println(coll);
//生成一个迭代器,遍历集合,当发现集合中”Tom“对象时,利用iterator.remove()方法将其删除
Iterator iterator = coll.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (“Tom”.equals(obj)) {
//iterator内部定一个了一个remove()方法,可以在遍历集合的时候删除集合中的元素,该方法不同于集合直接调用remove方法
iterator.remove();
}
}
//当遍历结束,上述迭代器失效,若要在其遍历集合,需要重新调用集合的iterator()方法生成一个迭代器
//重新遍历输出集合中的元素
iterator = coll.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
class Person {
//创建私有属性
private String name;
private int age;
//提供一个无参构造器
public Person() {
}
//提供一个有参构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//重写toString方法,使其返回属性值
@Override
public String toString() {
return “Person{” +
“name='” + name + ‘’’ +
“, age=” + age +
‘}’;
}
//提供访问和设定私有属性的public方法getter和setter
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;
}
}
运行结果:
[123, 456, 789, Tom, false, Person{name=‘Jerry’, age=18}]
123
456
789
false
Person{name=‘Jerry’, age=18}
如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报illegalStateException异常
3. for-each循环遍历集合
Java 5.0 提供了 foreach 循环迭代访问 Collection和数组。
该遍历操作不需获取Collection或数组的长度,无需使用索引访问元素。
遍历集合的底层调用Iterator完成操作。
for-each还可以用来遍历数组。
语法:
for(集合元素的类型 局部变量名 : 集合名称)
for-each循环遍历集合:
for (Object j : coll) {
System.out.println(j);
}
for-each循环遍历数组:
int[] arr = new int[]{1,2,3,4}
for (int j : arr) {
System.out.println(j);
}
for-each循环遍历字符串:
String[] str = new String[]{1,2,3,4}
for (int j : str) {
System.out.println(j);
}
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明,KuangStudy,以学为伴,一生相伴!
本文链接:https://www.kuangstudy.com/bbs/1380775553455484930