集合概述
概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。
和数组的区别:
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。
Collection体系集合
Collection父接口
特点:代表一组任意类型的对象,无序、无下标、不能重复。
方法:
- boolean add(Object obj) //添加一个对象。
- boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
- void clear() //清空此集合中的所有对象。
- boolean contains(Object o) //检查此集合中是否包含o对象。
- boolean equals(Object o) //比较此集合是否与指定对象相等。
- boolean isEmpty() //判断此集合是否为空。
- boolean remove(Object o) //在此集合中移除o对象。
- int size() //返回此集合中的元素个数。
- Object[] toArray() //姜此集合转换成数组。
public class Demo1{
pubic static void main(String[] args){
//创建集合
Collection collection=new ArrayList();
// * 1.添加元素
Collection.add("苹果");
Collection.add("西瓜");
Collection.add("榴莲");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
// * 2.删除元素
collection.remove("榴莲");
System.out.println("删除之后:"+collection.size());
// * 3.遍历元素
//3.1 使用增强for
for(Object object : collection){
System.out.println(object);
}
//3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)
//hasnext();判断是否有下一个元素
//next();获取下一个元素
//remove();删除当前元素
Iterator iterator=collection.Itertor();
while(iterator.hasnext()){
String object=(String)iterator.next();
System.out.println(s);
//删除操作
//collection.remove(s);引发错误:并发修改异常
//iterator.remove();应使用迭代器的方法
// * 4.判断
System.out.println(collection.contains("西瓜"));//true
System.out.println(collection.isEmpty());//false
}
}
}
/**
* Collection接口的使用(二)
* 1.添加元素
* 2.删除元素
* 3.遍历元素
* 4.判断
*/
public class Demo2 {
public static void main(String[] args) {
Collection collection=new ArrayList();
Student s1=new Student("张三",18);
Student s2=new Student("李四", 20);
Student s3=new Student("王五", 19);
//1.添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
//collection.add(s3);可重复添加相同对象
System.out.println("元素个数:"+collection.size());
System.out.println(collection.toString());
//2.删除数据
collection.remove(s1);
System.out.println("删除之后:"+collection.size());
//3.遍历数据
//3.1 增强for
for(Object object:collection) {
Student student=(Student) object;
System.out.println(student.toString());
}
//3.2迭代器
//迭代过程中不能使用collection的删除方法
Iterator iterator=collection.iterator();
while (iterator.hasNext()) {
Student student=(Student) iterator.next();
System.out.println(student.toString());
}
//4.判断和上一块代码类似。
}
}
Collection子接口
- 特点:有序、有下标、元素可以重复。
- 方法:
- void add(int index,Object o) //在index位置插入对象o。
- boolean addAll(index,Collection c) //将一个集合中的元素添加到此集合中的index位置。
- Object get(int index) //返回集合中指定位置的元素。
- List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素。
/**
* List子接口的使用(一)
* 特点:1.有序有下标 2.可以重复
*
* 1.添加元素
* 2.删除元素
* 3.遍历元素
* 4.判断
* 5.获取位置
*/
public class Demo3 {
public static void main(String[] args) {
List list=new ArrayList<>();
//1.添加元素
list.add("tang");
list.add("he");
list.add(0,"yu");//插入操作
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//2.删除元素
list.remove(0);
//list.remove("yu");结果同上
System.out.println("删除之后:"+list.size());
System.out.println(list.toString());
//3.遍历元素
//3.1 使用for遍历
for(int i=0;i<list.size();++i) {
System.out.println(list.get(i));
}
//3.2 使用增强for
for(Object object:list) {
System.out.println(object);
}
//3.3 使用迭代器
Iterator iterator=list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//3.4使用列表迭代器,listIterator可以双向遍历,添加、删除及修改元素。
ListIterator listIterator=list.listIterator();
//从前往后
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
//从后往前(此时“遍历指针”已经指向末尾)
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
//4.判断
System.out.println(list.isEmpty());
System.out.println(list.contains("tang"));
//5.获取位置
System.out.println(list.indexOf("tang"));
}
}
/**
* List子接口的使用(二)
* 1.添加元素
* 2.删除元素
* 3.遍历元素
* 4.判断
* 5.获取位置
*/
public class Demo4 {
public static void main(String[] args) {
List list=new ArrayList();
//1.添加数字数据(自动装箱)
list.add(20);
list.add(30);
list.add(40);
list.add(50);
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//2.删除元素
list.remove(0);
//list.remove(20);很明显数组越界错误,改成如下
//list.remove(Object(20));
//list.remove(new Integer(20));
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//3-5不再演示,与之前类似
//6.补充方法subList,返回子集合,含头不含尾
List list2=list.subList(1, 3);
System.out.println(list2.toString());
}
}
List实现类
- ArrayList【重点】
- 数组结构实现,查询块、增删慢;
- JDK1.2版本,运行效率快、线程不安全。
/**
* ArrayList的使用
* 存储结构:数组;
* 特点:查找遍历速度快,增删慢。
* 1.添加元素
* 2.删除元素
* 3.遍历元素
* 4.判断
* 5.查找
*/
public class Demo5 {
public static void main(String[] args) {
ArrayList arrayList=new ArrayList<>();
//1.添加元素
Student s1=new Student("唐", 21);
Student s2=new Student("何", 22);
Student s3=new Student("余", 21);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList.toString());
//2.删除元素
arrayList.remove(s1);
//arrayList.remove(new Student("唐", 21));
//注:这样可以删除吗(不可以)?显然这是两个不同的对象。
//假如两个对象属性相同便认为其是同一对象,那么如何修改代码?
//3.遍历元素
//3.1使用迭代器
Iterator iterator=arrayList.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
//3.2使用列表迭代器
ListIterator listIterator=arrayList.listIterator();
//从前往后遍历
while(listIterator.hasNext()) {
System.out.println(listIterator.next());
}
//从后往前遍历
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
//4.判断
System.out.println(arrayList.isEmpty());
//System.out.println(arrayList.contains(new Student("何", 22)));
//注:与上文相同的问题。
//5.查找
System.out.println(arrayList.indexOf(s1));
}
}
注:Object里的equals(this==obj)用地址和当前对象比较,如果想实现代码中的问题,可以在学生类中重写equals方法:
@Override
public boolean equals(Object obj) {
//1.是否为同一对象
if (this==obj) {
return true;
}
//2.判断是否为空
if (obj==null) {
return false;
}
//3.判断是否是Student类型
if (obj instanceof Student) {
Student student=(Student) obj;
//4.比较属性
if(this.name.equals(student.getName())&&this.age==student.age) {
return true;
}
}
//不满足,返回false
return false;
}
ArrayList源码分析
- 默认容量大小:private static final int DEFAULT_CAPACITY = 10;
- 存放元素的数组:transient Object[] elementData;
- 实际元素个数:private int size;
- 创建对象时调用的无参构造函数:
//这是一个空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?
这就得看看add方法的源码了:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到ensureCapacityInternal(size + 1);该方法源码如下:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
该方法中的参数minCapacity传入的值为size+1也就是 1,接着我们再进入到calculateCapacity(elementData, minCapacity)里面:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
上文说过,elementData就是存放元素的数组,当前容量为0,if条件成立,返回默认容量DEFAULT_CAPACITY也就是10。这个值作为参数又传入ensureExplicitCapacity()方法中,进入该方法查看源码:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
因为elementData数组长度为0,所以if条件成立,调用grow方法,重要的部分来了,我们再次进入到grow方法的源码中:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
后面详情请看
https://blog.youkuaiyun.com/weixin_41121133/article/details/109409268