一、泛型Generics
JDK1.5之后出现的。
1.概念:广泛的类型——>声明要存储的类型是什么。
2.作用:存入到容器中的元素,Object类型(向上转型)。当获取的时候,需要手动的向下转型,降低效率,容易出错。
3.使用:在创建集合的时候,使用泛型来指明该容器中,能够存储的数据类型。
4.目的:指定集合中存储的元素的数据类型,保护容器中的数据的类型的安全。
String-->Object
Integer-->Object
Person-->Object
String-->String
Integer-->Integer
Person-->Person
5.语法:
容器<数据类型> 容器对象 = new 容器<>();
例如:Collection<String> c2 = new ArrayList<>();
Collection<Person> c4 = new ArrayList<>();
注意点:因为集合仅限于存储引用类型,所以声明泛型不能直接写基本数类型,需要写对应的包装类。
()-->方法
[]-->数组
{}-->....
<>-->泛型
5.2、泛型应用在类上。
声明一个类的时候使用<>,限制数据类型,泛型作用在类上。普通方法和普通的属性。属于对象的,可以直接使用该泛型。但是不能给静态用。因为作用在类上的泛型,当对象被创建的时候确定的。
class 类名<T>{
//T这个类型,当创建对象的时候决定好。
}
泛型擦除:如果创建对象的时候,没有指明泛型,那么该类型T——>Object类型。
5.3、泛型作用在静态方法上
方法的声明上使用泛型的声明<>。
类的静态方法如果使用泛型,需要单独进行泛型的声明,声明泛型要写在static关键字之后,返回值类型之前。
//3.<M>,静态方法上自己独立声明泛型,不能使用类的。
publicstatic<M>Mtest(Mm){
System.out.println(m);
returnm;
}
6、泛型的限定:集合中
?:代表了任意集合中可以存储任意类型,区分于Object
List<?>,List<Object>
List<?>指代可以存储任意泛型类型的集合
List<Object>集合中的对象,就是Object类型,其他类型的对象会自动转为Object类型。
?extends T:限定了上限
接收集合的泛型:中可以存储T,以及T的子类类型。
?super T:限定了下限
接收集合的泛型:可以是T,以及T的父类。
7、不允许使用泛型的地方
静态属性:private static T member;//错误的
创建T的实例:T t = new T();//错误
自定义异常,不能使用泛型
class MyException<T> extends Exception
8.数组的语法格式:
数据类型[] 数组名= new 数据类型[长度];
int[] arr = new int[5];
arr[0]-->int
Arrays.toString(arr);//--->数组的元素
集合对象直接打印,不显示集合的地址,直接显示集合中存储的元素。集合对象,都重写了toString();
二、迭代器Iterator
1.定义:集合是用来存储元素,存储的元素需要查看,那么就需要迭代(遍历)
演示遍历集合
2.迭代器使用:(接口类型)(属于Collection接口)
step1://先在要遍历的集合上,获取迭代器对象
c1.iterator();--->Iterator it
step2:判断迭代器对象之后是否有元素
it.hasNext();--->boolean
step3:获取该元素:
it.next();-->元素
实例代码:
Collection<String> c = new ArrayList();
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String s1 = it.next();
System.out.println(s1);
}
3.注意点:
(1、每次迭代获取(调用next())前,应该先判断是否有这个元素(hasNext()),如果有再获取,如果没有就不要获取,如果强行获取,就报错:java.util.NoSuchElementException
(2、一个迭代器对象,从头执行到最后就不能再次使用,因为后面没有元素,迭代不出来了。
(3、迭代器在工作期间,集合本身不要去更改集合的结构。但是迭代器对象自己可以删除。(功能慎用)
三、List接口(重点中重点!!!!!)
作为Collection接口的子接口,也是一种容器。但是有自己的独特的存储特点。
1、定义
List集合是有序的,可以储存重复的数据
List集合通过记录元素在集合中的位置来准确的查找元素
2、List集合体系
ArrayList 底层使用数组(线程不安全)
LinkedList 底层使用链表
Vector 底层使用数组(线程安全的,不推荐使用)
3、新增了自己特有的功能方法:都是和下标有关系的。
set(index,E)-->指定位置替换元素
get(index)-->E,获取指定位置的元素
add(index,E)-->指定位置添加元素
remove(index)-->根据位置进行删除
indexOf()-->int,搜索指定的元素,返回下标,如果没有就返回-1
subList(fromIndex,endIndex)-->List,截取子集合
遍历一个List接口中的所有元素:
for-each,增强for循环
Iterator,迭代器
普通的for循环,结合get()方法。
四、ArrayList实现类
作为List接口的实现类,将接口中的方法全部实现。
1、定义
底层:数组的结构来实现的。也会有人叫动态数组。(最大的特点:内存连续)
储存的元素是有序的,而且可以重复存储, 通过数组角标来查询更改元素,速度非常快
由于每次增删都要改动数组中的角标,所有导致增删效率低下
2、ArrayList的增删改查原理
ArrayList 集合初始化会有一个默认长度是10的数组, 内部还有一个记录当前元素个数的变量, 当储存的元素个数超过数组长度之后,容量就会扩充一半
当我们去查询集合中的元素时, 需要提供给集合一个角标值, 然后通过这个角标值查找集合中的元素
当我们去删除一个元素的时候, 集合就会根据角标删除这个元素,并且改动其他元素的位置,这就是导致增删缓慢的原因
其实如果我们是连续往集合尾部插入数据的话, 速度其实是非常快的, 因为其他元素的位置不需要改动,但是如果我们插入数据的位置是数组的前面或者中间,速度就会有明显的降低
3、构造方法
ArrayList() 构造一个初始化容量为10的空列表
ArrayList(Collection<? exends E> e) 构造一个包含执行集合元素的列表
ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表
4、常用方法
boolean add(E e) 将指定的元素添加到此列表的尾部
void add(int index,E element) 将指定的元素插入此列表中的指定位置
boolean contains(Object o) 如果此列表中包含指定的元素,则返回true
E get(int index) 通过角标查找元素
int indexOf(Object o) 返回此列表中首次出现的指定元素的索引, 或如果没有则返回 -1
int lastIndexOf(Object o) 返回此列表中最后一次出现的指定元素的索引(从后先前查)没有返回-1
E remove(int index) 移除此列标中指定位置上的元素
boolean remove(Object o) 移除此列表中首次出现的指定元素(如果存在)
E set(int index , E element) 用指定元素替代此列表中指定位置上的元素,返回原来的元素
int size() 返回此列表中的元素数
理解为ArrayList相当于一个可变长度的数组,访问遍历效率较高。增加,删除元素,效率较低。
JDK1.2的版本的类。
五、LinkedList实现类
LinkedList实现类,区别于ArrayList,除了实现List接口,还实现了Deque接口。
LinkedList实现类:
实现的接口:
List接口------------------------------------------------->Collection
Deque(双端队列)接口--->Queue(队列)接口--->Collection
queue:队列。排队,队列
deque:双端队列,全名:double-ended queue
模拟栈的结构:后进先出(LIFO),栈顶元素,
push(),压栈,入栈,pop(),弹栈,出栈
模拟队列的结构:先进先出(FIFO),队头元素
offer(),poll()
1、定义
底层实现:采用双向链表的结构实现
这个集合中的每个元素都被封装到一个叫Node的内部类中, 然后记录上一个元素和下一个元素的地址,通过手拉手形成一个链条
增删快, 查询慢
2、增删改查的原理
当需要去查询LinkedList集合中的元素时,需要从最开始的元素查找起,然后一层一层往后找,直到找到该元素,这样的动作十分消耗性能
当需要去删除元素的时候, 我们只需要将被删除元素两端的元素重新连接到一起,或者新增的时候将新元素和左右两边的元素连起来就可以了
3、构造方法
LinkedList() 构造一个空列表
LinkedList(Collection<? extends E> e) 构造一个包含指定collection中元素的列表
4、常用方法
E remove() 获取并移除此列表的头
E poll() 获取并移除此列表的头
E peek() 获取但不移除此列表的头
六、ArrayList, LinkedList 及Vector集合之间的区别
1、线程安全
Vector : 线程安全
ArrayList, LinkedList : 线程不安全
2、实现方式
LinkedList : 链表
ArrayList,Vector : 数组
3、扩容
ArrayList和Vector使用数组实现, 当数组长度不够,内部会创建一个更大的数组
LinkedList 不存在这方面的问题
4、速度
ArrayList 查改块, 增删慢
LinkedList 查改慢, 增删快
七、ArrayList和LinkedList总结
1.ArrayList 是有序插入 LlnkedList 是无序插入。
比较谁查找快: 要考虑数据量 和是否有无序插入
如顺序插入 如果是尾部添加, ArrayList反而更块
乱序插入 LlnkedList快
八、拓展1
数组结构:在内存中连续空间。存储的数据的组织特点。
线性表,链表,树。。。。
栈:Stack,这种数据结构的特点?
last In First Out,简称LIFO,后进先出。
队列:queue,
First in First out,简称FIFO,先进先出。
拓展2
Vector:向量
对比ArrayList,LinkedList,Vector实现类
A:ArrayList,底层采用数组结构的实现的。(内存中连续空间)。jdk1.2
只实现了List接口,功能都是List接口中规定的。
优缺点:
优点:遍历访问元素,效率很高
缺点:插入或删除元素,效率相对低。
B:LinkedList,底层采用双向链表结构实现的。(元素在内存中不挨着,元素之间的指向)。jdk1.2
实现了List接口的同时,还实现了Deque接口,所以有这两个接口中的功能。
优缺点:
优点:插入或删除元素,效率很高。
缺点:遍历访问元素,效率相对低。
注意点:
如果一个集合,频繁的添加或删除元素,建议选择LinkedList。
如果一个集合,绝大多数的操作就是遍历查询,建议选择ArrayList。
如果要模拟栈,队列等结构,建议选择LinkedList。
C:Vector,是ArrayList的前身。也是数组的结构。古老的类。从jdk1.0的版本就有了。
线程安全,效率低,后来被ArrayList替代了。
ArrayList和LinkedList都是线程不安全的,效率高。Collections工具类,可以获取线程安全的集合。