模拟ArrayList,HashMap底层测试?

有干货!

建立了ArrayListTest类 , Genery类
在这里插入图片描述

(Genery<T> )是泛型

在这里插入图片描述

在这里插入图片描述

根据图示得出运行结果是
第一种返回的是字符串类型
第二种返回的是Integer类型
因为第一种我没有定义一定它的泛型类型,它可以是任意类型,返回Object类型
第二种我定义为Integer类型,那么(Genery<T>)里面被我赋上了Integer类型,那么它的类型只能是Integer Integer类型是给了 (Genery<T>) 上面的 T 赋值 (如果没有跟类型 它就默认Object类型 任意类型 )
在这里插入图片描述 (Genery<T>) 这里面的 T 也可以写成(Genery<E>) 当然下面也都有改正过来
而且还能多个泛型,例如:
(Genery<T,E>) 最常见的 类似于map集合的(Genery<K,V>) 当然有不同的作用,多个泛型要用逗号隔开

可能大家就要迷惑了?类似于map集合?
不慌,我们潜水一探究竟 HashMap更加直观一些
进入HashMap底层
搜索 entry 然后点击进去

在这里插入图片描述

在这里插入图片描述也就是接口下的Entry

这里你就发现为什么给map赋值的时候可以传任何值呢 ,
答案当然就是因为这个泛型
和ArrayList是一样的

  四个值
	   value = v;
       next = n;
       key = k;
       hash = h;

为什么和ArrayList也一样呢?
下图请看ArraList底层

在这里插入图片描述

我们可以发现里面的是element  返回的也是element  E
我们都知道添加的是一个**具体的泛型**
public boolean add(E e)添加的时候对象是E .
这个E翻译过来其实就是Object(前提是没有对她进行规定,如果规定好了呢  就是你具体给的他 规定的类型)

还包括一些泛型类 泛型方法 泛型接口,以后待更

那可能就有好学的好奇宝宝就要问l ?泛型什么时候起作用?
1,泛型在编译的阶段时候起作用(编译阶段语法拦截)
2,运行阶段执行(泛型被擦除),ArrayList来说它其实只支持Object类型(这里可以用XJad来查看 泛型什么时候起作用? )

类里的类型
在这里插入图片描述
使用Xjad查看发现泛型被擦除,编译阶段语法拦截

在这里插入图片描述

ArrayList 是Object数组的原因
在这里插入图片描述

通过构造参数来进行初始化,根据你显示几个参数来进行构造
在这里插入图片描述
默认构造我们会发现有一个 EMPTY_ELEMENTDATA 默认的大小
在这里插入图片描述

默认的大小在下图,默认的值是 10;
ArrayList 默认初始化的数值是10,当然可以进行扩容,下面详解
在这里插入图片描述

size是有效位数
elementData搭的数组长度大概是10
在这里插入图片描述

‘’
看源码太蒙,咋们上代码!
在这里插入图片描述
在这里插入图片描述
源码

public class ArrayListTest {
	//集合底层的数组
    private Object[] elementData;  
    //集合的有效数位---size
    private int size;   //有效数位帮你记录当前值的个数 
    private static final int DEFAULT_CAPACITY = 10;   //elementData的长度,长度是固定的   
    public ArrayListTest() {
    	elementData = new Object[DEFAULT_CAPACITY];    //创建了一个底层的数组
    }    
    public ArrayListTest(int capacity) {
    elementData = new Object[capacity];
    }	
    public void add(Object obj) {
    	elementData[size++] = obj;   
    }    
//改写
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for(int i = 0; i < size; i++) {
        	sb.append(elementData[i] + ",");    
        }
        sb.setCharAt(sb.length() - 1, ']');//拿到StringBuilder最后一个元素 替换成]
        return sb.toString();        
    }
	public static void main(String[] args) { 
		ArrayListTest arr = new ArrayListTest();
		arr.add("aa");
    	arr.add("bb");
    	arr.add("cc");
    	arr.add("dd");
    	System.out.println(arr);  //"[aa, bb, cc ,dd]"对他进行一个改写	
	}
}

