【Java】轻松搞定数组队列的动态存储!

——脱离弟中弟,看破楼外楼;

需要注意的是,在这里我们仅做简单的阐述,不做深入展开。

在这里我们实现数组的动态存储主要是两个方面:

  1. 存储对象的类的动态化(可以只存一类,也可以全部储存),这里我们使用泛型来解决。
  2. 存储对象的总量的动态化/数组长度动态,我们通过自定义数组来解决这个问题。

从另外一个角度看,我们实现JDK中Arraylist的部分功能,
目的是能够做到自定义一个数组队列,无关功能丰富,
能够满足需求的精简队列才是实际上会使用的;

再从一个角度上看,我们在学习数据结构的一些基础知识嘛:)

那么我们开始吧!



存储对象的类的动态化


泛型的需要场合

    当我们在写方法但是却不知道方法具体会调用什么类的时候,
    我们可以先将需要的对象类型写为Object
    (包括基本数据类型,如int,float等基本数据类型都有封装的类作为object的子类)

 public void fuc(Object o){}

    之后再强制转型成相应的类

 int a=10;
 int i=(int)fuc(a);

    但是,当我们传入的对象有时需要是特定的类,有时需要是所有的类,
    这个时候前面的需求就无法解决了,所以我们需要用到泛型


泛型的简单使用

泛型的直观理解是占位
    我们先指定这里需要有个东西存在,就在这里占个位,
    之后再用具体的事物把这个占位替换掉。

具体操作如下,当我们在自定义数列列表中这么写
当我们要新建该类时,可以指定只能传入特定的类

public class Myarraylist<E>{}
public MyArrayList() {array = new Object[0];}

实例化数组时这么写

Myarraylist<student>[] ml=new Myarraylist<student>();//假设已经定义了一个student的类。

或者不指定,所有的类都可以传入。

 Myarraylist[] ml=new Myarraylist();

需要注意的是,泛型有特定的字母,这里我们就用< E >!
同时泛型不能指定基本数据类型(int等)
,那实在要用到基本数据类型怎么办呢?
还记得刚刚前面有提到过,基本数据类型都有相应封装的类作为Object的子类,
比如int对应着一个Integer的类,于是我们可以用

      Integer a=new Integer(1);

来取代

      int a=1;



存储对象的总量的动态化


我们先做一个小补充吧:)

数组的定义:

首先是一维数组

  1. 数据类型[] 数组名 = {值,…};
  2. 数据类型[] 数组名 = new 数据类型[长度];
  3. 数据类型[] 数组名 = new 数据类型[]{值,…};

仔细回想使用数组的过程,通常用1来储存已知的体量较小的数据,用2去存储需要用for语句去不断存储的数据。
需要注意的是,1其实是规定好自动添加3的"new 数据类型[]",也仅在该种定义方式下做省略。


当然如果在某个类中已经定义了一个数组作为属性,那么可以这么用

  1. 数组名 = new 数据类型[长度];
  2. 数组名 = new 数据类型[]{值,…};

需要注意的是,数组名 ={值,…};语句是无效的,因为在这个语句中不会自动添加"new 数据类型[]"。


二维数组是类似的,这样就可以得到想要的二维数组了。

  1. 数据类型[][] 数组名 = new 数据类型[行][列];
  2. 数据类型[][] 数组名 = new 数据类型[][]{{值,…},…};

使用数组过程中需要熟记于心的是:
调用方法时,数组通过数组名传入首地址,也就是说方法内改变了数组,方法外数组也会被改变了;
与之相较的变量传入的是值所以方法外的变量不受方法影响;



数组的存储特点:连续存储,大小固定,按序访问

  1. 第一个特点导致我们在进行数据操作时十分繁琐,
    具体而言就是当我们进行插入或是删除,在对应索引位置之后的元素都要进行移动
    不然我们会在插入时无位可插,或删除后在队列中间的位置空出一个位。
    ——>那么能不能进行自动补位或挪位的操作呢?

  2. 第二个特点导致我们在数据元素个数未知时显得十分被动,
    数组长度太长,开辟太多内存空间,浪费。
    数组长度太短,我们时常会面临数组越界的尴尬情况。
    ——>能否确定合适的数组大小呢?能否自动改变数组长度呢?

  3. 可谓数组的最大优点,是这位小老弟在数据结构中的核心竞争力,
    数组是所有数据结构中访问速度最快的一种。

  基于以上的叙述,我们充分发挥主观能动性:)
  定义一个新类,封装一些基础方法,让这位小老弟扬长避短。



基于数组特定,数组列表要实现的功能及实现的原理

