Java中集合类 Collection
集合类 Collection是集合层次结构中的根接口。集合表示一组对象,称为其元素。有些集合允许重复元素,而有些则不允许。有些是有序的,有些是无序的。JDK不提供此接口的任何直接实现:它提供更具体的子接口(如Set和List)的实现。此接口通常用于传递集合,并在需要最大通用性的地方对其进行操作。
集合类 Collection
一、集合
/*
* Collection:使程序能够存储和操纵元素不固定的一组数据,集合类属于java.util包中
* 数组:长度固定,可以存放任意类型数据
* 集合:长度不固定,只能存放引用类型(使用自动装箱存放基本数据类型)
*
* 根据继承体系,集合中分为两大类,List和Set 且两个都继承了Collection
* Collection中有的方法List和Set都有
*
* Collection集合只能存储单个元素,且只能保存引用数据类型,不能保存基本数据类型
* 底层为Object[]数组,可以保存任何元素,Object是祖类,所有类型都会发生向上转型(多态)
* 基本类型和Object没有关系,可以把基本数据类型转换为对应的包装类类型保存在Collection
* 包装类类型是Object的子类
*
* 常用方法:
* Boolean add(): 添加
* void clear(): 清空集合
* boolean remove(): 删除
* boolean isEmpty(): 是否为空
* boolean contains(): 是否包含某个元素
* int size(): 返回集合中 元素个数
* */
public class _01_CollectionSummary {
public static void main(String[] args) {
// 接口不能创建对象,以ArrayList为例,发生多态,会丢失ArrayList的特有方法
// 现在调用方法都是Collection中的方法
Collection<Object> c1 = new ArrayList<>();
// 判断是否为空 true
System.out.println(c1.isEmpty());
// 添加
c1.add("abed");
c1.add(111); // 自动装箱为Integer在向上转型为Object
Object o1 = new Object();
_01_CollectionSummary o2 = new _01_CollectionSummary();
c1.add(o1);
c1.add(o2);
System.out.println(c1.isEmpty()); // false
// size不是数组长度,是数组中已经添加的元素个数
System.out.println(c1.size());
// 转数组
Object[] arr = c1.toArray();
for (Object o : arr) {
System.out.println(o);
}
System.out.println();
System.out.println("--------------");
// 删除
c1.remove(111);
// 从新获取数组
arr = c1.toArray();
for (Object o : arr) {
System.out.print(o);
}
System.out.println();
System.out.println("--------------");
c1.clear();
System.out.println(c1.size());
}
}
二、迭代器
/*
* 迭代器是一种从程序设计模式,可在迭代对象上遍历,而无需关心容器对象的内存分配细节
* Collection接口的iterator()和toArray()方法都用于获取集合中所有元素,前者返回迭代对象,后者返回数组
* Iterator接口隐藏集合底层数据结构,提供各种类型集合的统一接口
* 可以使序列类型的数据结构的遍历行为和被遍历的对象分离
*
* 创建迭代器对象
* Iterator it = 集合对象.iterator();
* 调用集合对象自身的iterator方法就可以创建数据当前对象的迭代器
*
* Iterator方法
* 1 boolean hasNext(); 判断光标下一位,是否还有元素,有返回true,否返回false
* 生成迭代器的时候,光标不是指向第一个元素,而是在最顶端,没有指向如何元素
* 光标会自动复位,使用完之后,必须从新生成
* 2 E next(); 光标向下移动一位,并返回该位置上的数据
* 3 删除当前光标指向的元素
* 三个方法使用顺序:1->2->3
*
* 迭代器创建后,如果集合在添加或删除元素,那迭代器必须从新生成,否则调用next方法报错
* 但更改数据不需从新创建
*
* 增强for循环 forEach 属于iterator的简单形式,功能不如iterator全,也是迭代器
* forEach和iterator基本一致,不能删除和添加集合数据,可以更改
* 普通 for while 循环,是和数据结构存储有关系的,如遍历数组时,需要使用arr[index]访问
* 且可以进行删除和添加操作
*
* 使用迭代器进行遍历操作时,如果需要删除元素,只能使用迭代器的remove方法,不能使用集合的remove方法
* */
public class _01_Collection_Iterator {
public static void main(String[] args) {
// 创建集合
Collection<Object> c = new ArrayList<>();
//添加元素
c.add(111);
c.add("abcd");
c.add(false);
c.add(null);
// 通过集合创建迭代器对象
Iterator<Object> it = c.iterator();
// 判断是否还有元素,否终止
while (it.hasNext()){
Object next = it.next();
System.out.println(next);
}
System.out.println("-------");
System.out.println(it.hasNext()); // false
// 不会执行,因为while循环中执行完后 光标就移动到最后
// 这时在判断hasNext(),则为false
if (it.hasNext()){
// 能进来说明集合还存在元素
Object next = it.next();
System.out.println(next);
}
// 迭代器使用后添加或删除操作
c.add(123);
// 只要迭代器生成,只要集合添加或删除操作后继续使用这个迭代器,就会报错
// java.util.ConcurrentModificationException
// 如果使用,需要重新生成
it = c.iterator();
if (it.hasNext()){
// 能进来说明集合还存在元素
Object next = it.next();
// 生成迭代器后后,不能使用集合的remove方法,除非使用后从新生成,否则报错
// c.remove(123);
// 可以使用迭代器的remove方法
it.remove();
System.out.println(next);
}
// if 循环中 it.remove(); 操作全部删除完了。输出0
System.out.println(c.size());
}
}
三、常用的两个方法
/*
* contains()与remove()
* boolean contains(); 判断集合中是否包含某个元素
* boolean remove(); 集合中删除指定元素
*
* 这两个方法底层都会调用equals方法进行比较
* c.contains("abc"), 会用 abc 调用String的equals方法 依次和集合中元素进行比较
* 判断或删除某个对象,就用某个对象调用equals方法,依次比较
* */
public class _01_Collection_Imp {
public static void main(String[] args) {
// 创建集合对象
Collection<Object> c = new ArrayList<>();
Integer i1 = 1; // 自动装箱
Integer i2 = 2;
Integer i3 = 3;
c.add(i1);
c.add(i2);
c.add(i3);
String s1 = "abc";
boolean b1 = false;
c.add(s1);
c.add(b1);
Integer i4 = new Integer(2);
String s2 = new String("abc");
boolean b2 = false;
System.out.println(i4==i2); // false,i4中new,在堆内存中
System.out.println(i4.equals(i2)); // true, Integer重写了equals方法,比较的是值
// contains(i4)方法会自动调用i4的equals方法和集合中元素进行比较
System.out.println(c.contains(i4)); // true
System.out.println(c.contains(s2)); // true
System.out.println(c.contains(b2)); // true
c.remove(b1);
System.out.println(c.contains(b2));
System.out.println("----------");
// 自定义类型
Manager m1 = new Manager(11, "张三");
Manager m2 = new Manager(11, "张三");
c.add(m1);
// 如果Manager类中没有覆写equals方法,在contains(m2)方法执行时自动调用的是Manager父类中的equals方法
// Manager默认继承Object类,则会调用Object类中的equals方法,Object类中的equals方法默认比较内存地址
// 所以尽管两个实例化对象数据相同,但使用contains()方法时依旧不存在
// 按指定需求覆写equals方法后在比较久为true
System.out.println(c.contains(m2));
System.out.println(c.contains(m1));
}
}
class Manager{
private int num;
private String name;
public Manager() {
}
public Manager(int num, String name) {
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Manager [num=" + num + ", name=" + name + "]";
}
@Override
// 自定义对象中通过覆写equals方法定制条件判断对象是否相等
// 需求:如果编号num与姓名name一样。认同为同一个对象
public boolean equals(Object obj) {
System.out.println("=====");
if (obj == null) return false;
if (obj == this){
return true;
}
if (obj instanceof Manager){
Manager m2 = (Manager) obj; // 强制类型转换,是的传入对象一致才有可比性
return m2.name.equals(this.name) && m2.num == this.num;
}
return false;
}
}
/*
ArrayList中contains源码
public boolean contains(Object o) {
return indexOf(o) >= 0;
// Returns: true if this list contains the specified element
}
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])) // 调用equals方法比较集合中元素
return i;
}
return -1;
}
ArrayList中remove源码
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) { // 调用equals方法比较集合中元素
fastRemove(index);
return true;
}
}
return false;
}
*/
总结
这里简单的介绍了Collection接口,在Java中,集合采用的是 接口与实现分离,在具体应用中,应根据自己的需求选择合适的接口并实现。