当前位置:首页 » 操作系统 » javaArraylist源码

javaArraylist源码

发布时间: 2022-11-29 07:32:58

‘壹’ java ArrayList add() 方法报错

直接看API就好,注意最后一句:IndexOutOfBoundsException - 如果索引超出范围 (index < 0 || index > size())
add
public void add(int index,
E element)将指定的元素插入此列表中的指定位置。向右移动当前位于该位置的元素(如果有)以及所有后续元素(将其索引加 1)。

指定者:
接口 List<E> 中的 add
覆盖:
类 AbstractList<E> 中的 add
参数:
index - 指定元素所插入位置的索引
element - 要插入的元素
抛出:
IndexOutOfBoundsException - 如果索引超出范围 (index < 0 || index > size())

补充------------------------
在指定位置上插入并不是顺序插入的意思呀
比如 1 2 3 4 5 6
现在有6个数,我可以在第三个位置插入一个数7,这样就变成:1 2 7 3 4 5 6
但是我不能在第100个上位置插入,因为目前没有那个位置,你不可能在那插入。
假设可以这样插入的话,在100这个位置插入后,就要将容量扩充至至少100,虽然中间都是null,但是内存也要分配。同样的你还得提防着是不是有人要在10万、100万这个位置插入数字呢?这样说的话,内存迟早要爆掉了……
所以只能在已经被分配了的位置上插入数据,而不能人工的去先插入再要求分配内存空间。

‘贰’ 在java源码中ArrayList数据增长是50%+1,为什么其他人都说是50%

int newCapacity = (oldCapacity * 3)/2 + 1;

list初始化默认为10
当第第10个被赋值时list是不会增长长度的,因为此时不需要开辟新的内存
当第11个时将执行会新开辟内存 (if (minCapacity > oldCapacity) 为真 )
因为包含第11个,所以新增后数组长度则为 10 + 10/2 + 1
但是实际上未赋值的为5
也就是说每次开辟新内存时 都需要多开辟1为当前赋值用
所以出现了楼主所说的 //这里明显是50%+1啊!

‘叁’ 如何自己实现一个简单的ArrayList

ArrayList是Java集合框架中一个经典的实现类。他比起常用的数组而言,明显的优点在于,可以随意的添加和删除元素而不需考虑数组的大小。