一.判断是否需要改变数组长度
  1. 对应的两种主要情况:
       数组数据被大量删除,缩短空间
       ——>数据元素远小于数组长度;
      数据总数超过数组长度
       ——>数组长度为零;

  2. 数组长度:array.length;
    数据总量:private int size;

二.实现数组长度的动态改变
  1. 创建一个长度符合要求的新数组;
  2. 将原数组数数据copy到新数组;
  3. 原组名指向的地址改成指向新数组的地址
  4. 原数组jvm自动销毁空间,无需我们操作;
  • 不知道大家看到第三点能不能理解呢?
  • 对于由java中数组内存空间的分配到java整体内存空间分配,
    我没有弄懂,导致对声明和实例化对象有一种半知不解的感觉,
    这里先做一个小预告吧,之后会写一篇详细介绍java内存分配的文章,
    写完了会把这里替换掉,稍微期待一下:)
    毕竟要对自己文章负责嘛;

没了,核心就这两点,搞定它我们就完成一大部分了。


基于此上我们可以写一个refresh方法,用于判断并改变数组长度。

//判断并更新数组长度的方法,size过小,数组长度不够,数组长度为0,手动开启
      private void  refresh()
      {
    	  if(size>=array.length||array.length == 0||flag ==1)
    	  {
    		  Object[] newarray=new Object[array.length+rate];
    		  for(int i=0;i<array.length;i++)
    		  {
    			  newarray[i]=array[i];
    		  }
    		  array=newarray;
    		  
    	  }
    	  else if(size<array.length/2)
    	  {
              Object[] newarray=new Object[size+rate];
    		  for(int i=0;i<size;i++)
    		  {
    			  newarray[i]=array[i];
    		  }
    		  array=newarray;
    	  }
      }



三、基础操作的实现
  1. 增加,减少,替换数据,及对应的补位;
  2. 操作的对象:一个对象(一个索引),一个队列(一个索引);
  3. 补位或插入空元素我们先各写一个基本方法(move/add);
  4. 每次添加或删除时都会调用到他们。每次添加或删除时都会调用到他们;

基本的实现逻辑就是,索引值对应的位置后的元素左移(将空位补掉)或右移(腾出空位);
需要注意的是他们开始的位置是不同的,前者从左往右,后者从右往左,目的是避免元素被覆盖;

   //进行补位的操作,通过指定位置来补位,每次移除单个元素时都会调用此方法进行补位,同时同步元素总数个数
      private void move(int index)
      {
    	  for(int i=index;i<size;i++)
    	  {
    		  array[i]=array[i+1];
    	  }
    	  size--;
      }
      //进行插入空位置的方法,每次插入单个元素时会调用此方法,同时同步元素总数个数
      private void add0(int index)
      {
    	  for(int i=size;i>index;i--)
    	  {
    		  array[i+1]=array[i];
    	  }
    	  size++;
      }



2019.2.15:代码更新,运行检验无误,基本完成JDK中ArrayList的方法;
问题: 1.jvm的内存分配机制;
2.collection的理解;
3.java中的应用,浅表副本的理解;
4.异常抛出存在细节问题;

完整代码如下


实现的主要功能如图JDK-Arraylist

   package Myarraylist;


public class MyArrayList<E> {
	public  Object[] Array;
	private  int size=0;
	public String name;
	public MyArrayList(int size) {
		Array=new Object[size];
	}
	
	public MyArrayList()
	{
		Array=new Object[0];
	}
	private void refresh()
	{
		if(size>=Array.length)
		{
			Object[] newList=new Object[size+10];
			for(int i=0;i<size;i++)
			{
				newList[i]=Array[i];
			}
			Array=newList;
		}
	}
	private void refresh(boolean j)
	{
		
			Object[] newList=new Object[Array.length+10];
			for(int i=0;i<size;i++)
			{
				newList[i]=Array[i];
			}
			Array=newList;
	}
	private void moveR(int index)
	{
		if(index>Array.length)
		{
			System.out.println("error");
		}
		else 
		{
			refresh();
			for(int i=size;i>=index;i--)
			{
				Array[i+1]=Array[i];
			}
		}
		
	}
	private E moveL(int index)
	{
		if(index>=Array.length)
		{
			System.out.println("error");
		}
		else 
		{
			E a=(E) Array[index];
			for(int i=index;i<size-1;i++)
			{
				Array[i]=Array[i+1];
			}
			size--;
			return a;
		}
		return null;
		
	}
	public boolean add(E e)
	{
		refresh();
		Array[size]=e;
		size++;
		return true;
	}
	public void add(int index,E e)
	{
		refresh();
		if(index>=size)
		{
			System.out.println("error");
		}
		else 
		{
			moveR(index);
			Array[index]=e;
			size++;
		}
	}
	public boolean addAll(MyArrayList<E> a)
	{
		if(a.size<10)
		{
			refresh(true);
			int bsize=size;
			for(int i=0;i<a.size;i++)
			{
				Array[bsize+i]=a.Array[i];
				size++;
			}
		}
		else
		{	int bsize=size;
			refresh(true);
			for(int i=0;i<a.size;i++)
			{
				
				if(i%10==0)
				{
					refresh(true);
				}
				Array[bsize+i]=a.Array[i];
				this.size++;
			}
		}
		return true;
	}
	public boolean addAll(MyArrayList<E> a,int index)
	{
		if(a.size<10)
		{
			refresh(true);
			for(int i=0;i<a.size;i++)
			{
				moveR(index+i);
				Array[index+i]=a.Array[i];
				size++;
			}
		}
		else
		{
			for(int i=0;i<a.size;i++)
			{
				if(i%10==0)
				{
					refresh(true);
				}
				moveR(index+i);
				Array[index+i]=a.Array[i];
				size++;
			}
		}
		return true;
	}

