容器
数组也是一种容器,但是容器更加灵活、更加强大,它的容量是随时可扩的。
- 层次结构图
【注:图片来源:尚学堂】
set、List继承collection;
实现set接口:Hashset;
实现List接口:ArrayList、LinkedList;
实现Map接口:HashMap。
ArrayList的特点
List是有序、可重复的容器
List接口的实现类有:ArrayList、LinkedList和vector
ArrayList底层是用数组实现存储的。
特点:
- 查询效率高
- 增删效率低
- 线程不安全
- 可存放任意数量的对象,但是对数组来说,它的数组长度是有限的。原因:ArrayList类中有长度自动扩容的方法(超出本身长度的话,长度就会自身增加本身长度的一半,再把原来长度中的数据copy到新的长度数组中来。查看源码可知)
手工实现ArrayList
下面一些基本方法可以查看ArrayList中的源码。为了加深对ArrayList的了解,手动去实现一个ArrayList。
ArrayList中一些基本方法:
- 定义返回数组长度方法(size())
- 判断容器是否为空(isElmpty())
- 在容器中按顺序插入数据方法(add())
- 给定位置插入数据方法(add(int index, E element))
- 输入索引获取数据元素值(get(int index) )
- 在index位置设置数据元素值(set(E element,int index))
- 查找某数据元素值x,返回该数据元素值的位置(==indexOf(Object x) ==)
- 给出索引位置,删除该位置的数据元素值(remove(int index))
- 给出数据元素值,删除这个数据元素值(remove(E element))
手工实现ArrayList:
package arrayListTest;
//手工实现ArrayList,体会底层原理
public class ArrayTest5<E> {
private Object[] elementDate;
private int size;
private static final int DEFALT_CAPACITY = 10;
//默认的构造方法,查看源码可知初始化时定义了长度为10的数组
public ArrayTest5(){
elementDate = new Object[DEFALT_CAPACITY];
}
public ArrayTest5(int capacity) throws Exception {
if(capacity==0) {
elementDate = new Object[DEFALT_CAPACITY];
}else if(capacity<0){
throw new Exception("输入的容器数量不合法!");
}else {
elementDate = new Object[capacity];
}
}
public int size() {
return size;
}
public boolean isElmpty() {
return size == 0?true:false;
}
public void add(E element) {
//扩容操作(size == elementDate.length---->扩容)
if(size == elementDate.length){
//怎么扩容?
//Object[] newArray = new Object[elementDate.length<<1]; 左移(这方法效率较高),相当于长度*2;但是防止数组长度过多的浪费,
//所以定义长度为:原来长度+原来长度/2
Object[] newArray = new Object[elementDate.length + (elementDate.length>>1)]; //右移,除2
//拷贝(使用的是系统提供的函数)
System.arraycopy(elementDate, 0, newArray, 0, elementDate.length);
elementDate = newArray;
}
elementDate[size++] = element;
}
public void add(int index,E x) throws Exception {
check(index);
size++;
System.arraycopy(elementDate, index, elementDate, index+1, size-index);
elementDate[index] = x;
}
//方便其它需要检查索引的调用
public void check(int index)throws Exception {
if(index < 0 || index > elementDate.length-1 ) {
throw new Exception("输入的索引不合法!");
}
}
//输入索引获取值
public E get(int index) throws Exception {
check(index);
return (E)elementDate[index];
}
//为index位置设置值
public void set(E element,int index) throws Exception {
check(index);
elementDate[index] = element;
}
//indexOf查找方法
public int indexOf(Object x) {
return indexOfRange(x,0,elementDate.length);
}
public int indexOfRange(Object x,int start,int end) {
Object[] s = elementDate;
if(x==null) {
for(int i=start;i<end;i++) {
if(s[i]==null) {
return i;
}
}
}else {
for(int i=start;i<end;i++) {
if(s[i].equals(x)) {
return i;
}
}
}
return -1;
}
//remove方法
public void remove(E element) throws Exception {
for(int i = 0;i < size;i++) {
if(element.equals(get(i))) {
remove(i);
}
}
}
public void remove(int index) {
int numRemove = elementDate.length - index - 1;
if(numRemove > 0 ) {
System.arraycopy(elementDate, index+1, elementDate, index, numRemove);
}
/*elementDate[size-1] = null;
size--;
相当于如下:*/
elementDate[--size] = null;
}
//重写toString方法
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("["); //增加字符序列
for(int i = 0;i<size;i++) {
sb.append(elementDate[i] + ",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) throws Exception {
ArrayTest5<String> s1 = new ArrayTest5<>();
for(int i = 0;i<30;i++) { //超出默认长度,扩容
s1.add("哈" + i);
}
System.out.println(s1);
System.out.println(s1.get(10));
s1.set("呼", 15);
System.out.println(s1);
s1.remove("哈20");
System.out.println(s1);
System.out.println(s1.indexOf("哈13"));
s1.add(2, "happy");
System.out.println(s1);
}
}
【结果】
声明:根据观看bilibili中的【尚学堂】视频学习整理!