下面是咋们改造的泛型 咋们要在哪里加泛型呢?在源码的基础上
也就是类名旁边,注解的四个值

  四个值
	   value = v;
       next = n;
       key = k;
       hash = h;

在这里插入图片描述
上图的类名一加泛型 下面就开始报黄色警告!!在这里插入图片描述
那add添加方法咋们也要改掉啊 因为里面是Object类型

改前
在这里插入图片描述
改后

在这里插入图片描述

改造泛型以后 ,提示黄色报错但是不会影响
添加 泛型以后 就不能添加int其他的数据类型了 ,(基本数据类型不能作为泛型例如int)
在这里插入图片描述
只能规定是String类型 ,这就是泛型的最重要的一个作用,规定以后就约束了类型
在这里插入图片描述

   new 	Object[DEFAULT_CAPACITY] = 10;
    在我们操作集合的时候你会发现	没有这个限制 (可以添加任意个数20 25 ,
    这就跟底层默认10矛盾了   所以咋们要在基础之上做文章----扩容
    如果超过上限  我们就做一个新的数组   把原来的数组地址指向 这个被扩大的新数组

扩容前

(我这里是扩容了 1倍)
在这里插入图片描述
如果没有扩容的话,数组溢出咋们看看运行结果 ,先注解掉上面的扩容代码。
运行炸了 !!!
在这里插入图片描述

扩容以后

运行成功! 是不是秒懂了!!

在这里插入图片描述

数组扩容一倍 变成了 20 这里的有效数位是13! 数组20
在这里插入图片描述

添加的值没有超过上限,这里的有效数位是3! 数组10
在这里插入图片描述

扩容了以后数组没有超过上限的话,默认10,超过上限,就会自己复制新你规定的数组位数

然后底层是默认了大小10的,你想一下如果随便给个-10是不是就报错了
在这里插入图片描述 所以咋们得想个办法 做个判断 异常提示

所以咋们在构造方法中要做一个判断!
这个值就自己在main方法测试就ok啦!
在这里插入图片描述

然后下面是通过指定下标 获得指定元素
在这里插入图片描述
下标异常报错
在这里插入图片描述
获取指定的元素
在这里插入图片描述

源码:

package com.JH.demo;

import java.util.ArrayList;
import java.util.Arrays;

import javax.management.RuntimeErrorException;

//集合里面都是元素T--类型   K---键   V---值   E----元素
public class ArrayListTest<E> {
	//集合底层的数组
    private Object[] elementData;  
    //集合的有效数位---size
    private int size;   //有效数位帮你记录当前值的个数 
    private static final int DEFAULT_CAPACITY = 10;   //elementData的长度,长度是固定的   
    public ArrayListTest() {
    	elementData = new Object[DEFAULT_CAPACITY];    //创建了一个底层的数组
    } 
    //new 	Object[DEFAULT_CAPACITY] = 10;
    //在我们操作集合的时候你会发现	没有这个限制 (可以添加任意个数20 25 ,这就跟底层默认10矛盾了   所以咋们要在基础之上做文章----扩容
    //如果超过上限  我们就做一个新的数组   把原来的数组地址指向 这个被扩大的新数组
    public ArrayListTest(int capacity) {
    	if(capacity<0){
    		throw new RuntimeException("数组不能是负值");
    	}else if(capacity==0){
    	   	elementData = new Object[DEFAULT_CAPACITY];  //
    		
    	}else{
    	    elementData = new Object[capacity];	//	如果没有上面二种 方法 ,就默认自己创建
    	}  
    }	
    public void add(E element) {
    	//什么时候扩容
    	//有效数位==数组的长度立刻进行扩容	
    	if(size==elementData.length){
    		//扩容    copyOf复制
    		elementData=Arrays.copyOf(elementData, elementData.length*2);
    	}	
    	elementData[size++] = element;   
    }    
    
    
    /**
     * 获得某个元素
     *  index
     * @param index
     * @return
     */
    //根据传入的下标获取某个元素
    public E get(int index){
    	range(index);
    	return(E) elementData[index]; 	
    }
    /**
     * 下标异常检查
     * @param index
     */
    
    public void range(int index){    	
       	if(index <0 || index > size-1){
    		throw new RuntimeException("数组下标越界异常  "+index+","+size);
    	}
    }   
//改写
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for(int i = 0; i < size; i++) {
        	sb.append(elementData[i] + ",");    
        }
        sb.setCharAt(sb.length() - 1, ']');//拿到StringBuilder最后一个元素 替换成]
        return sb.toString();        
    }
	public static void main(String[] args) { 
	
		//构造方法中要做一个判断d测试!
//		ArrayListTest arr1 = new ArrayListTest<>(-10);
//		System.out.println(arr1);
		
		ArrayListTest<String> arr = new ArrayListTest<String>();
		arr.add("aa");
    	arr.add("bb");
    	arr.add("cc");	
    	System.out.println(arr);
    	//有效数位
    	System.out.println(arr.size);  //"[aa, bb, cc ,dd]"对他进行一个改写	
    	//扩容一倍以后
    	System.out.println(arr.elementData.length);
    	
    	String ar=arr.get(2);
    	System.out.println(ar);
	}
}