	public void clear()
	{
		Object[] newList=new Object[size];
		Array=newList;
		size=0;
	}
	public Object clone()
	{
		return (Object)this;
	}
	public boolean contains(Object o)
	{
		boolean a=false;
		for(int i=0;i<size;i++)
		{
			//三目运算符;
			a=(o==null ? Array[i]==null : o.equals(Array[i]));
			if(a==true)
			{
				return a;
			}
		}
		return a;
	}
	public E get(int index)
	{
		return (E)Array[index];
	}
	public int indexof(Object o)
	{
		for(int i=0;i<size;i++)
		{
			if(Array[i].equals(o))
			{
				return i;
			}
		}
		return -1;
	}
	public boolean isEmpty()
	{
		for(int i=0;i<size;i++)
		{
			if(Array[i]!=null)
			{
				return false;
			}
		}
		return true;
	}
	public int lastIndexOf(Object o)
	{
		int g=-1;
		for(int i=0;i<size;i++)
		{
			if(o.equals(Array[i]))
			{
				g=i;
			}
		}
		
		return g;
		
	}
	public E remove(int index)
	{
		if(index>=size)
		{
			System.out.println("error");
		}
		else 
		{
			return moveL(index);
		}
		return null;
	}
	public boolean removeO(Object o)
	{
		for(int i=0;i<size;i++)
		{
			if(o.equals(Array[i]))
			{
				moveL(i);
				return true;
			}
		}
		return false;
	}
	protected void removeRange(int fromIndex,int toIndex)
	{
		int times =toIndex-fromIndex;
		if(times<0)
		{
			System.out.println("error");
		}
		else 
		{
			for(int i=0;i<times;i++)
			{
				moveL(fromIndex);
			}
		}
	}
	public E set(int index,E element)
	{
		E a=(E)Array[index];
		Array[index]=element;
		return a;
	}
	public Object[] toArray()
	{
		return Array;
	}
	//待完善;
	public <T> T[] toArray(T[] a)
	{
		return a;
	}
	public void trimTosize()
	{
		Object[] newArray=new Object[size];
		for(int i=0;i<size;i++)
		{
			newArray[i]=Array[i];
		}
		Array=newArray;
	}
	//这是为了方便检验结果而定义的方法;
	public void toMyString()
	{
		System.out.println("name: "+name+"  size:"+size+"  length:"+Array.length);
		for(int i=0;i<size;i++)
		{
			System.out.print("第"+i+"位"+":"+Array[i]+"      ");
			if(i%7==0&&i!=0)
			{
				System.out.println();
			}
		}
		System.out.println();
		System.out.println();
	}
	public static void main(String[] args) {
		
		System.out.println("——————————————————————————————————————————————————————————————————");
		
		MyArrayList a=new MyArrayList();
		MyArrayList b=new MyArrayList(10);
		MyArrayList c=new MyArrayList(10);
		a.name="a";
		b.name="b";
		c.name="c";
		
		
		
		System.out.println("调用add:");
		for(int i=0;i<6;i++)
		{
			a.add(i);
			b.add(i*2);
			c.add(i*3);
			c.add(i*4);
		}
		a.toMyString();
		b.toMyString();
		c.toMyString();
		
		System.out.println("调用add(指定索引):");
		b.add(2, 9);
		b.toMyString();
		
		System.out.println("调用addAll(比自身短):");
		b.addAll(a);
		b.toMyString();
		
		System.out.println("调用addAll(比自身长):");
		b.addAll(c);
		b.toMyString();
		
		System.out.println("调用addAll(比自身短+指定索引):");
		b.addAll(a, 2);
		b.toMyString();
		
		System.out.println("调用addAll(比自身长+指定索引):");
		c.toMyString();
		c.addAll(b,2);
		c.toMyString();
		
		System.out.println("——————————————————————————————————————————————————————————————————");
		System.out.println("调用clear:");
		c.clear();
		c.toMyString();
		
		System.out.println("clone存在问题");
		System.out.println( );
		//不是很懂浅表副本的含义,复制元素但不复制引用,说起来Java的对象赋值似乎就在进行引用?
		//此处留空。
		
		System.out.println("调用contains(1):");
		System.out.println(a.contains(1));
		System.out.println( );
		
		System.out.println("调用contains(元素为null):");
		System.out.println(a.contains(null));
		System.out.println( );
		
		System.out.println("调用get(index:2):");
		System.out.println(a.get(2));
		a.toMyString();
		
		System.out.println("调用indexOf:");
		System.out.println(a.indexof(2));
		System.out.println( );

		System.out.println("调用indexOf(不存在元素):");
		System.out.println(a.indexof(6));
		System.out.println( );
		
		System.out.println("调用isEmpty:");
		System.out.println(a.isEmpty());
		System.out.println( );
		
		System.out.println("调用isEmpty(空数列):");
		System.out.println(c.isEmpty());
		System.out.println( );
		
		System.out.println("调用lastIndexOf:");
		System.out.println(b.lastIndexOf(0));
		b.toMyString();
		
		System.out.println("调用lastIndexOf(不存在):");
		System.out.println(b.lastIndexOf(36));
		b.toMyString();
		
		System.out.println("——————————————————————————————————————————————————————————————————");
		
		System.out.println("调用remove(Index):");
		System.out.println(b.remove(2));
		b.toMyString();
		
		
		//移除此列表中首次出现的指定元素(如果存在);
		System.out.println("调用removeO(Object):");
		int numbera=1;
		System.out.println(b.removeO(numbera));
		b.toMyString();
		
		//注意不包括尾指引;
		System.out.println("调用removeRange(指定首尾索引):");
		b.removeRange(0,2);
		b.toMyString();
		
		System.out.println("调用set(指定索引+元素):");
		b.set(0,20);
		b.toMyString();
		
		System.out.println("toarray存在问题");
		System.out.println( );
		//一是不知道作用何在,二是不是很懂collection;
		//此处留空。
		
		System.out.println("调用trimTosize:");
		System.out.println("b.length:"+b.Array.length);
		b.trimTosize();
		System.out.println("b.length:"+b.Array.length);
		
	}

}


}