实现一个简单的ArrayList,实现的过程:
实现的ArrayList主要的功能如下:

  • 默认构造器和一个参数的有参构造器

  • add方法

  • get方法

  • indexOf方法

  • contains方法

  • size方法

  • isEmpty方法

  • remove方法

  • 这个简单的ArrayList类 取名为SimpleArrayList,全部的代码查看SimpleArrayList代码

    构造器

    源码ArrayList一共有三个构造器,一个无参构造器,一个参数为int型有参构造器,一个参数为Collection型的有参构造器。参数为Collection型的构造器用来实现将其他继承Collection类的容器类转换成ArrayList。SimpleArrayList类因为还没有手动实现其他的容器类,所以实现的构造方法只有2个。代码如下:

  • public SimpleArrayList(){ this(DEFAULT_CAPACITY);

  • } public SimpleArrayList(int size){ if (size < 0){ throw new IllegalArgumentException("默认的大小" + size);

  • }else{

  • elementData = new Object[size];

  • }

  • }

  • 无参构造器中的DEFAULT_CAPACITY是定义的私有变量,默认值是10,用来创建一个大小为10的数组。有参构造器中,int参数是用来生成一个指定大小的Object数组。将创建好的数组传给elementData。elementData是真正的用来存储元素的数组。

    add方法

    add 方法用来往容器中添加元素,add方法有两个重载方法,一个是add(E e),另一个是add(int index, E e)。add本身很简单,但是要处理动态数组,即数组大小不满足的时候,扩大数组的内存。具体的代码如下:

  • public void add(E e){

  • isCapacityEnough(size + 1);

  • elementData[size++] = e;

  • }

  • 方法isCapacityEnough就是来判断是否需要扩容,传入的参数就是最小的扩容空间。因为add一个元素,所以最小的扩容空间,即新的长度是所有元素+ 1。这里的size就是真正的元素个数。

  • private void isCapacityEnough(int size){ if (size > DEFAULT_CAPACITY){

  • explicitCapacity(size);

  • } if (size < 0){ throw new OutOfMemoryError();

  • }

  • }

  • 判断扩容的方法也很简单,判断需要扩容的空间是不是比默认的空间大。如果需要的空间比默认的空间大,就调用explicitCapacity进行扩容。这里有个size小于0的判断,出现size小于0主要是因为当size超过Integer.MAX_VALUE就会变成负数。

  • private final static int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; private void explicitCapacity(int capacity){ int newLength = elementData.length * 2; if (newLength - capacity < 0){

  • newLength = capacity;

  • } if (newLength > (MAX_ARRAY_LENGTH)){

  • newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH);

  • }

  • elementData = Arrays.Of(elementData, newLength);

  • }

  • 上面的代码是扩容的代码,首先,定义一个数组最大的容量的常量为最大值,这个值按照官方的源码中的解释是要有些VM保留了数组的头部信息在数组中,因此实际存放数据的大小就是整数的最大值 - 8
    然后设定一个要扩容的数组的大小,虽然上面说了有一个扩容空间的值 size + 1 ,这个是实际我们最小需要扩容的大小。但为了继续增加元素,而不频繁的扩容,因此一次性的申请多一些的扩容空间。这里newLength 打算申请为 数组长度的2倍,然后去判断这个长度是否满足需要的扩容空间的值。 即有了后续的两段代码

  • if (newLength - capacity < 0){ newLength = capacity;

  • } if (newLength > (MAX_ARRAY_LENGTH)){ newLength = (capacity > MAX_ARRAY_LENGTH ? Integer.MAX_VALUE : MAX_ARRAY_LENGTH);

  • }

  • 如果2倍的长度仍然不满足,则申请到需要的扩容长度。在我们只增加一个元素的情况下,这个判断是永远不会生效的,但是如果有addAll方法,则增加的元素很多,就要导致一次申请2倍的长度是不够的。第二个判断是判断newLength的长度如果超过上面定义的数组最大长度则判断要需要的扩容空间是否大于数组最大长度,如果大于则newLength为 MAX_VALUE ,否则为 MAX_ARRAY_LENGTH。
    最后,真正实现数组扩容到设定长度的方法就没意思了,调用Arrays.Of(elementData, newLength)得到一个扩容后的数组。
    add的另一个重载方法也很简单。

  • public void add(int index, E e) {

  • //判断是不是越界

  • checkRangeForAdd(index);

  • //判断需不需要扩容

  • isCapacityEnough(size + 1);

  • //将index的元素及以后的元素向后移一位

  • System.array(elementData,index,elementData,index + 1,size - index);

  • //将index下标的值设为e

  • elementData[index] = e; size++;

  • }

  • private void checkRangeForAdd(int index){ //这里index = size是被允许的,即支持头,中间,尾部插入

  • if (index < 0 || index > size){ throw new IndexOutOfBoundsException("指定的index超过界限");

  • }

  • }

  • 至此,一个简单的add方法就实现完了。

    get方法

    get方法用来得到容器中指定下标的元素。方法实现比较简单,直接返回数组中指定下标的元素即可。

  • private void checkRange(int index) { if (index >= size || index < 0){

  • throw new IndexOutOfBoundsException("指定的index超过界限");

  • }

  • } public E get(int index){

  • checkRange(index); return (E)elementData[index];

  • }

  • indexOf方法

    indexOf方法用来得到指定元素的下标。实现起来比较简单,需要判断传入的元素,代码如下:

  • public int indexOf(Object o){ if (o != null) { for (int i = 0 ; i < size ; i++){ if (elementData[i].equals(o)){ return i;

  • }

  • }

  • }else { for (int i = 0 ; i < size ; i++){ if (elementData[i] == null) { return i;

  • }

  • }

  • } return -1;

  • }

  • 判断传入的元素是否为null,如果为null,则依次与null。如果不为空,则用equals依次比较。匹配成功就返回下标,匹配失败就返回-1。

    contains方法

    contains用来判断该容器中是否包含指定的元素。在有了indexOf方法的基础上,contains的实现就很简单了。

  • public boolean contains(Object o){ return indexOf(o) >= 0;

  • }

  • size方法

    size方法用来得到容器类的元素个数,实现很简单,直接返回size的大小即可。

  • public int size(){ return size;

  • }

  • isEmpty方法

    isEmpty方法用来判断容器是否为空,判断size方法的返回值是否为0即可。

  • public boolean isEmpty(){ return size() == 0;

  • }

  • remove方法

    remove方法是用来对容器类的元素进行删除,与add一样,remove方法也有两个重载方法,分别是
    remove(Object o)和remove(int index)

  • public E remove(int index) {

  • E value = get(index); int moveSize = size - index - 1; if (moveSize > 0){

  • System.array(elementData,index + 1, elementData,index,size - index - 1);

  • }

  • elementData[--size] = null; return value;

  • }

  • public boolean remove(Object o){ if (contains(o)){

  • remove(indexOf(o)); return true;

  • }else { return false;

  • }

  • }

  • 第一个remove方法是核心方法,首先得到要删除的下标元素的值,然后判断index后面的要前移的元素的个数,如果个数大于零,则调用库方法,将index后面的元素向前移一位。最后elementData[--size] = null;缩减size大小,并将原最后一位置空。
    第二个remove方法不需要向第一个方法一样,需要告诉使用者要删除的下标对应的元素,只需要判断是否删除成功即可。如果要删除的元素在列表中,则删除成功,如果不在则失败。因此调用contains方法就可以判断是否要删除的元素在列表中。在则调用remove(int index),不在则返回失败。

‘肆’ java中ArrayList类中的size()方法

