Java基础系列:了解ArrayList
2021-03-20 21:25
标签:final 自己 下标 lca flow 有一个 情况 turn inter 来,进来的小伙伴们,我们认识一下。 我是俗世游子,在外流浪多年的Java程序猿 在Java中,存在两种存储数据的容器: 我们首先来了解下数组 首先,我们要明白:数组是相同类型数据的有序集合。 我猜一定有人会说,Object的数组可以存字符串,数字等等,你说的不对 Object: 在我面前,你们都是弟弟 其中,我们将存储在数组中的数据称之为:元素, 元素在数组中存储的位置称之为下标。 我们可以通过下标来得到所对应的元素,反过来也一样 我们都知道,声明对象就是在内存中开辟一块空间,而声明一个数组就是在内存中开辟一串连续的空间: 在Java中,任何的数据类型都可以定义对象,比如: 内存结构如上图所示 简单一点说,使用数组可以分为3步: 我们来看下下面这段代码: 需要注意的一点是:在任何的编程语言中,如果需要通过下标来得到指定元素,那么这个下标的值一定是从0开始的,且可取值的最大范围为:指定长度 - 1。 上面代码中:我们最大可以操作的范围为 7 而且,数组在声明的时候有分配内存空间的操作,那么如果我们指定下标超过了数组指定的长度,那么我们的程序就会抛出异常: 上面介绍了数组的简单使用,下面我们再来重点看一个操作:数组拷贝。比如: arrs 是另一种定义方式: 数组拷贝操作: 在 首先来看如何使用: 从上面的方法和输出我们多少都能看出来这里的参数的意义,用一句话总结下来就是: 将源数组的第srcPos个位置到指定长度的元素copy到目标数组从第destPos个位置开始到指定长度位置 老外很有趣,以后再看到 而且一般参数的顺序都是:先源后目标 切记:在copy的时候,不能超过目标数组限定长度 而且:该方法执行效率略低,涉及到数组整体数据的copy 数组还有一个二维数组,这里就不介绍了。在实际工作中很少会用到。 关于数组就介绍到这里,我们还没有结束,下面我们重点要来聊一聊Java中的集合 可以说,集合在Java中也是属于一种容器,上面我们介绍的数组也是一种容器。上面我们也介绍过了数组,我们先考虑一个问题: 我们在这里来总结一下数组的特点,上面说到: 数组是一个相同类型数据的集合,在数组中只能存储一种类型的数据 可以说,这两个特点让我们在实际的开发中存在过多的限制。 所以出现了我们接下来要聊的集合 集合在Java中存在于 在集合框架中,我们可以感受到另外一种编程思想:面向接口编程 根据存储数据格式进行划分,可以分为两大类 两者都是接口,通过接口来规范操作方式 其中, 我们直接来聊聊ArrayList ArrayList属于List的子类,其特点: 很多时候不知道无从下手的时候,就先从该类的构造方法看起: 下面我们通过这三个构造方法来具体看下ArrayList是如何实现的: 通过查看构造方法,我们可以看出: 背景: 我们后续的方式都以无参构造方法创建的ArrayList对象进行说明 默认构造方法在初始化的时候,底层默认是空的Object数据,上面数组说到,我们在存储数据的时候数组必须要定义数组的长度,那么无参构造方法在添加元素的时候又是怎么做到添加成功而且不会出错呢? 下面我们来详细了解一下 两者都是添加元素的方法,唯一的区别在于: add(index, element)方法可以指定元素的添加位置 关于该方法的执行效率,是分情况的 而且添加方式可以分为两步: 下面我们来研究一下扩容的方法: 针对底层初始化的时候出现空Object数组的情况,这里对该情况进行了验证: 然后得到上面通过验证得到的长度进行扩容判断,如果容量不足,才会进行扩容的操作: 我们具体查看grow()方法,可以得到以下结果: 因为如果新扩容后的长度小于calculateCapacity()得到的值的话,calculateCapacity()得到的值就是最终要扩容的值 calculateCapacity()得到的值:使我们当前List的size() + 我们需要添加List中元素的数量 ArrayList底层是采用数据结构来实现的,所以我们随机访问数据的方式和直接通过数组来访问是一样的,不过在ArrayList中专门提供了一个方法: 下来可以自己看下实现源码,肯定是数组根据下标获取元素的方式 这块主要的内容是 Iterator,是Java对设计模式中迭代器模式的实现,下面我们来看操作代码 List提供了 看图更详细 准确来讲,ListIterator是Iterator的子类,拥有和Iterator同样的功能,但是又有不同: 其实,ArrayList如果只是局部变量的话,是不牵扯线程安全不安全的,只有作为共享资源存在的时候,才会出现线程不安全的问题: 这部分设计到多线程的知识,后面会对多线程的基础知识进行介绍 同时还会专门开一个专栏,深入了解多线程的内容。大家在这里记住就可以了 那么, 这种情况下,我们如何操作来保证线程安全呢? 自己查看源码,其实就是对方法进行加锁操作 更多关于ArrayList使用方法推荐查看其文档: ArrayList API文档 Java基础系列:了解ArrayList 标签:final 自己 下标 lca flow 有一个 情况 turn inter 原文地址:https://blog.51cto.com/14948012/2542376认识数组
数组
认识数组
内存空间
如何使用数组
声明数组
String[] arrs = new String[8];
arrs[0] = "元素1";
System.out.println(arrs[0]); // 元素1
int[] intArrs = {1,2,3,4,5,6,7};
System.out.println(intArrs[0]); // 元素1
String[] arrs = new String[8];
arrs[0] = "元素1";
arrs[8] = "元素8";
System.out.println(arrs[0]);
/**
* Java.lang.ArrayIndexOutOfBoundsException: 8
*/
数组拷贝
String[] arrs = {"元素1","元素2","元素3","元素4","元素5","元素6","元素7"};
String[] newArrs = new String[7];
// 如何把arrs数据赋值给newArrs
Java.lang.System
中为我们提供了一个静态方法,可以专门用来做数组拷贝:public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
String[] arrs = {"元素1","元素2","元素3","元素4","元素5","元素6","元素7"};
String[] newArrs = new String[7];
System.arraycopy(arrs, 0, newArrs, 0, 7);
Arrays.stream(newArrs).forEach(System.out::println);
/**
元素1
元素2
元素3
元素4
元素5
元素6
元素7
*/
newArrs = new String[3];
System.arraycopy(arrs, 2, newArrs, 0, 3);
Arrays.stream(newArrs).forEach(System.out::println);
/**
元素3
元素4
元素5
*/
Arrays.stream(newArrs).forEach(System.out::println);
这是jdk8之后推出的lambda的写法,看不懂的可以忽略,就当for循环输出就好
src
, source
这些都是代表的是源;dest
, target
都是代表目标
认识集合
集合框架
java.util
包下,为我们提供了一套性能优良,使用方便的接口和类。
Collection
存储的数据是单一元素,而Map
是已 ArrayList
这是我们在使用ArrayList的方式
// 无参
List
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
private static final int DEFAULT_CAPACITY = 10;
我们记住这个属性,很快我们就会说到具体操作方法
add()
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
elementData
是空数组的情况下,会扩容到10个长度。
迭代器:Iterator
List
Iterator
iterator()
,通过该方法我们就可以拿到Iterator进行迭代操作,我们先来看一看它的执行流程是什么样,其中最重要的两个属性:
流程
public boolean hasNext() {
return cursor != size;
}
next()
得到当前元素,同时改变cursor和lastRet的值,可以进行下一次的操作public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
hasNext()
为false
和ListIterator的对比
ListIterator
add()
和set()
,支持在迭代过程中向集合中添加和修改元素hasPrevious()
和previous()
,支持逆向迭代线程安全性
volidate
修饰
java.util.concurrent
下,也就是我们所说的JUC
文档
文章标题:Java基础系列:了解ArrayList
文章链接:http://soscw.com/index.php/essay/66869.html