赞
踩
Java集合框架,又被称为容器container,是定义在 java.util 包下的一组 接口interfaces 和其实现的 类classes .
其主要表现为将多个元素置于一个单元中,用于对这些元素进行快速便捷的 存储store , 检索retrieve , 管理manipulate ,即平时俗称的 增删查改CRUD .
也就是说,集合框架是很多类组成的,每个类的背后就是一种数据结构.
线性表(linear list) 是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结构,常见的线性表: 顺序表,链表,栈,队列...
线性表在逻辑上是线性结构,是连续的一条址线; 但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储.
顺序表是用一段物理地址连续的存储单元 依次存储 数据元素的线性结构,一般情况下采用 数组 存储.在数组上完成数据的增删查改.
1.在src包底下创建以下类和接口
2.IList接口代码实现
- public interface IList {
- public void add(int data);
- // 在 pos 位置新增元素
- public void add(int pos, int data);
- // 判定是否包含某个元素
- public boolean contains(int toFind);
- // 查找某个元素对应的位置
- public int indexOf(int toFind);
- // 获取 pos 位置的元素
- public int get(int pos);
- // 给 pos 位置的元素设为 value
- public void set(int pos, int value);
- //删除第一次出现的关键字key
- public void remove(int toRemove);
- // 获取顺序表长度
- public int size();
- // 清空顺序表
- public void clear();
- // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
- public void display();
-
- boolean isFull();
-
- boolean isEmpty();
- }
3.MyArrayList类代码实现
- import java.util.Arrays;
-
- public class MyArrayList implements IList {
- public int[] elem;
- public int usedSize;
- //默认的容量
- public static final int DEFAULT_CAPACITY = 5;
- public MyArrayList() {
- elem = new int[DEFAULT_CAPACITY];
- }
-
- //添加元素,默认添加到数组的最后位置
- @Override
- public void add(int data) {
- //1.判断数组是否满了,满了要扩容
- if(isFull()) {
- elem = Arrays.copyOf(elem,2*elem.length);
- }
- elem[usedSize] = data;
- usedSize++;
- }
-
- /**
- * 给pos位置 添加一个元素(即指定位置插入元素)
- * @param pos
- * @param data
- */
- @Override
- public void add(int pos, int data) {
- //1.pos位置的判断
- checkPosOfAdd(pos);
- if(isFull()) {
- elem = Arrays.copyOf(elem,2*elem.length);
- }
- /**
- * 1.elem的下标i是 最后 一个存储的数据元素的位置,所以是usedSize-1 (移动元素,从后往前移动)
- * 2.i下标的元素赋值给i+1下标的元素
- * 3.i-- 往前挪一个
- * 4.当 i < pos 时结束
- * 5.将要添加的元素data 放到elem的pos位置 (元素放进去)
- * 6.usedSize++
- */
-
- for (int i = usedSize - 1; i >= pos; i--) {
- elem[i+1] = elem[i];
- }//(移动元素,从后往前移动)
- elem[pos] = data;//(元素放进去)
- usedSize++;
-
- }
-
- public void checkPosOfAdd(int pos) {
- if(pos <0 || pos > usedSize) {
- throw new PosException("pos位置为:" + pos);
- }
- }
-
- //查找当前元素 是否存在
- @Override
- public boolean contains(int toFind) {
- for (int i = 0; i < usedSize; i++) {
- if(elem[i] == toFind) {
- return true;
- }
- }
- return false;
- }
-
- //查找当前元素的下标
- @Override
- public int indexOf(int toFind) {
- for (int i = 0; i < usedSize; i++) {
- if(elem[i] == toFind) {
- return i;
- }
- }
- return -1;
- }
-
-
- //获取pos位置的值
- @Override
- public int get(int pos) {
- //1.pos位置不合法怎么办
- checkPosOfGet(pos);
- //2.为空怎么办
- if(isEmpty()) {
- throw new EmptyException("顺序表为空");
- }
- return elem[pos];
- }
-
- public void checkPosOfGet(int pos) {
- if(pos < 0 || pos >= this.usedSize) {
- throw new PosException("pos位置不合法" + pos);
- }
- }
-
- @Override
- public boolean isEmpty() {
- return usedSize == 0;
- }
-
- /**
- * 更新pos位置的值为value
- * @param pos
- * @param value
- */
- @Override
- public void set(int pos, int value) {
- checkPosOfGet(pos);
- if (isEmpty()) {
- throw new EmptyException("顺序表为空");
- }
- this.elem[pos] =value;
- }
-
- /**
- * 删除toRemove这个数字
- * @param toRemove
- */
- @Override
- public void remove(int toRemove) {
- if(isEmpty()) {
- throw new PosException("顺序表为空,不能删除");
- }
- int index = indexOf(toRemove);
- for (int i = index; i <usedSize-1 ; i++) {
- elem[i] = elem[i+1];
- }
- usedSize--;
- }
-
- @Override
- public int size() {
- return this.usedSize;
- }
-
-
- /**
- *清空顺序表 防止内存泄漏
- *
- *引用数据类型,将每个对象都置为null
- *基本数据类型,将元素置为0
- */
- @Override
- public void clear() {
- usedSize = 0;
- }
-
- //打印顺序表当中的所有元素
- @Override
- public void display() {
- for (int i = 0; i < usedSize; i++) {
- System.out.print(elem[i] +" ");
- }
- System.out.println();
- }
-
- @Override
- public boolean isFull() {
- return usedSize == elem.length;
- }
-
-
- }
4.异常类处理
- //Pos位置不合法异常
- public class PosException extends RuntimeException{
- public PosException() {
-
- }
-
- public PosException(String message) {
- super(message);
- }
- }
-
-
-
- //顺序表为空异常
- public class EmptyException extends RuntimeException{
- public EmptyException() {
- }
-
- public EmptyException(String message) {
- super(message);
- }
- }
5.Test测试代码实现
- public class Test {
- public static void main(String[] args) {
- MyArrayList myArrayList = new MyArrayList();
- myArrayList.add(10);
- myArrayList.add(20);
- myArrayList.add(30);
- myArrayList.add(40);
- myArrayList.display();
-
- myArrayList.remove(40);
- myArrayList.display();
- }
- }
6.运行结果
ArrayList是Java已经实现好的顺序表,我们只需要学习掌握ArrayList里面的方法!
当我们学习一个新的类时,一定要先从构造方法入手~
方法 | 解释 |
ArrayListI() | 无参构造 |
ArrayList(int initiCapacity) | 指定顺序表初始容量 |
ArrayList( Collection<? extends E> c) | 利用其他Collection构建ArrayList |
- //构造一个空的列表
- ArrayList<Integer> arrayList = new ArrayList<Integer>();
- arrayList.add(99);//将99存入顺序表 下同
- arrayList.add(88);
- arrayList.add(75);
- arrayList.add(64);
- System.out.println(arrayList);
ArrayList是以泛型方式实现的,使用时先实例化.
ArrayList()无参构造就是在创建的时候不需要 参数 去创建,至于他的初始化的内存是多少,是怎么样初始化的,下文会提到.
- //构造一个容量大小为10的列表
- ArrayList<Integer> arrayList = new ArrayList<Integer>(10);
- arrayList.add(11);//将11存入顺序表 下同
- arrayList.add(22);
- arrayList.add(75);
- arrayList.add(64);
- System.out.println(arrayList);
上面的是没有参数的,这里就是有参数的了,在括号里面增加的 参数 就是关于这个顺序表的 初始容量,也就是大小.
- //创建的 参数 其实就是用其他List的大小作为参数
- ArrayList<Integer> arrayList = new ArrayList<Integer>();
- arrayList.add(99);
- arrayList.add(88);
- arrayList.add(75);
- arrayList.add(64);
- System.out.println(arrayList);
-
- List<Number> arrayList1 = new ArrayList(arrayList);//把arraylist的大小作为参数传参
- arrayList1.add(99999999);//也有自己的add方法
- System.out.println(arrayList1);//打印输出[99, 88, 75, 64, 99999999],"把另一个集合 拿过来 构造当前的集合"
-
- //ArrayList<String> arrayList2 = new ArrayList<>(arrayList);//error
- /**
- 满足ArrayList实现了Collection接口的条件,但是不满足传入的参数是E类型或者E的子类类型().
- 传入的参数arrayList是Integer,和String无关系.既不是String类型也不是Stringent的子类类型
- */
ArrayList( Collection<? extends E> c)要同时满足两点:
- 顺序表要实现Collection接口
- 传入的参数是E类型本身 或者 E的子类类型 (? 表示通配符)
- ArrayList<Integer> arrayList = new ArrayList<Integer>();
- arrayList.add(99);
- arrayList.add(88);
- arrayList.add(75);
- arrayList.add(64);
- System.out.println(arrayList);
-
- List<Number> arrayList1 = new ArrayList(arrayList);
- arrayList1.add(99999999);
- System.out.println(arrayList1);//打印输出[99, 88, 75, 64, 99999999]
-
- //subList截取
- List<Number> list =arrayList1.subList(0,2);//下标
- System.out.println(list);
- //[99, 88, 75, 64, 99999999]
-
- //我们认为截取后list的值是[99, 88]
- System.out.println("=======================");
- list.set(0,199);
- System.out.println(list);//把list里面0下标的值改为199,就认为变成[199,88]
- System.out.println(arrayList1);//arrayList1里面的值不变,还是[99, 88, 75, 64, 99999999]
- /**
- * 实际输出:
- * [199, 88] list中
- * [199, 88, 75, 64, 99999999] arrayList1中
- * List<Number> list =arrayList1.subList(0,2);不是产生新的对象
- * list和arrayList1指向的是同一个对象
- * */
-
截取list中 [0,2)之间的元素 可以发现,arraylist1 和 list共用的是一个数组.list中发生改变时,arraylist1中的数据也会随之改变.
因此,截取方法不是产生一块新的对象,而是指向的同一个引用 .
- public static void main3(String[] args) {
- //ArrayList的遍历
- ArrayList<Integer> arrayList = new ArrayList<>();
- arrayList.add(10);
- arrayList.add(20);
- arrayList.add(30);
- arrayList.add(40);
- //第一种 直接输出
- System.out.println(arrayList);
- //第2种遍历方式 for
- for (int i = 0; i < arrayList.size(); i++) {
- System.out.print(arrayList.get(i) + " ");
- }
- System.out.println();
- //3、for-each
- for (int x: //自动装箱
- arrayList) {
- System.out.print(x + " ");
- }
- System.out.println();
- //4.迭代器(有多种使用方式)
- Iterator<Integer> it1 = arrayList.iterator();//iterator继承自Iterator
- while (it1.hasNext()) {
- System.out.print(it1.next() + " ");
- }
- System.out.println();
- //5
- Iterator<Integer> it2 = arrayList.listIterator();//listIterator继承自Iterator
- while (it2.hasNext()) {
- System.out.print(it2.next() + " ");
- }
- System.out.println();
- //6.从后向前遍历
- ListIterator<Integer> it3 = arrayList.listIterator(arrayList.size());
- //arrayList.size()是一个方法调用,它返回了arrayList列表的大小或元素数量。
- // 在这里,ListIterator<Integer> it3 = arrayList.listIterator(arrayList.size())的作用是
- // 创建一个ListIterator对象it3,并将其定位在arrayList列表的 末尾 位置。
- while (it3.hasPrevious()) {
- System.out.print(it3.previous() + " ");
- }
- System.out.println();
- }
ArrayList的add()方法
通过观察ArrayList的源码 ,发现:
总结:
- 当我们进行ArrayList()的无参构造时,初始大小为0. 当我们第一次add(存放数据元素)时,会分配大小为10给数组,而当10个放满的时候,进行1.5倍扩容。如果调用的是给定容量的构造方法(括号里面带参数),那么顺序表的大小,就是你指定的容量,放满了之后也是1.5倍的扩容。
- 检测是否真正需要扩容,如果是调用grow准备扩容
- 使用copyOf进行扩容
寄语:不要忘了你希望的远方
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。