在这里插入图片描述

ArrayList相关的一部分方法!详解 绝对干货!

public ArrayList()   
构造一个初始容量为10的空列表。
public ArrayList(Collection<? extends E> c) 
构造一个包含指定集合元素的列表,其顺序由集合的迭代器返回。


public int size()
返回此列表中的元素数。
public boolean isEmpty()
如果此列表不包含任何元素,则返回truepublic int indexOf(Object o)
返回指定元素在此列表中首次出现的索引;如果此列表不包含该元素,则返回-1。更正式地,
返回最低索引i,使 (o == null?get(i)== null:o.equals(get(i)));如果没有这样的索引,
则返回-1public int lastIndexOf(Object o)
返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1。更正式地,
返回最高索引i,使 (o == null?get(i)== null:o.equals(get(i)));如果没有这样的索引,
则返回-1public Object[] toArray()
以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。
返回的数组将是“安全的”,因为此列表不保留对其的引用。(换句话说,此方法必须分配一个新数组)。
因此,调用者可以自由修改返回的数组。

此方法充当基于数组的API和基于集合的API之间的桥梁。
public <T> T[] toArray(T[] a)
返回一个数组,该数组按适当顺序(从第一个元素到最后一个元素)包含此列表中的所有元素;
返回数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则将其返回。否则,
将使用指定数组的运行时类型和此列表的大小分配一个新数组。
如果列表适合指定的数组并有剩余空间(即,数组中的元素多于列表),
则紧接集合结束后的数组中的元素设置为 null。(仅当调用者知道列表不包含任何null元素时,这才对确定列表的长度很有用。)

public E get(int index)
返回此列表中指定位置的元素。
public E set(int index,E element)
用指定的元素替换此列表中指定位置的元素。


public boolean add(E e)
将指定的元素追加到此列表的末尾。

public void add(int index, E element)
将指定的元素插入此列表中的指定位置。将当前在该位置的元素(如果有)和任何后续元素右移(将其索引加一)。

public E remove(int index)
删除此列表中指定位置的元素。将所有后续元素向左移动(从其索引中减去一个)。
public boolean remove(Object o)
如果存在指定元素,则从该列表中删除该元素的第一次出现。如果列表不包含该元素,则该元素不变。
更正式地讲,删除索引i最低的元素, 使得 (o == null?get(i)== null:o.equals(get(i)))
如果存在这样的元素)。如果此列表包含指定的元素(或者等效地,如果此列表由于调用而更改),则返回truepublic boolean removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有其元素。

public void clear()
从此列表中删除所有元素。该调用返回后,该列表将为空。


public Iterator<E> iterator()
以适当的顺序返回对该列表中的元素的迭代器。
返回的迭代器是快速失败的。





在这里插入图片描述
在这里插入图片描述

发布了17 篇原创文章 · 获赞 0 · 访问量 483

猜你喜欢

转载自blog.csdn.net/sqL520lT/article/details/105309734