数组Array
数组 是一种顺序存储的线性表,所有元素的内存地址是连续的。
数组向堆空间申请一连串的内存空间:
在很多编程语言中,数组都有个致命的缺点:无法动态修改容量,而实际开发中,我们更希望数组的容量是可以动态改变的
动态数组(Dynamic Array)
接口设计:
> 1. int size();size();// 元素的数量
> 2. boolean isEmpty();isEmpty();//是否为空
> 3. boolean contains(E elementelement); // 是否包含某个元素
> 4. void add(E elementelement); // 添加元素到最后面
> 5. E get( int indexindex); //返回 index 位置对应的元素
> 6. E set( int index , E elementelement); // 设置index 位置的元素
> 7. void add( int index , E elementelement); // 往index位置添加元素
> 8. E remove( int indexindex); // 删除 index 位置对应的元素
> 9. int indexOf(E elementelement); // 查看元素的位置
> 10. void clear();clear();//清除所有元素
打印数组:
- 重写toString方法
- 在toString方法中将元素拼接成字符串
- 字符串拼接建议使用StringBuilder
// 打印数组,重写toString()方法
@Override
public String toString() {
// size = 3,[11,22,33]
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(", [");
for (int i = 0; i < size; i++) {
if(i != 0) {
stringBuilder.append(", ");
}
stringBuilder.append(elements[i]);
// if(i != size - 1) {
// stringBuilder.append(", ");
// }
}
stringBuilder.append("]");
return stringBuilder.toString();
}
如何扩容:
一旦发现数组空间不够用时,new一个比原来数组空间大的数组,并将原数组的数据依次复制到新数组中,最后指向新数组。
/**
* 保证要有capacity的容量
* @param capacity
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if(oldCapacity >= capacity) return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity+"扩容为:"+newCapacity);
}
使用泛型技术可以让动态数组更加通用,可以存放任何数据类型
内存管理细节
null的处理
根据自己的需要,是否可以存储null数据
ArrayList实现代码:
package com.gyl;
// 动态数组设计
/**
* @author DELL
*
*/
// Alt + Shift + J 快速添加函数注释
/**
* @author DELL
*
*/
@SuppressWarnings("unchecked")
// 泛型
public class ArrayList<E> {
/**
* 元素的数量
*/
private int size;
/**
* 所有的元素
*/
private E[] elements;
private static final int DEFAULT_CAPACITY = 10;
private static final int ELEMENT_NOT_FOUND = -1;
public ArrayList(int capacity) {
capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity;
elements = (E[]) new Object[capacity];
}
public ArrayList() {
// elements = new int[DEFAULT_CAPACITY];
// 通过this调用有参的构造方法
this(DEFAULT_CAPACITY);
}
/**
* 清除所有元素
*/
public void clear() {
// 清空数组中的地址值,对象内存销毁,数组内存还在
// 能循环利用的留下,不能循环利用的销毁
for(int i = 0;i < size;i++) {
elements[i]= null;
}
size = 0;
}
/**
* 元素的数量
* @return
*/
public int size() {
return size;
}
/**
* 是否为空
* @return
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 是否包含某个元素
* @param element
* @return
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
/**
* 添加元素到尾部
* @param element
*/
public void add(E element) {
add(size,element);
}
/**
* 获取index位置的元素
* @param index
* @return
*/
public E get(int index) {
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index:"+index+", Size:"+size);
}
return elements[index];
}
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素
*/
public E set(int index,E element) {
rangeCheck(index);
E old = elements[index];
elements[index] = element;
return old;
}
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
public void add(int index,E element) {
rangeCheckForAdd(index);
ensureCapacity(size + 1);
// 算法优化
// for(int i = size - 1;i >= index;i--) {
// elements[i+1] = elements[i];
// }
for(int i = size;i > index;i--) {
elements[i] = elements[i - 1];
}
elements[index] = element;
size++;
}
/**
* 删除index位置的元素
* @param index
* @return 返回被删除的元素
*/
public E remove(int index) {
rangeCheck(index);
E old = elements[index];
// 算法优化
for(int i = index+1;i < size;i++) {
elements[i - 1] = elements[i];
}
elements[--size] = null;
return old;
}
/**
* 删除元素element
* @param element
*/
public void remove(E element) {
remove(indexOf(element));
}
/**
* 查看元素的索引
* @param element
* @return
*/
public int indexOf(E element) {
// 找到第一个为空的位置
if(element == null) {
for(int i = 0;i < size;i++) {
if(elements[i] == element) return i;
}
}else {
for(int i = 0;i < size;i++) {
if(element.equals(elements[i])) return i;
}
}
// == 默认比较内存地址是否相等,太局限
// equals 提供接口自定义比较规则
return ELEMENT_NOT_FOUND;
}
/**
* 保证要有capacity的容量
* @param capacity
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if(oldCapacity >= capacity) return;
// 新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
E[] newElements = (E[]) new Object[newCapacity];
for (int i = 0; i < size; i++) {
newElements[i] = elements[i];
}
elements = newElements;
System.out.println(oldCapacity+"扩容为:"+newCapacity);
}
/**
* 抛出数组越界异常
* @param index
*/
private void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:"+index+", Size:"+size);
}
/**
* 检查index范围
* @param index
*/
private void rangeCheck(int index) {
if(index < 0 || index >= size) {
outOfBounds(index);
}
}
private void rangeCheckForAdd(int index) {
if(index < 0 || index > size) {
outOfBounds(index);
}
}
// 打印数组,重写toString()方法
@Override
public String toString() {
// size = 3,[11,22,33]
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("size=").append(size).append(", [");
for (int i = 0; i < size; i++) {
if(i != 0) {
stringBuilder.append(", ");
}
stringBuilder.append(elements[i]);
// if(i != size - 1) {
// stringBuilder.append(", ");
// }
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}