运行结果如下:
——————————————————————————————————————————————————————————————————
调用add:
name: a size:6 length:10
第0位:0 第1位:1 第2位:2 第3位:3 第4位:4 第5位:5

name: b size:6 length:10
第0位:0 第1位:2 第2位:4 第3位:6 第4位:8 第5位:10

name: c size:12 length:20
第0位:0 第1位:0 第2位:3 第3位:4 第4位:6 第5位:8 第6位:9 第7位:12
第8位:12 第9位:16 第10位:15 第11位:20

调用add(指定索引):
name: b size:7 length:10
第0位:0 第1位:2 第2位:9 第3位:4 第4位:6 第5位:8 第6位:10

调用addAll(比自身短):
name: b size:13 length:20
第0位:0 第1位:2 第2位:9 第3位:4 第4位:6 第5位:8 第6位:10 第7位:0
第8位:1 第9位:2 第10位:3 第11位:4 第12位:5

调用addAll(比自身长):
name: b size:25 length:50
第0位:0 第1位:2 第2位:9 第3位:4 第4位:6 第5位:8 第6位:10 第7位:0
第8位:1 第9位:2 第10位:3 第11位:4 第12位:5 第13位:0 第14位:0
第15位:3 第16位:4 第17位:6 第18位:8 第19位:9 第20位:12 第21位:12
第22位:16 第23位:15 第24位:20

调用addAll(比自身短+指定索引):
name: b size:31 length:60
第0位:0 第1位:2 第2位:0 第3位:1 第4位:2 第5位:3 第6位:4 第7位:5
第8位:9 第9位:4 第10位:6 第11位:8 第12位:10 第13位:0 第14位:1
第15位:2 第16位:3 第17位:4 第18位:5 第19位:0 第20位:0 第21位:3
第22位:4 第23位:6 第24位:8 第25位:9 第26位:12 第27位:12 第28位:16
第29位:15 第30位:20