size()就是获取到ArrayList中存储的对象的个数,举例:
List list = new ArrayList();
list.add("123");
list.add("123");
int c =list.size();
System.out.print(c);
上面输出的结果:2;
备注:list每次add,之后size值会进行加1,也就是说list的对象数增加了一个。

‘伍’ java Arraylist扩容为什么是1.5倍+1

//ArrayList类的源码:对内部数组扩容
publicvoidensureCapacity(intminCapacity){
modCount++;
intoldCapacity=elementData.length;
if(minCapacity>oldCapacity){
ObjectoldData[]=elementData;
intnewCapacity=(oldCapacity*3)/2+1;//计算新容量
if(newCapacity<minCapacity)newCapacity=minCapacity;
//,sothisisawin:
elementData=Arrays.Of(elementData,newCapacity);
}
}

‘陆’ 一开始学习java有必要看源代码吗诸如Arraylist,Linkedlist的这些源代码

你好,看源码是可以帮助你以后写代码的。如果你是刚开始学,就没有必要看那些东西。但是你要是有能力的话,看看还是很有帮助的,你说的那几个类,等你学习到了,最好还是看看,可以加深你对他们的理解。

‘柒’ java中Arraylist是干什么的怎么用

java中的ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本。

它提供了如下一些好处:动态的增加和减少元素实现了ICollection和IList接口灵活的设置数组的大小 。

ArrayList 的用法:

ArrayList List = new ArrayList(); for( int
i=0;i<10;i++ ) //

给数组增加10个Int元素 List.Add(i); //..

程序做一些处理
List.RemoveAt(5);//

将第6个元素移除 for( int i=0;i<3;i++ ) //

再增加3个元素
List.Add(i+20); Int32[] values =
(Int32[])List.ToArray(typeof(Int32));//

返回ArrayList包含的数组 。

(7)javaArraylist源码扩展阅读:

Arraylist的定义:

List 接口的大小可变数组的实现,位于API文档的java.util.ArrayList<E>。

实现了所有可选列表操作,并允许包括 null 在内的所有元素。

除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector 类,除了此类是不同步的。)

size、isEmpty、get、set、iterator 和 listIterator 操作都以固定时间运行。

add 操作以分摊的固定时间 运行,也就是说,添加 n 个元素需要 O(n) 时间。

其他所有操作都以线性时间运行(大体上讲)。

与用于 LinkedList 实现的常数因子相比,此实现的常数因子较低。

每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数组的大小。

它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。

并未指定增长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单

在添加大量元素前,应用程序可以使用
ensureCapacity 操作来增加 ArrayList
实例的容量。这可以减少递增式再分配的数量。

注意,此实现不是同步的。如果多个线程同时访问一个 ArrayList
实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。

(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)

这一般通过对自然封装该列表的对象进行同步操作来完成。

如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:

List list = Collections.synchronizedList(new ArrayList(...));

此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的。

在创建迭代器之后,除非通过迭代器自身的
remove 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出

因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

注意,迭代器的快速失败行为无法得到保证。

因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出

因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测
bug。

‘捌’ Java ArrayList C语言实现 函数体

分配内存的地方,修改成这样

array->data=(void**)malloc(sizeof(ArrayList)*array->size);

编译通过

‘玖’ JAVA关于ArrayList的代码的写法

import java.util.ArrayList;

public class TestMain {
public static void main(String[] args){
String[] inStrArr = new String[]{"Nisse","Oskar","Lena","Adam","Jens","Beata","Cecilia","Stina","Pelle"};

ArrayList<String> retArr = smallStrings(inStrArr,"Lennart");

for(String retStr : retArr){
System.out.println(retStr);
}
}

public static ArrayList<String> smallStrings(String[] inStrArr,String str){
ArrayList<String> retArr = new ArrayList<String>();

for(String inStr : inStrArr){
if(str.compareTo(inStr) > 0){
retArr.add(inStr);
}
}

return retArr;
}
}

‘拾’ arraylist java源码为什么判断o==null

因为null不能参与运算,一旦参与,会报Null Pointer(空指针)异常。
如下:
Student a = null;
a.name 就会报异常。

ArrayList一样的道理,如果为null,遍历的时候同样报错。

热点内容
php旅游网站系统 发布:2024-05-07 20:27:32 浏览:610
jdk源码怎么看 发布:2024-05-07 20:18:22 浏览:519
编程c语言自学书 发布:2024-05-07 20:12:03 浏览:422
usb大容量存储驱动 发布:2024-05-07 19:02:01 浏览:815
红米1s没有存储空间 发布:2024-05-07 18:59:09 浏览:505
妖云解压密码 发布:2024-05-07 18:50:08 浏览:1002
sql语句等于怎么写 发布:2024-05-07 18:05:46 浏览:816
我的世界电脑版第三方服务器大全 发布:2024-05-07 18:00:46 浏览:627
主服务器的ip地址 发布:2024-05-07 17:58:50 浏览:546
组服务器打电脑游戏 发布:2024-05-07 17:46:19 浏览:866