目录
- 什么是集合
- Collection
- Collection系列的3种集合遍历
集合框架图:
什么是集合
集合是一个可以封装并管理对象的容器(基本数据类型存入的是封装类),且容器都具有其自己的操作标准(对于对象的增删改查等等)。
MyArrayList我们自己设计的一种数据结构,一种逻辑结构,当别人用我这个MyArrayList的对象时,就是一个容器对象,
可以用来装对象。
public class MyArrayList {
//为什么使用Object,因为只是说这个容器是用来装对象的,但是不知道用来装什么对象。
private Object[] data;
private int total;
public MyArrayList(){
data = new Object[5];
}
//添加一个元素
public void add(Object obj){
//检查是否需要扩容
checkCapacity();
data[total++] = obj;
}
private void checkCapacity() {
//如果data满了,就扩容为原来的2倍
if(total >= data.length){
data = Arrays.copyOf(data, data.length*2);
}
}
//返回实际元素的个数
public int size(){
return total;
}
//返回数组的实际容量
public int capacity(){
return data.length;
}
//获取[index]位置的元素
public Object get(int index){
//校验index的合理性范围
checkIndex(index);
return data[index];
}
private void checkIndex(int index) {
if(index<0 || index>=total){
throw new RuntimeException(index+"对应位置的元素不存在");
// throw new IndexOutOfBoundsException(index+"越界");
}
}
//替换[index]位置的元素
public void set(int index, Object value){
//校验index的合理性范围
checkIndex(index);
data[index] = value;
}
//在[index]位置插入一个元素value
public void insert(int index, Object value){
//(1)考虑下标的合理性:校验index的合理性范围
checkIndex(index);
//(2)总长度是否够:检查是否需要扩容
checkCapacity();
//(3)[index]以及后面的元素往后移动,把[index]位置腾出来
System.arraycopy(data, index, data, index+1, total-index);
//(4)data[index]=value 放入新元素
data[index] = value;
//(5)total++ 有效元素的个数增加
total++;
}
//返回所有实际存储的元素
public Object[] getAll(){
//返回total个
return Arrays.copyOf(data, total);
}
//删除[index]位置的元素
public void remove(int index){
//(1)考虑下标的合理性:校验index的合理性范围
checkIndex(index);
//(2)移动元素,把[index+1]以及后面的元素往前移动
System.arraycopy(data, index+1, data, index, total-index-1);
//(3)把data[total-1]=null 让垃圾回收器尽快回收
data[total-1] = null;
// (4)总元素个数减少 total--
total--;
}
//查询某个元素的下标
/* public int indexOf(Object obj){
for (int i = 0; i < total; i++) {
//这两种写法都有风险
if(obj.equals(data[i])){
//if(data[i].equals(obj)){
return i;//找到,返回第一个找到的
}
}
return -1;//没找到返回-1
}*/
//查询某个元素的下标
public int indexOf(Object obj){
if(obj == null){
for (int i = 0; i < total; i++) {
if(data[i] == null){//等价于 if(data[i] == obj)
return i;
}
}
}else{
for (int i = 0; i < data.length; i++) {
if(obj.equals(data[i])){
return i;
}
}
}
return -1;
}
//删除数组中的某个元素
//如果有重复的,只删除第一个
public void remove(Object obj){
/*
* (1)先查询obj的[index]
* (2)如果存在,就调用remove(index)删除就可以
*/
//(1)先查询obj的[index]
int index = indexOf(obj);
if(index != -1){
remove(index);
}
//不存在,可以什么也不做
//不存在,也可以抛异常
//throw new RuntimeException(obj + "不存在");
}
public void set(Object old, Object value){
/*
* (1)查询old的[index]
* (2)如果存在,就调用set(index, value)
*/
// (1)查询old的[index]
int index = indexOf(old);
if(index!=-1){
set(index, value);
}
//不存在,可以什么也不做
//不存在,也可以抛异常
//throw new RuntimeException(old + "不存在");
}
}
然而不同集合由于其封装的对象的不同,底部的数据结构支持也就不同,所以就会出现很多种类的集合
比如 ArrayList、HashMap底层数据结构是数组,LinkedList底层数据结构是链表。
对于开发人员来说,这么多的集合无疑会造成很大的学习开销,因此java给这些集合抽取了两大接口:
1.Collection
规范单值集合的接口——>单身party
2.Map
规范对值集合的接口,(key,value)——>情侣party
Collection
(1)它是根接口
(2)它没有直接的实现类,有更具体的子接口:List和Set…
(3)有些集合的元素是可以重复的,有些集合的元素是不能重复,有些集合的元素是有序的,有些集合的元素是无序的。虽然有很多具体的子接口,但是他们具有统一的API:
(1)添加
add(Object obj):添加一个元素
addAll(Collection c):添加多个元素
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add(1);
c.add(2);
c.add(3);
Collection c2 = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c2.add("张三");
c2.add("李四");
c2.add("王五");
c.addAll(c2);//把c2中的所有元素都添加到c集合中
System.out.println(c);//[1,2,3,张三,李四,王五] 6个元素
System.out.println( c.size());//6
c.add(c2);
System.out.println(c);//[1,2,3,[张三,李四,王五]] 4个元素
(2)获取有效元素的个数
int size()
(3)是否包含
contains(Object o) :判断o是否在当前的集合中
containsAll(Collection c) :判断c是否是当前集合的子集
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
System.out.println(c.contains("张三"));//true
System.out.println(c.contains("杨洪强"));//false
Collection c2 = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c2.add("张三");
c2.add("李四");
Collection c3 = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c3.add("张三");
c3.add("杨洪强");
System.out.println(c.containsAll(c2));//c2是c的子集,true
System.out.println(c.containsAll(c3));//c3不是c的子集,false
(4)判断当前集合是否为空
boolean isEmpty() , 等价于 集合对象.size()==0
(5)remove(Object o):删除一个
removeAll(Collection c):删除多个 this = this - this ∩ c
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
//c.remove("张三");//删除一个
// System.out.println(c);//[李四,王五]
Collection c3 = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c3.add("张三");
c3.add("杨洪强");
c.removeAll(c3);
System.out.println(c);//[李四,王五]
(6)clear():清空所有
(7)retainAll(Collection<?> c) :保留交集 this = this ∩ c
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
Collection c2 = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c2.add("张三");
c2.add("杨洪强");
c.retainAll(c2);
System.out.println(c);//[张三]
(8)Object[] toArray() :把集合中的元素用一个数组返回
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
Object[] all = c.toArray();
System.out.println(Arrays.toString(all));//[张三,李四,王五]
Collection系列的3种集合遍历
(1)Object[] toArray():先返回数组,然后遍历数组
(2)迭代器设计模式, 每一个Collection系列的集合,内部都自带一个迭代器。
java.util.Iterator:它是所有迭代器的标准接口。这个接口的实现类在每一种集合类中,例如:ArrayList内部有一个内部类实现了Iterator接口。
这里声明为内部类有两个原因:
(1)每一种集合的内部实现(物理结构不同),意味着对迭代器(的实现是不同的,每一种集合都要单独定制迭代器
(2)内部类可以直接访问外部类的私有的属性,成员,迭代器就可以直接访问集合的私有的元素。
判断是否还有下一个元素:hasNext()
访问它的下一个元素:next()
删除某个元素:remove()
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
//返回这个集合自带的迭代器对象
//从头挨个访问
Iterator iterator = c.iterator();
while(iterator.hasNext()){
String obj = (String) iterator.next();
//移除姓“王”
if(obj.startsWith("王")){
iterator.remove();
}
}
System.out.println(c);//张三 李四
//直接remove得把内容写全,灵活性不高
(3)foreach:增强for循环
foreach循环可以用于遍历数组、Collection系列的集合等容器。
语法结构:
for(元素的类型 元素临时名称 : 数组和集合名) { }
Collection c = new ArrayList();//ArrayList是Collection下面的一个实现类而已
c.add("张三");
c.add("李四");
c.add("王五");
//Object:元素的数据类型
//obj:临时的元素名称
//c:要遍历的集合的名称
for (Object obj : c) {
System.out.println(obj);
}
ArrayList<String> stringArrayList=new ArrayList<>();
stringArrayList.add("你好");
stringArrayList.add("再见");
stringArrayList.add("吃了吗你");
for (Object obj :
stringArrayList) {
System.out.print(obj.toString()+" ");//你好 再见 吃了吗你
}
for (String str :
stringArrayList) {
System.out.print(str+" ");//你好 再见 吃了吗你
}
//遍历数组
String[] arr = {"hello","world","java"};
for (String string : arr) {
System.out.println(string);
}
什么样集合或容器类型可以使用foreach循环?
凡是实现了java.lang.Iterable接口(可迭代)的集合或容器都支持foreach循环 (implements Iterable)
如下:将上文自己定义的MyArrayList实现iterable接口:
public class MyArrayList implements Iterable{
private Object[] data;
private int total;
public MyArrayList(){
data = new Object[5];
}
... ... ... ...
@Override//Iterable里面的抽象方法
public Iterator iterator() {
//源码为return null;所以要重写才能使用
return new MyItr();
}
private class MyItr implements Iterator{
private int cursor;//游标
@Override
public boolean hasNext() {
System.out.println("还有下一个");
return cursor!=total;
}
@Override
public Object next() {
System.out.println("拿到下一个");
return data[cursor++];
}
}
}
可见 foreach底层还是调用Iterator迭代器来遍历集合。
补:定义泛型的时候必须要将泛型写在前面,后面可以不写:
否则只能用object当做元素使用