集合
数组的缺点:
1.长度固定,无法自动扩容
2.不是一个类,没有对应方法,只能手动编写代码实现增删查改
集合与数组
存储一组元素,容器,集合是一个集合类
什么是集合
1:)集合只能存对象
2:)集合可以储存任意类类型(引用类型)的数据,长度可变,不限制元素的类型(集合中不能放基本数据类型,但可以放基本数据类型的包装类)
3:)集合可以自动扩容
4:)集合类全部支持**泛型,**是一种数据安全的用法
集合的类的结构图
集合分为两大体系
1.Collection接口,存储单一对象
常用的子接口
1:)List接口:存放的元素有序且允许有重复(有下标)
2:)Set接口:存放的元素无序不包含重复(无下标)
2.Map接口, 存储key / value 键值对
key任意数据类型,value任意数据类型
key唯一,value可重复
另外还有三个分支,均是为上述两大家族服务的。
1、 Iterator(迭代器)家族。主要用于遍历Colleciton接口的及其子类而设计。
2、 Comparetor(比较器), 在集合中存储对象时候,用于对象之间的比较
3、 Collecitons是工具类。注意该类名带个s,一般就表示工具类。里面提供了N多静态方法,来对Colleciton集合进行操作。
集合类位于java.util包
Collection的集合方法:
增删改查: add() addAll() remove() removeAll(集合)删除集合中包含的指定集合的所有元素 , clear() 从此集合中删除所有元素
辅助方法: size() isEmpty() contains() iterator() toArray()
List接口
List接口多了一组关于下标相关的方法:
add(int index , 元素) 在指定下标插入元素
remove(int index) 删除指定下标的元素
set(int index, 元素) 修改指定下标的元素
int indexOf(元素) 查找第一次出现该元素的下标
Object get(int 下标) 获取指定下标的元素
List常用的实现类
1:)ArrayList:底层以数组结构存放元素
2:)LinkList:底层以双向链表结构存放元素
对象比较
理论上,比较两个对象是否是同一对象 ==和equals()方法都是在比较地址码是否相等,
但是在实际开发中,比较两个对象是否是同一对象:1. 地址码是否一样, 2. 两个对象的属性值是否一样
对自定义的类类型, 重写Object的equlas()方法, 重写hashCode()
set集合判断两个对象是否相等:
1:)判断两个对象的hashCode是否一样,如果hashCode一样,进行equals()判断,如果为true,那么是相同的对象;
2:)如果hashCode不一样,那么不会继续判断equals(),不是同对象
3:)如果hashCode一样,equals()判断为false,不是同对象
List判断两个对象是否相等
只调用对象的equals()方法,equals()返回true,表示是同对象,与hashCode无关
对自定义的类类型对象比较, 重写Object的equlas()方法, 重写hashCode()
Student stu1 = new Student(1,"张三",21);
Student stu2 = new Student(1,"张三",21);
System.out.println("stu1的hashCode:"+stu1.hashCode());//stu1的hashCode:2129789493
System.out.println("stu2的hashCode:"+stu2.hashCode());//stu2的hashCode:1313922862
System.out.println(stu1 == stu2);//false == 比较的是地址码
System.out.println(stu1.equals(stu2));//true Student重写equals() 快捷方式Alt+insert
/*
从Object类继承:
public boolean equals(Object obj) {
return (this == obj);
}
*/
List list = new ArrayList();
list.add(stu1);
//contains() 判断集合是否包含某个元素
System.out.println(list.contains(stu2));//true
Student重写equals()
@Override
public boolean equals(Object o) {
if (this == o) return true;//地址码相同
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNo == student.stuNo &&
age == student.age &&
Objects.equals(name, student.name);
}
ArrayList
//创建ArrayList集合
List list = new ArrayList();
//List只能存对象
list.add(1); //1 int基本数据类型 自动装箱Integer 向上转型: Object
list.add("abc"); // 向上转型: Object
list.add(1,"word");//指定下标之前插入元素
list.remove(2);//删除指定下标的元素
Object ele = list.get(1);获取指定下标的元素,返回的是Object对象
//list == null 判断这个list是否创建对象, 防止空指针异常
//isEmpty() 判断集合是否是空集合, 没有添加元素
Object[] objects = list.toArray();//集合转数组
//遍历集合, 把集合的元素一个一个获取
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));//list里的数据都有对应的包装类,都重写了toString()方法,所以可以打印数据出来而不是地址码,如果里面存储的是Student对象,那么Sthdent类也要重写toString()方法
}
//如果get() 的下标大于等于 size() 抛IndexOutOfBoundsException 下标越界,注意,等于size()也不行,因为下标从0开始
1.打印List数据,如果存储的数据是自定义类的对象,那么要重写Object的toString()方法,否则打印出来的是地址码
从List中拿出存储的自定义类的对象,要向下转型为对应的类型,因为List中的数据是Object类型的对象 例如:Student stu = (Student) list.get(i); 假设list存的是Sthdent对象
ArrayList源码(8.4上午)
add() 添加元素的源码:
//Object[] elementData是ArrayList的属性
public ArrayList() {
//构造方法
//elementData初始是空数组, 长度为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //{}
}
public boolean add(E e) {//list.add("abc");
//确定所需容量: 1
ensureCapacityInternal(size + 1); // Increments modCount!!
//size=0 size=size+1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//elementData: {} minCapacity: 1
private static int calculateCapacity(Object[] elementData, int minCapacity)