视频链接:https://www.bilibili.com/video/BV1Rx411876f?p=1
视频范围P660 - P693
目录描述
- 1.集合概述
- 2.Collection和terator
- 3.List接口
- 4.泛型机制
- 5.foreach
1.集合概述
- 数组其实就是一个集合
- 集合实际上就是一个容器,是一个载体,可以来容纳其它类型的数据(可以一次容纳多个对象)
举例:在实际开发中,假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。 - 集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址(或者说集合中存储的是引用)
list.add(100);//自动装箱Integer
//注意:集合在java中本身是一个容器,是一个对象
//集合中任何时候存储的都是“引用”
4. 在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到了不同的数据结构(数据存储的结构)当中。
注意:不同的数据结构,数据存储的方式不同,例如:数组、二叉树、链表、哈希表等等
//使用不同的集合等于使用了不同的数据结构
new ArrayList();//创建一个集合,底层是数组
new LinkedList();//创建一个集合,底层是链表
new TreeSet();//创建一个集合,底层是二叉树
- 集合在java JDK中java.util.;包下【所有的集合类和集合接口都在java.util.;包下】
- java中集合分为两大类:
集合 | 备注 |
---|---|
单个方式存储元素 | 这一类集合中超级父接口: java.util.Collection; |
以键值对的方式存储元素 | 这一类集合中超级父接口: java.util.Map; |
- 集合的继承结构图
- Map集合的继承结构图
- 总结
实现类 | 备注 |
---|---|
ArrayList | 底层是数组 |
LinkedList | 底层是双向链表 |
Vector | 底层是数组,线程安全的,效率较低,使用较少 |
HashSet | 底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了 |
TreeSet | 底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了 |
HashMap | 底层是哈希表 |
Hashtable | 底层也是哈希表,只不过线程安全的,效率较低,使用较少 |
Properties | 是线程安全的,并且key和value只能存储字符串String |
TreeMap | 底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序 |
List集合存储元素的特点:
- 有序可重复
- 有序:存进去的顺序和取出的顺序相同,每一个元素都有下标
- 可重复:存进去1,可以再存储一个1
Set(Map)集合存储元素的特点:
- 无序不可重复
- 无序:存进去的顺序和取出的顺序不一定相同,另外Set集合中元素没有下标
- 不可重复:存进去1,不能再存储1了
SortedSet(SortedMap)集合存储元素特点:
- 首先是无序不可重复的,但是SortedSet集合中的元素是可排序的
- 无序:存进去的顺序和取出的顺序不一定相同,另外Set集合中元素没有下标
- 不可重复,存进去1,不能再存储1了
- 可排序:可以按照大小顺序排列
注意: Map集合的key,就是一个Set集合,往Set集合中放数据,实际上放到了Map集合的key部分
2.Collection和terator
2.1 Collection接口中常用的方法
- 没有使用“泛型”之前Collection中可以存储Object的所有子类型
- 使用“泛型”之后Collection中只能存储O某个具体的类型
方法 | 作用 |
---|---|
boolean add(Object e) | 向集合中添加元素 |
int size() | 获取集合中元素的个数 |
void clear() | 清空集合 |
boolean contains(Object o) | 判断当前集合中是否包含元素o,包含返回true,不包含返回false |
boolean remove(Object o) | 删除集合中的某个元素 |
boolean isEmpty() | 判断该集合中元素的个数是否为0 |
Object[ ] toArray() | 把集合转换为数组 |
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
public class CollecticeTest01 {
public static void main(String[] args) {
//创建一个集合对象
//Collection c = new Collection;//接口是抽象的,无法实例化
//多态
Collection c = new ArrayList();
//测试Collection接口中的常用方法
c.add(1200);//自动装箱(java5的新特性),实际上是放进去了一个对象的内存地址
//如:Integer x = new Integer(1200);
c.add(3.14);//自动装箱
c.add(new Object());
c.add(new Student());
c.add(true);//自动装箱
//获取集合中元素的个数
System.out.println("集合中元素个数是:" + c.size());//输出为:集合中元素个数是:5
//清空集合
c.clear();
System.out.println("集合中元素个数是:" + c.size());//输出为:集合中元素个数是:0
//再向集合中添加元素
c.add("hello");
c.add("world");
c.add("浩克");
c.add("绿巨人");
//判断集合中是否包含 绿巨人
boolean flag = c.contains("绿巨人");
System.out.println(flag);//输出为:true
//删除集合中某个元素
c.remove("绿巨人");
System.out.println("集合中元素个数是:" + c.size());//输出为:集合中元素个数是:3
//判断集合中是否为空(集合中是否存在元素)
System.out.println(c.isEmpty());//输出为:false
//转换成数组
Object[] objs = c.toArray();
for (int i = 0; i < objs.length; i++) {
//遍历数组
Object o = objs[i];
System.out.println(o);
}
}
}
class Student{
}
2.2 集合遍历/迭代专题一
以下讲解的遍历方式/迭代方式,是所有Collection通用的一种方式,在Map集合中不能用,在所有的Collection以及子类中使用
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollecticeTest02 {
public static void main(String[] args) {
//创建集合对象
//后面的集合无所谓,主要看前面的Collection接口,怎么遍历/迭代
Collection c = new ArrayList();
//添加元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
//对集合Collection遍历/迭代
//第一步:获取集合对象的迭代器对象Iterator
Iterator it = c.iterator();
//第二步:通过以上获取的迭代器对象开始迭代/遍历集合
/*
以下两个方法是迭代器对Iterator中的方法:
boolean hasNext()如果仍有元素可以迭代,则返回true
Object next()返回迭代的下一个元素
*/
while (it.hasNext()){
Object obj = it.next();
System.out.println(obj);
}
}
}
运行结果:
内存分析图:
2.3 集合遍历/迭代专题二
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class CollecticeTest03 {
public static void main(String[] args) {
//创建集合对象
Collection c1 = new ArrayList();//ArrayList集合:有序可重复
//添加元素
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
c1.add(5);
//迭代集合
Iterator it = c1.iterator();
while (it.hasNext()){
//存进去是什么类型,取出来还是什么类型
Object obj = it.next();
if(obj instanceof Integer){
System.out.println("Integer类型");
}
//只不过在输出的时候会转换成字符串,因为这里的println会调用toString()方法
System.out.println(obj);
}
//HashSet集合:无序不可重复
//无序:存进去和取出的顺序不一定相同
//不可重复:存储100,不能再存储100
Collection c2 = new HashSet();
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(100);
Iterator it2 = c2.iterator();
while (it2.hasNext()){
System.out.println(it2.next());
}
}
}
运行结果:
2.4 contains方法解析
boolean contains(Object o) :判断当前集合中是否包含元素o,包含返回true,不包含返回false
contains方法是用来判断集合中是否包含某个元素的方法,底层判断集合中是否包含某个元素:
- 调用equals方法进行比对;
- equals方法返回true,就表示包含这个元素
,代码实例一:
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
public class CollecticeTest04 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//向集合中存储元素
String s1 = new String("abc");
c.add(s1);
String s2 = new String("def");
c.add(s2);
//集合中元素的个数
System.out.println("元素的个数为:" + c.size());//输出为:元素的个数为:2
//新建的对象String
String x = new String("abc");
//c集合中是否x?
System.out.println(c.contains(x));//输出为:true
}
}
内存分析图:
,代码实例二:
存放在一个集合中的类型,一定要重写equals方法
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
public class CollecticeTest05 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//创建用户对象
User u1 = new User("jack");
//加入集合
c.add(u1);
//判断集合中是否包含u2
User u2 = new User("jack");
//没有重写equals之前:这个结果是false
//System.out.println(c.contains(u2));//输出为:false
//重写equals之后:这个结果是true
System.out.println(c.contains(u2));//输出为:true
}
}
class User{
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
//重写equals方法
//将来调用equals方法的时候,一定是调用这个重写的equals方法
public boolean equals(Object o) {
if (o == null || !(o instanceof User)) return false;
if (o == this) return true;
User u = (User)o;
//如果名字一样表示同一个人(不再比较对象的内存地址了,比较内容)
return u.name.equals(this.name);
}
}
2.5 remove方法解析
代码实例一:
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
public class CollecticeTest06 {
public static void main(String[] args) {
//创建集合对象
Collection cc = new ArrayList();
//创建字符串对象
String s1 = new String("hello");
//加进去
cc.add(s1);
//创建一个新的字符串对象
String s2 = new String("hello");
//删除s2
cc.remove(s2);
//集合中元素个数
System.out.println(cc.size());//输出为:0
}
}
代码实例二:
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollecticeTest07 {
public static void main(String[] args) {
//创建集合
Collection c = new ArrayList();
//添加元素
c.add(1); //Integer类型
c.add(2);
c.add(3);
//获取迭代器
Iterator it = c.iterator();
while (it.hasNext()){
//编写代码时next()方法返回值类型必须是object
Object obj = it.next();
System.out.println(obj);
}
}
}
运行结果:
代码实例三:
重点:当集合的结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器,会出现异常:java.util.ConcurrentModificationException
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollecticeTest07 {
public static void main(String[] args) {
//创建集合
Collection c = new ArrayList();
//注意:此时获取的迭代器,指向的是那是集合中没有元素状态下的迭代器
//一定要注意:集合结构只要发生改变,迭代器必须重新获取
//当集合结构发生了改变,迭代器没有重新获取时
//调用next()方法时:java.util.ConcurrentModificationException
Iterator it = c.iterator();
//添加元素
c.add(1); //Integer类型
c.add(2);
c.add(3);
//获取迭代器
//Iterator it = c.iterator();
while (it.hasNext()){
//编写代码时next()方法返回值类型必须是object
Object obj = it.next();
System.out.println(obj);
}
}
}
运行结果:
代码实例四:
重点:在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素会出现:java.util.ConcurrentModificationException
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollecticeTest07 {
public static void main(String[] args) {
//创建集合
Collection c = new ArrayList();
//添加元素
c.add(1); //Integer类型
c.add(2);
c.add(3);
//获取迭代器
Iterator it = c.iterator();
while (it.hasNext()){
Object obj = it.next();
//删除元素
//删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
//但是,循环下一次的时候并没有重新获取迭代器
//所以会出现异常:java.util.ConcurrentModificationException
//出异常根本原因:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化了)
//直接通过集合去删除元素,没有通知迭代器(导致迭代器的快照和原集合快照不同)
c.remove(obj);
System.out.println(obj);
}
}
}
运行结果:
代码实例五:
重点:在迭代元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素,不要使用集合自带的remove方法删除元素
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollecticeTest07 {
public static void main(String[] args) {
//创建集合
Collection c = new ArrayList();
//添加元素
c.add(1); //Integer类型
c.add(2);
c.add(3);
//获取迭代器
Iterator it = c.iterator();
while (it.hasNext()){
Object obj = it.next();
//使用迭代器删除,删除的一定是迭代器指向的当前元素
//迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)
it.remove();
System.out.println(obj);
}
System.out.println(c.size());//输出为:0
}
}
运行结果:
3.List接口
3.1 List接口方法
- List集合存储元素特点:有序可重复
有序:List集合中的元素有下标。从0开始,以1递增
可重复:存储一个1,还可以再存储1 - List接口自己特色方法:
特色方法 |
---|
void add(int index,Object element) |
Object get(int index) |
int indexOf(Object o) |
int LastIndexOf(Object o) |
Object remove(int index) |
Object set(int index ,Object element) |
3.1.1 void add(int index,Object element)
这个方法使用不多,因为对于ArrayList集合来说效率比较低
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");//默认都向集合末尾添加元素
mylist.add("B");
mylist.add("C");
mylist.add("D");
//在列表的指定位置插入指定元素(第一个参数是下标)
//这个方法使用不多,因为对于ArrayList集合来说效率比较低
mylist.add(1,"king");
//迭代
Iterator it = mylist.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
3.1.2 Object get(int index)
根据下标获取元素
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");
mylist.add("B");
mylist.add("C");
mylist.add("D");
//根据下标获取元素
Object firstObj = mylist.get(0);
System.out.println(firstObj);//输出为:A
//因为有下标,所以list集合有自己比较特殊的遍历方法
//通过下标遍历【list集合特有的方式,Set没有】
for (int i = 0; i < mylist.size(); i++) {
Object obj = mylist.get(i);
System.out.println(obj);
}
}
}
3.1.3 int indexOf(Object o)
获取指定对象第一次出现处的索引
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");
mylist.add("B");
mylist.add("C");
mylist.add("D");
//获取指定对象第一次出现处的索引
System.out.println(mylist.indexOf("B"));//输出为:1
}
}
3.1.4 int LastIndexOf(Object o)
获取指定对象最后一次出现处的索引
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");
mylist.add("B");
mylist.add("C");
mylist.add("C");
mylist.add("D");
//获取指定对象最后一次出现处的索引
System.out.println(mylist.lastIndexOf("C"));//输出为:3
}
}
3.1.5 Object remove(int index)
删除指定下标位置的元素
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");
mylist.add("B");
mylist.add("C");
mylist.add("D");
//删除指定下标位置的元素
//删除下标为0的元素
mylist.remove(0);
System.out.println(mylist.get(0));//输出为:B
}
}
3.1.6 Object set(int index ,Object element)
package Collectice;
import java.util.*;
public class ListTest01 {
public static void main(String[] args) {
//创建list类型的集合
//List mylist = new LinkedList();
//List mylist = new Vector();
List mylist = new ArrayList();
//添加元素
mylist.add("A");
mylist.add("B");
mylist.add("C");
mylist.add("D");
//修改指定位置的元素
mylist.set(0,"F");
System.out.println(mylist.get(0));//输出为:F
}
}
3.2 ArrayList
- ArrayList集合初始化容量是10【底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10】
- ArrayList集合底层是Obeject类型的数组Object[ ]
- 构造方法:new ArrayList()或者new ArrayList(20)
package Collectice;
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest01 {
public static void main(String[] args) {
//默认初始化容量是10
//数组的长度是10
List list1 = new ArrayList();
//集合的size()方法是获取当前集合中元素的个数,不是获取集合的容量
System.out.println(list1.size());//输出为:0
//默认初始化容量是20
//数组的长度是20
List list2 = new ArrayList(20);
System.out.println(list2.size());//输出为:0
}
}
- ArrayList集合的扩容:增长到原容量的1.5倍
ArrayList集合底层是数组
优化方式:尽可能少的扩容,因为数组扩容效率比较低,建议在使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量 - 数组优点:检索效率比较高【每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高。】;向数组末尾添加元素,效率很高,不受影响
数组缺点:随机增删元素效率比较低;数组无法存储大数据量【很难找到一块非常巨大的连续的内存空间】 - 面试问题:这么多的集合中,哪个集合用的最多?
答:ArrayList集合,因为往数组末尾添加元素,效率不受影响,另外,检索/查找某个元素的操作比较多 - ArrayList集合是非线程安全的(不是线程安全的集合)
3.2.1 位运算符
package Collectice;
public class BinaryTest {
public static void main(String[] args) {
// >> 1 二进制右移1位
// >> 2 二进制右移2位
//10的二进制位是:00001010 【10】
//10的二进制右移1位是:00000101 【5】
System.out.println(10 >> 1);//输出为:5
//二进制左移1位
//10的二进制位是:00001010 【10】
//10的二进制左移1位是:00010100 【20】
System.out.println(10 << 1);//输出为:20
}
}
3.2.2 ArrayList构造方法
package Collectice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class ArrayListTest02 {
public static void main(String[] args) {
//默认初始化容量10
List myList1 = new ArrayList();
//指定初始化容量100
List myList2 = new ArrayList(100);
//创建了HashSet集合
Collection c = new HashSet();
//添加元素到set集合
c.add(100);
c.add(200);
c.add(900);
c.add(500);
//通过这个构造方法就可以将HashSet集合转换成List集合
List myList3 = new ArrayList(c);
for (int i = 0; i < myList3.size(); i++) {
System.out.println(myList3.get(i));
}
}
}
运行结果:
3.3 LinkedList
- LinkedList集合是双向链表(看源码)
- 对于链表数据结构来说,随机增删效率较高,检索效率较低
- 链表中的元素在空间存储上,内存地址不连续
3.3.1 单向链表结构
链表优缺点 | 备注 |
---|---|
优点 | 由于链表上的元素在空间存储上内存地址不连续。所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。 |
缺点 | 不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率较低。 |
ArrayList:把检索发挥到极致(末尾添加元素效率还是很高的)
LinkedList:把随机增删发挥搭配极致
加元素都是往末尾添加,所以ArrayList用的比LinkedList多
单链表中的节点:
节点是单向链表中基本的单元,每一个节点Node都有两个属性:
- 属性1:是存储的数据
- 属性2:是下一个节点的内存地址
package danlink;
public class Node {
//存储的数据
Object element;
//下一个节点的内存地址
Node next;
public Node() {
}
public Node(Object element, Node next) {
this.element = element;
this.next = next;
}
}
链表:
package danlink;
public class Link {
//头节点
Node header;
int size = 0;
public int size(){
return size;
}
//向链表中添加元素的方法(向某尾部添加)
public void add(Object data) {
//创建一个新的节点对象
//让之前的单链表的某尾节点next指向新节点对象
//有可能这个元素是第一个,也可能是第二个
if (header == null){
//说明还没有节点
//new一个新的节点对象,作为头节点对象
//这个时候的头节点既是一个头节点,又是一个末尾节点
header = new Node(data,null);
}else {
//说明头不是空,头节点已有
//找出当前某尾节点,让当前末尾节点的next是新节点
Node currentLastNode = findLast(header);
currentLastNode.next = new Node(data,null);
}
size++;
}
/**
* 专门查找末尾节点的方法
* @param
* @return
*/
private Node findLast(Node node) {
if (node.next == null){
//如果一个节点的next是null
//说明这个节点就是末尾节点
return node;
}
//程序能够到这里说明:node不是末尾节点
return findLast(node.next);//递归算法!
}
//删除链表中某个数据的方法
public void remove(Object obj) {
}
//修改链表中某个数据的方法
public void modify(Object newObj) {
}
public int find(Object obj) {
return 1;
}
}
测试类:
package danlink;
public class Test {
public static void main(String[] args) {
//创建了一个集合对象
Link link = new Link();
//往集合中添加元素
link.add(100);
link.add(200);
link.add(300);
link.add(400);
//获取元素个数
System.out.println(link.size());//输出为:4
}
}
注意:
- LinkedList集合底层也是有下标的
- ArrayList之所以检索效率比较高,不是单纯因为下标的原因,是因为底层数组发挥的作用
- LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点开始一个一个遍历
3.3.2 双向链表结构
内存演示图:
package danlink;
public class Test {
public static void main(String[] args) {
//创建了一个集合对象
List list = new LinkedList();
//往集合中添加元素
list.add("a");
list.add("b");
list.add("c");
//获取元素个数
for(int i = 0;i < list.size();i++){
Object obj = list.get(i);
System.out.println(obj);
}
}
}
内存演示图:
方法执行后内存释放:
注意:LinkedList集合没有容量初始化;最初这个链表中没有任何元素,first和last引用都是null;
3.4 Vector
- 底层也是一个数组
- 初始化容量:10
- 扩容之后是原容量的2倍:10–>20–>40–>80
ArrayList集合扩容特点:10–>15–>15*1.5 - Vector中所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的,效率比较低,使用较少了。
- 将一个线程不安全的ArrayList集合转换成线程安全的:
使用集合工具类:java.util.Collections;
注意:
java.util.Collection 是集合接口
java.util.Collections 是集合工具类
import java.util.*;
public class VectorTest {
public static void main(String[] args) {
//创建一个Vector集合
Vector vector = new Vector();
//添加元素
//默认容量10个
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
vector.add(6);
vector.add(7);
vector.add(8);
vector.add(9);
vector.add(10);
//满了之后扩容
vector.add(11);
Iterator it = vector.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//以后使用
List myList = new ArrayList();//非线程安全的
//变成线程安全的
Collections.synchronizedList(myList);//学会多线程后可看效果
//myList集合就是线程安全的
myList.add("111");
myList.add("222");
myList.add("333");
}
}
4.泛型机制
- JDK5.0之后推出的新特性:泛型
- 泛型这种语法机制,只在程序编译阶段起作用,只是给编译器参考的(运行阶段泛型没用!)
- 泛型好处:
第一:集合中存储的元素类型统一了
第二:从集合中取出的元素类型是泛型指定的类型,不需要进行大量的“向下转型”! - 泛型缺点:导致集合中存储的元素缺乏多样性!
- 大多数业务中,集合中元素的类型还是统一的,所以这种泛型特性被大家所认可
4.1 不使用泛型
package Collectice;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest01 {
public static void main(String[] args) {
//不使用泛型机制,分析程序存在缺点
//创建集合
List myList = new ArrayList();
//准备对象
Cat c = new Cat();
Bird b = new Bird();
//将对象添加到集合当中
myList.add(c);
myList.add(b);
//遍历集合,取出每个Animal,让它move
Iterator it = myList.iterator();
while (it.hasNext()){
//没有这个语法,通过迭代器取出的就是Object
//Animal a = it.next();
Object obj = it.next();
//obj中没有move方法,无法调用,需要向下转型!、
if (obj instanceof Animal){
Animal a = (Animal) obj;
a.move();
}
}
}
}
class Animal{
//父类自带方法
public void move(){
System.out.println("动物在移动!");
}
}
class Cat extends Animal{
//特有方法
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animal{
//特有方法
public void fly(){
System.out.println("鸟儿在飞翔!");
}
}
运行结果:
4.2 使用泛型
package Collectice;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest02 {
public static void main(String[] args) {
//使用JDK5之后的泛型机制
//使用泛型List<Animal>之后,表示List集合只运行存储Animal类型的数据
//用泛型来指定集合中存储的数据类型
List<Animal> myList = new ArrayList<Animal>();
//指定List集合中只能存储Animal,那么存储String就编译报错了
//这样用了泛型之后,集合中元素的数据类型更加统一了
//myList.add("abc");
//准备对象
Cat c = new Cat();
Bird b = new Bird();
myList.add(c);
myList.add(b);
//获取迭代器
//这个表示迭代器迭代的是Animal类型
Iterator<Animal> it = myList.iterator();
while (it.hasNext()){
//使用泛型之后,每一次迭代返回的数据都是Animal类型
Animal a = it.next();
//这里不需要进行强制类型转换了,直接调用
a.move();
//调用子类型特有的方法还说需要向下转型的
Animal e = it.next();
if (e instanceof Cat){
Cat x = (Cat) e;
x.catchMouse();
}
if (e instanceof Bird){
Bird y = (Bird) e;
y.fly();
}
}
}
}
class Animal{
//父类自带方法
public void move(){
System.out.println("动物在移动!");
}
}
class Cat extends Animal{
//特有方法
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animal{
//特有方法
public void fly(){
System.out.println("鸟儿在飞翔!");
}
}
4.3 自动类型推断机制(钻石表达式)
package Collectice;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest03 {
public static void main(String[] args) {
//ArrayList<这里的类型会自动推断>() 前提是JDK8之后才允许的
//自动类型推断,钻石表达式!
List<Animal> myList = new ArrayList<>();
myList.add(new Animal());
myList.add(new Cat());
myList.add(new Bird());
//遍历
Iterator<Animal> it = myList.iterator();
while (it.hasNext()){
Animal a = it.next();
a.move();
}
}
}
class Animal{
//父类自带方法
public void move(){
System.out.println("动物在移动!");
}
}
class Cat extends Animal{
//特有方法
public void catchMouse(){
System.out.println("猫抓老鼠!");
}
}
class Bird extends Animal{
//特有方法
public void fly(){
System.out.println("鸟儿在飞翔!");
}
}
4.4 自定义泛型
- 自定义泛型的时候,<>尖括号中的是一个标识符,随便写
- 用泛型就被固定了,不用泛型就是Object类型
- java源代码中经常出现的是:< E >和< T >
E是Element单词首字母;T是Type单词首字母
package Collectice;
public class GenericTest04 <标识符随便写>{
public void doSome(标识符随便写 o){
System.out.println(o);
}
public static void main(String[] args) {
//new对象的时候指定了泛型是:String类型
GenericTest04<String> gt = new GenericTest04<>();
//类型不匹配
//gt.doSome(100);
gt.doSome("abc");
}
}
5.foreach
- JDK5.0之后推出了一个新特性:叫做增强for循环,或者叫做foreach
- 语法格式:
for(元素类型 变量名 : 数组或集合){
System.out.println(变量名);
}
- foreach缺点:没有下标
- 在需要使用下标的循环中,不建议使用增强for循环
5.1 foreach正常案例
package Collectice;
public class ForEachTest01 {
public static void main(String[] args) {
//int类型数组
int[] arr = {432,4,65,45,76,11,2};
//遍历数组(普通for循环)
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("========================");
//foreach方法
for (int data : arr) {
//data就是数组中的元素(数组中的每一个元素)
System.out.println(data);
}
}
}
运行结果:
5.2 foreach在集合中的使用
package Collectice;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ForEachTest02 {
public static void main(String[] args) {
//创建List集合
List<String> strList = new ArrayList<>();
//添加元素
strList.add("hello!");
strList.add("world!");
strList.add("kitty!");
//遍历,使用迭代器方式
Iterator<String> it = strList.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
//使用下标方式(只针对于有下标的集合)
for (int i = 0; i < strList.size(); i++) {
System.out.println(strList.get(i));
}
//使用foreach
for(String s : strList){//因为泛型使用的是String类型,所以是:String s
System.out.println(s);
}
}
}