调用addAll(比自身长+指定索引):
name: c size:12 length:20
第0位:0 第1位:0 第2位:3 第3位:4 第4位:6 第5位:8 第6位:9 第7位:12
第8位:12 第9位:16 第10位:15 第11位:20

name: c size:43 length:60
第0位:0 第1位:0 第2位:0 第3位:2 第4位:0 第5位:1 第6位:2 第7位:3
第8位:4 第9位:5 第10位:9 第11位:4 第12位:6 第13位:8 第14位:10
第15位:0 第16位:1 第17位:2 第18位:3 第19位:4 第20位:5 第21位:0
第22位:0 第23位:3 第24位:4 第25位:6 第26位:8 第27位:9 第28位:12
第29位:12 第30位:16 第31位:15 第32位:20 第33位:3 第34位:4 第35位:6
第36位:8 第37位:9 第38位:12 第39位:12 第40位:16 第41位:15 第42位:20

——————————————————————————————————————————————————————————————————
调用clear:
name: c size:0 length:43

clone存在问题

调用contains(1):
true

调用contains(元素为null):
false

调用get(index:2):
2
name: a size:6 length:10
第0位:0 第1位:1 第2位:2 第3位:3 第4位:4 第5位:5

调用indexOf:
2

调用indexOf(不存在元素):
-1

调用isEmpty:
false

调用isEmpty(空数列):
true

调用lastIndexOf:
20
name: b size:31 length:60
第0位:0 第1位:2 第2位:0 第3位:1 第4位:2 第5位:3 第6位:4 第7位:5
第8位:9 第9位:4 第10位:6 第11位:8 第12位:10 第13位:0 第14位:1
第15位:2 第16位:3 第17位:4 第18位:5 第19位:0 第20位:0 第21位:3
第22位:4 第23位:6 第24位:8 第25位:9 第26位:12 第27位:12 第28位:16
第29位:15 第30位:20

调用lastIndexOf(不存在):
-1
name: b size:31 length:60
第0位:0 第1位:2 第2位:0 第3位:1 第4位:2 第5位:3 第6位:4 第7位:5
第8位:9 第9位:4 第10位:6 第11位:8 第12位:10 第13位:0 第14位:1
第15位:2 第16位:3 第17位:4 第18位:5 第19位:0 第20位:0 第21位:3
第22位:4 第23位:6 第24位:8 第25位:9 第26位:12 第27位:12 第28位:16
第29位:15 第30位:20

——————————————————————————————————————————————————————————————————
调用remove(Index):
0
name: b size:30 length:60
第0位:0 第1位:2 第2位:1 第3位:2 第4位:3 第5位:4 第6位:5 第7位:9
第8位:4 第9位:6 第10位:8 第11位:10 第12位:0 第13位:1 第14位:2
第15位:3 第16位:4 第17位:5 第18位:0 第19位:0 第20位:3 第21位:4
第22位:6 第23位:8 第24位:9 第25位:12 第26位:12 第27位:16 第28位:15
第29位:20

调用removeO(Object):
true
name: b size:29 length:60
第0位:0 第1位:2 第2位:2 第3位:3 第4位:4 第5位:5 第6位:9 第7位:4
第8位:6 第9位:8 第10位:10 第11位:0 第12位:1 第13位:2 第14位:3
第15位:4 第16位:5 第17位:0 第18位:0 第19位:3 第20位:4 第21位:6
第22位:8 第23位:9 第24位:12 第25位:12 第26位:16 第27位:15 第28位:20

调用removeRange(指定首尾索引):
name: b size:27 length:60
第0位:2 第1位:3 第2位:4 第3位:5 第4位:9 第5位:4 第6位:6 第7位:8
第8位:10 第9位:0 第10位:1 第11位:2 第12位:3 第13位:4 第14位:5
第15位:0 第16位:0 第17位:3 第18位:4 第19位:6 第20位:8 第21位:9
第22位:12 第23位:12 第24位:16 第25位:15 第26位:20

调用set(指定索引+元素):
name: b size:27 length:60
第0位:20 第1位:3 第2位:4 第3位:5 第4位:9 第5位:4 第6位:6 第7位:8
第8位:10 第9位:0 第10位:1 第11位:2 第12位:3 第13位:4 第14位:5
第15位:0 第16位:0 第17位:3 第18位:4 第19位:6 第20位:8 第21位:9
第22位:12 第23位:12 第24位:16 第25位:15 第26位:20

toarray存在问题

调用trimTosize:
b.length:60
b.length:27


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值