ArrayList
一.实例化对象的两种方法
1.实例化操作
2.两种方式
这两种方法的区别:用第二个List引用的话只能用List接口中的方法,而不能使用ArrayList中的方法,第一个通过ArrayList的引用就可以用List的方法和自己的方法。
二.认识ArrayList的构造方法
1.不带参数的构造方法:
这是顺序表的底层逻辑,而顺序表本身就是数组,这个elementData就是数组。并且这里的elementData只是一个数组引用:
解释DEFAULTCAPACITY_EMPTY_ELEMENTDATA:这里是一个私有的静态常量为0,那么这个数组的长度就为0.
2.带参数的构造方法:
这里的if语句表示我们传入的参数大于0那么,我们传入的参数就是这个数组的容量。
如果我们传入的参数为0,他就等于EMPTY_ELEMENTDATA。
EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA一样是一个空数组,长度为0:
如果我们传入的参数小于0,那么就会抛出异常:
所以这个构造方法是初始化指定大小。
3.比较复杂的构造方法:
这里把参数拆分出来说明:
里面的c是一个变量,那么前面的Collection<? extends E >是一个类型,这里的Collection是一个顶层Iterable之下的第二大顶层接口,就说明只要实现了该接口,其他在他下面的接口都可以传递。其中?是通配符,<>里面的内容就是类似于泛型的上界,必须是E的子类或者她本身。
这里通过实例来讲解: 这里的我们直接将arraylist传入这个arraylist3中,为什么能传入呢?因为我们这里的arraylist她的类型属于Collection的子类Array List,并且其中<>的内容属于她本身,因为arraylist的<>是Integer而arraylist3也是Integer,并且这里就是和我们泛型的是上界差不多,只要是她的子类或者本身就行,所以就可以传入arraylist。
三.add方法
1.第一个add方法:
当我们在add的时候,传入的e就是我们传入需要add的数据,我们这次传入的是10,那么在add中,他里面还有一个add,那么这个add中的e就是我们传入的10,elementData就是们传入的数组引用,size就是0,这里我们调用的是没有参数的构造方法!,现在我们就要去看一下这个add内部的add的实现是什么。
add内部:
这里add进来之后,e就是传入的数据10,elementDate就是我们传入的数组,s就是传入数组的长度,所以这里s 等于数组的长度0,所以这里的elementData就等于一个grow的一个方法,这里就又要说grow(也叫扩容方法)的方法了。
grow方法内部:
来到这里之后又有一个grow那么又要去看一下内部:
第一个grow中size+1那么在第二个grow中的minCapacity就等于1,但是oldCapacity是等于数组的长度为0,那么第一个if语句的第一个判断就是false,因为这是或逻辑,看第二个语句elementData!=DEFAULTCAPACITY_EMPTY_ELEMENTDATA,但是我们的elementData就是等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA的,所以if语句不满足条件。这时候进入了else语句,那么此时add就会通过这个语句来给我们分配内存了。
这里return的语句就是通过new一个新的对象来开辟空间,然后空间的大小是在DEFAULT_CAPACITY和minCapacity中取较大值,而DEFAULT_CAPACITY我们需要去看一下他底层的数据是多少:
而我们的minCapacity才为1,所以这个新开辟空间的大小为10。
2.addAll
将一组数组直接添加到另一个数组当中:
四.删除方法
1.remove通过下标删除数组中的数据:
2.remove通过对象来删除数据,这里需要注意的是,必须通过装箱来删除数据,而不能直接输入数据本身:
五.截取方法
subList方法:(左闭右开)
注意这个subList是通过引用来直接使用的。
这里需要注意的是我们通过List引用来修改数据的时候原来数组的数据也被修改了,说明这里的数据直接是将引用传给List,而不是重新开辟一个新的空间。
六.遍历ArrayList
1.for循环:
2.for each循环:
3.迭代器:
迭代器需要通过Iterator这个接口的引用,在同过他的方法来进行迭代,下面通过图例说明:
it一开始在这个1的数据的上方并没有指向这个数据,然后it会通过it.hasNext()来判断下一个是否有数据,如果有就进入循环,在通过it.next将it向下移动到第一个数据的位置。一直往复到it.hasNext()判断下一个没有数据的时候就退出循环。
这里还可以通过ListIterator来进行迭代,因为ListIterator是Iterator的子类。这里还可以进行倒着迭代,原理都是一样的,但是在实例化对象的时候需要传入从哪个位置开始倒着打印:
七.Array List的使用
- 1.洗牌
- 首先我们需要先定义一个牌的类,因为在洗牌之前,我们必须先要有一副牌:
- 然后我们就需要得到一副牌:
- 这里一副牌就是4个花色,每个花色13张牌。首先通过Card类实例化一个对象来保存当前牌的数字和花色,再通过顺序表的List<Card> cardList引用来保存我们当前牌的花色和数字,因为我们<>内是Card,就是我们类的类型,那么这个数组的类型就是我们创建的一个牌的类型,然后保存好我们需要的牌之后我们再将顺序表的引用返回。
- 其次我们就需要洗牌了,因为不洗牌的话,这个牌就是我们刚买来的时候具有顺序,就没与任何意义了,这里我们需要用到随机数的知识:
- 这里我们运用到的原理是通过每个牌的对应下标,然后再通过随机数在对应下标下的范围来进行随机数的生成,然后将生成的随即下标和这个位置原本的下标进行交换,其中交换是通过自己写的一个方法来进行的:
- 交换的方法也很简单,本质就是通过tmp来作为中介然后进行数据的交换。
- 最后我们这里是需要给每个人发五张牌,那么我们就需要使用到二维数组这个玩意儿,并且我们还需要知道怎么给每个人轮流发牌:
- 我们先定义出每一个人装牌的空间。
- 然后我们再通过一个hands也就是二维数组来装他们的装牌空间的引用:
- 因为每个人5张牌,并且3个人轮流摸牌,所以我们这里是通过每次拿走第一张牌,(所谓的拿走第一张牌就是直接在牌组里面删除第一张牌,并且将这个牌保存下来)然后再把这张牌轮流给3个人。其中cardTmp就是通过hands.get(i)来找到是哪个人来拿牌,之后通过add把牌给这个人,拿牌结束再把他们的牌打印出来;
- 首先我们需要先定义一个牌的类,因为在洗牌之前,我们必须先要有一副牌:
- 2.用ArrayList写杨辉三角(二维数组)
- 首先,这里我们使用的是ArrayList这个顺序表的方法来写的这个二维数组,因为顺序表本身就是一个数组。对于杨辉三角,我们并不陌生,那么我们知道他大致就是这个样子的:
- 然后我们底层逻辑我们就不说了,直接来解释代码:这里我们知道,这里是需要用到二维数组的那么就和洗牌一样,先定义一个存放数组引用的数组:
- 然后我们就需要定义一个存放数据的数组了:
- 这样就构成了基本的二维数组,那么我们可以知道,第一行的数据就只有一个1,那么我们直接就先把第一行的数据添加出来:
- 然后从第二行的数据开始,我们就需要开始写循环了:
- 这里循环我们来进行解释一下:我们这里是直接定义了一个临时变量来作为每一行存放数组的数组,这样就可以让每次数组存储的数据都不一样了,然后我们这里需要从第二行开始,那么i就是初始化就等于1,我们知道每一行开始的第一个数据都是1,那么我们在循环一开始就直接添加一个1,那么我们就可以不需要在后续中添加,然后就开始写中间数据的生成,中间数据的生成的底层逻辑是通过上一行的第j-1列加上,上一行的j列的数据,得到下一行的第二行数据,所以这边的add是通过List这个二维数组先通过get拿到上一行哪个数组的数据,再通过get(j)拿到哪一行数组中的第j列数据,然后通过这样的方法计算出数组的下一行第j列的数据,在通过一维数组的List2把数据添加到临时变量,然后中间数据加完了之后,我们再通过add加上每一行最后一列的数据1,这样就把这个杨辉三角写出来了!
- 首先,这里我们使用的是ArrayList这个顺序表的方法来写的这个二维数组,因为顺序表本身就是一个数组。对于杨辉三角,我们并不陌生,那么我们知道他大致就是这个样子的:
八.面试题
CVTE的面试题:
这里我们是必须使用ArrayList的方法来写,那么就是如此的,这个题比较简单直接看方法:
第二种方法就是直接用StringBuilder或者用 StringBuffer来做:
注意其中的contains就是直接来遍历str2中与括号内ch是否存在相同的字符串。(这里的细节是我们比较的是字符,但是这里需要用到字符串,我们需要ch + " "就可以用来比较字符了)