有干货!
建立了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()
如果此列表不包含任何元素,则返回true。
public int indexOf(Object o)
返回指定元素在此列表中首次出现的索引;如果此列表不包含该元素,则返回-1。更正式地,
返回最低索引i,使 (o == null?get(i)== null:o.equals(get(i)));如果没有这样的索引,
则返回-1。
public int lastIndexOf(Object o)
返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1。更正式地,
返回最高索引i,使 (o == null?get(i)== null:o.equals(get(i)));如果没有这样的索引,
则返回-1。
public 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)))
如果存在这样的元素)。如果此列表包含指定的元素(或者等效地,如果此列表由于调用而更改),则返回true。
public boolean removeAll(Collection<?> c)
从此列表中删除指定集合中包含的所有其元素。
public void clear()
从此列表中删除所有元素。该调用返回后,该列表将为空。
public Iterator<E> iterator()
以适当的顺序返回对该列表中的元素的迭代器。
返回的迭代器是快速失败的。