学习了一段时间的Java,我们对Java的基本知识有了一定的了解,今天再来聊聊数组。
Java内置数组的特点
-
数组的长度一旦确定则不可更改
-
数组只能存储同一类型的数据
-
数组中每个存储空间大小一致且地址连续
-
数组提供角标的方式访问元素
我们发现数组又有一些局限性,于是在使用时又会有一些疑惑,我们可以总结一下
Java内置数组的潜在问题
容量不够用时,怎么办?
指定位置插入或删除元素,怎么做?
数组对象只有length属性,能满足更多的需求吗?
动态数组的封装
有了问题,我们就有想法,尝试用学过的知识来解决
能否用面向对象的思想,将数组进行再度封装呢?
可以的,我们可以把数组的相关属性和相关行为封装在类中
类似字符串String类,形成如下的调用形式
String s="HelloWorld";
s.charAt(1);
s.compareTo("Hello");
s.equals("Hello");
s.repalce('l','L');
数组对象.排序()
数组对象.插入(元素)
数组对象.查找(角标)
这样大大方便了我们对数组的操作
那么如何封装动态数组
属性方面:
- int size 数组的有效元素个数
- int capacity 数组的最大容量data.length
- E[] data 数据的存储容器
行为方面:
- 增()
- 删()
- 改()
- 查()
- 其他()
为什么要强调动态数组
动态数组是顺序存储结构的具体实现!
1)线性表的定义
零个或多个数据元素的有限序列
2)线性表接口List的定义
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
public interface List<E> extends Iterable<E>{
//获取线性表中元素的有效个数
int getSize();
//判断线性表是否为空表
boolean isEmpty();
//在线性表指定的index角标处插入元素e
void add(int index,E e);
//在线性表的表头处插入元素e
void addFirst(E e);
//在线性表的表位处插入元素e
void addLast(E e);
//获取线性表中指定角标index处的元素
E get(int index);
//获取表头元素
E getFirst();
//获取表尾元素
E getLast();
//修改线性表中指定角标index处的元素为新元素e
void set(int index,E e);
//判断线性表中是否包含元素e
boolean contains(E e);
//查找元素e的角标(从左到又默认第一个出现的元素角标)
int find(E e);
//删除并返回线性表中指定角标index处的元素
E remove(int index);
//删除并返回表头元素
E removeFirst();
//删除并返回表尾元素
E removeLast();
//删除指定元素e
void removeElement(E e);
//清空线性表
void clear();
}
创建线性表List的顺序存储结构实现类ArrayList
public class ArrayList<E> implements List<E>{
//创建E类型的一维数组
private E[] data;
//维护元素个数
private int size;
//默认最大容量为10
private static int DEFAULT_CAPACITY=10;
}
先创建一个顺序表 ,重写函数来获取元素有效个数与判断是否为空
//创建一个默认大小的顺序表
public ArrayList(){
this(DEFAULT_CAPACITY);
//data=(E[])(new Object[DEFAULT_CAPACITY]);
}
//创建一个容量由用户指定的顺序表
public ArrayList(int capacity){
if(capacity<=0) {
throw new IllegalArgumentException("容量>0:" + capacity);
}
data=(E[])(new Object[capacity]);
size=0;
}
//用户传入一个数组 将该数组封装成一个顺序表
public ArrayList(E[] data){
if(data==null){
throw new IllegalArgumentException("数组不能为空");
}
this.data=(E[])(new Object[data.length]);
for (int i = 0; i <data.length ; i++) {
this.data[i]=data[i];
}
size=data.length;
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size==0;
}
在指定角标插入元素时,如果数组已满,则需要扩容
@Override
public void add(int index, E e) {
if(index<0||index>size){
throw new IllegalArgumentException("角标越界");
}
if(size==data.length){
//扩容
resize(data.length*2);
}
for (int i = size; i >index ; i--) {
data[i]=data[i-1];
}
data[index]=e;
size++;
}
private void resize(int newLength) {
E[] newData=(E[])(new Object[newLength]);
for (int i = 0; i < size; i++) {
newData[i]=data[i];
}
data=newData;
}
@Override
public void addFirst(E e) {
add(0,e);
}
@Override
public void addLast(E e) {
add(size,e);
}
获取指定元素位置
@Override
public E get(int index) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
return data[index];
}
@Override
public E getFirst() {
return get(0);
}
@Override
public E getLast() {
return get(size-1);
}
修改线性表中指定角标index处的元素为新元素e
@Override
public void set(int index, E e) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
data[index]=e;
}
查找元素e的角标(从左到又默认第一个出现的元素角标)
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
在数组中查找是否含有指定元素e
@Override
public int find(E e) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
for (int i = 0; i < size; i++) {
if(data[i].equals(e)){
return i;
}
}
return -1;
}
删除并返回线性表中指定角标index处的元素
@Override
public E remove(int index) {
if(isEmpty()){
throw new IllegalArgumentException("线性表为空");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
E ret=data[index];
for(int i=index+1;i<size;i++){
data[i-1]=data[i];
}
size--;
if(size<=data.length/4&&data.length/2>=10){
resize(data.length/2);
}
return ret;
}
@Override
public E removeFirst() {
return remove(0);
}
@Override
public E removeLast() {
return remove(size-1);
}
删除指定元素e
@Override
public void removeElement(E e) {
int index=find(e);
if(index!=-1){
remove(index);
}else{
throw new IllegalArgumentException("元素不存在");
}
}
清空线性表
@Override
public void clear() {
size=0;
data=(E[])(new Object[DEFAULT_CAPACITY]);
}