2.5集合
集合:容器,装类型不同的元素,没有个数限制(比数组好用)
数组:容器,装类型相同的元素,有个数限制
JCF:集合框架(Java collection framework)
1)Collection:单值类型的集合,每次往集合里面添加一个元素
List[有序,不唯一]
Set[无序,唯一]
SortedSet[有序,唯一]
2)Map:键值对类型的集合,每次往集合里面添加一对元素
SortedMap[]
场景一:图书馆管理系统 想要集合装哪一个学生借了拿一本书 -》Map
场景二:统计班级学生信息 按照分数降序排序 -》 SortedSet
场景三:大润发会员系统 需求统计每个会员信息 -》Set
场景四:去餐厅吃饭 每一桌点的菜需要拿着一个容器装 -》 List
面试题: List Set Map属于同一等级吗?
List,Set属于Collection的子接口
Map和Collection属于同一级别
List:接口
ArrayList
特点:有序,不唯一
数据结构:数组
作用一:
由于ArrayList底层基于Object[]实现的
所以所有的引用数据类型都可以存储在集合里面
但是基本数据类型不可以 为了保证基本数据类型
也可以装在集合里面 -》 包装类
引用数据类型-》集合
基本数据类型-》包装类-》集合
基本数据类型的包装类:
基本数据类型 | 包装类(引用类型,包装类都位于java.lang包下 无需导入) |
---|---|
boolean | Boolean |
char | Character【特殊】 |
byte | Byte) |
short | Short |
int | Integer 【特殊】 |
long | Long |
float | Float |
double | Double |
int x = 45;
//基本数据类型 -》 包装类
Integer y = Integer.valueOf(x);//jdk5.0之前
Integer y = x;//jdk5.0开始
Integer x = new Integer(77);
int y = x.intValue();//jdk5.0之前
int y = x;//jdk5.0开始
作用二:包装类里面提供一个方法 可以将字符串转换成对应的基本数据类型
String str = “45”;
int x = Integer.parseInt(str);
public class TestArrayList2{
public static void main(String[] args){
String str="张三:77 李四:82 王五:30";
String[] data=str.split(" ");
int sum=0;
for(int i=0;i<data.length;i++){
String[] temp=data[i].split(":");
int score=Integer.parseInt(temp[1]);
sum+=score;
}
System.out.println(sum);
//谁的成绩>平均分
int avg=sum/data.length;
for(String x:data){
String[] temp=x.split(":");
int score=Integer.parseInt(temp[1]);
if(score>avg){
System.out.println(temp[0]);
}
}
//班里最高分
int max=0;
String name="";
for(String x:data){
String[] temp=x.split(":");
int score=Integer.parseInt(temp[1]);
if(score>max){
max=score;
name=temp[0];
}
}
System.out.println(name+"最高分:"+max);
}
}
ArrayList基本用法集合特点:
1)如何创建集合:
(1)jdk5.0之前 默认装的都是Object类型的对象
ArrayList list = new ArrayList();
(2)jdk5.0开始 可以加泛型
ArrayList<泛型> list = new ArrayList<泛型>();
(3)jdk7.0开始 后面的泛型可以自动推断
ArrayList<泛型> list = new ArrayList<>();
2)如何添加元素
list.add(元素);//一次添加一个
Collections.addAll(集合,元素,元素…);//一次添加多个
//Collections.addAll(集合,元素,元素,元素...)
public static void addAll(ArrayList<Integer> jihe,Integer ... nums){
for(Integer x : nums){
jihe.add(x);
}
“…”可变参:
参数个数可以0到无数个
可变参底层基于数组实现的 since jdk5.0
一个方法里面里面最多只能出现一个可变参
可变参只能放在参数的最后
不要在本类里面出现一个等价的数组类型的参数
public class Test1{
public static void main(String[] args){
//test();
//test(45);
//test(10,88);
test(11,22,33);
}
/**
可变参:参数个数可以0到无数个
可变参底层基于数组实现的 since jdk5.0
一个方法里面里面最多只能出现一个可变参
可变参只能放在参数的最后
不要在本类里面出现一个等价的数组类型的参数
*/
public static void test(int ... x){//x:数组
for(int num : x){
System.out.println(num);
}
}
}
面试题:
Collection和Collections之间的区别?
Collections是集合的工具类:class
Collection是所有单值类型集合统一的父接口:interface
3)得到集合大小:
list.size()
4)得到集合里面的某一个元素:
list.get(下标)
5)判断集合里面是否存在某个元素:
list.contains(元素)
能不能返回true 取决于equals方法
6)如何遍历集合:
for + 下标
foreach
迭代器
7)如何删除元素:
(1) list.remove(int 下标)
(2) list.remove(Object 元素)如果删除数字,需要把他转为Integer再进行删除:list.remove(new Integer(90));
*:一个remove方法只能删除一个对象
*:remove(Object 元素)底层需要尊重equals比较机制,如果被删元素和集合里面的元素相等,则可以删除成功
@Override
public boolean equals(Object obj){
//return true;//所有的对象都视为相等对象
return false;//即使是内存里面的同一个对象也被视为不同的两个对象
}
清空集合:list.clear()
*: 谁主张谁举证
要被删除的对象 会主动的调用他自己类的equals
和集合里面的每一个元素做比较
System.out.println(list.contains(stu));//调用的stu类的equals()
*: 当我们使用迭代器遍历集合的过程中 不允许对集合的整体进行添加、删除操作 否则触发CME异常(并发修改异常)
如果在遍历的过程中 进行删除的话: ite.remove()
用迭代器删除集合中符合某个条件的元素
代码示例:
import java.util.*;
public class TestRemove{
public static void main(String[] args){
ArrayList<String> list=new ArrayList<>();
Collections.addAll(list,"刘德华","黎明","张学友","郭富城");
//删除三个字的名字
for(Iterator<String> ite=list.iterator();ite.hasNext();){
String name=ite.next();
if(name.length()==3){
ite.remove();//迭代器删除
}
}
System.out.println(list);
}
}
8)常见的构造方法:
ArrayList list = new ArrayList(int 数组空间大小);
空间大小 >= 0 写几开辟几块空间
空间大小 < 0 抛出异常
ArrayList list = new ArrayList();//默认开辟10块空间
扩容:list.ensureCapacity(int 容量);
缩容:list.trimToSize()
import java.util.*;
public class TestArrayList7{
public static void main(String[] args){
/**
当我们创建一个数组对象的时候 需要先明确空间大小
ArrayList底层基于数组实现的 所以当我们创建一个ArrayList
对象的时候 其实底层在创建数组对象 数组对象开辟多大空间
取决于构造方法
ArrayList list = new ArrayList(int 数组容量);
容量 >= 0 写几开辟几块空间
容量 < 0 抛出异常
ArrayList list = new ArrayList();
默认开辟10块空间
集合无论底层开辟多少块空间 都可以装无数个元素
集合会自动的扩容
jdk6.0及之前 x * 3 / 2 + 1
10 -> 16 -> 25....
jdk7.0及之后 x + (x >> 1)
10 -> 15 -> 22....
在项目开发的时候尽量避免扩容:
1:创建一个新的数组对象
2:将老数组里面的元素复制到新的数组里面
3:改变引用指向
4:回收老数组对象
5:继续添加元素
*/
//ArrayList<Integer> list = new ArrayList<>();//[]:10
//Collections.addAll(list,1,2,3,4,5,6,7,8,9,10,11,12,13,14);
//System.out.println(list);
//10 -> 16 -> 22 -> 33.... >= 200
ArrayList<Integer> list = new ArrayList<>();//[]:200
//......
//扩容:将集合大小扩大为XXX块空间
list.ensureCapacity(200);
//80个元素 120块空间
//缩容:将集合的大小缩小为元素个数
list.trimToSize();
}
}
9)模拟实现ArrayList
通过我们自己创建一个数组来实现Sun公司开发的ArrayList,探究一下他的具体实现过程。
import java.util.*;
public class TestArrayList1{
public static void main(String[] args){
EtoakList <Integer> list=new EtoakList<>();
list.add(78);
list.add(23);
list.add(56);
list.add(57);
list.add(90);
list.add(18);
list.add(45);
list.add(12);
list.add(76);
list.add(99);
list.add(80);
list.add(12);
list.remove(new Integer(56));
System.out.println(list.size());
System.out.println(list.get(1));
System.out.println(list.contains(70));
System.out.println(list);
}}
//拿着EtoakList模拟实现ArrayList -> []
class EtoakList<E>{
//属性:对象有什么
//ArrayList底层基于数组实现的 为了保证什么类型都可以装进数组里面
//所以定义成Object[]
private Object[] data;//装元素
private int size; //统计元素个数 add() size+1 remove() size-1
//有参构造方法:参数表示底层数组空间大小
public EtoakList(int x){//x:空间大小
if(x<0){
System.out.println("空间开辟不规范");
}else{
data=new Object[x];
}
}
//无参构造方法:默认开辟10块空间
public EtoakList(){
this(10);//data = new Object[10];
}
//方法:
//得到集合的大小:list.size()
public int size(){
return size;}
//得到集合里面的某一个元素:
//Object obj = list.get(3)
public Object get(int i){
if(i>=0&&i<=size){//x合法的下标
return data[i];
}else{
return "下标超出边界异常";
}
}
//如何添加元素:
public void add(Object obj){
//当我们想要往集合里面添加元素obj的时候 其实底层将元素装进数组里面
//当我们想要往数组里面添加元素的时候 底层需要判断当前的 数组对象有没有满
if(data.length==size)
//如果满了 需要扩容
//创建一个新的数组对象
//jdk6.0之前 x * 3 / 2 + 1
//jdk7.0之后 x + (x >> 1)
data=Arrays.copyOf(data,size+(size>>1));
//将老数组里面的元素复制到新的数组里面
//改变引用指向
//回收老数组对象 -> gc
//继续添加元素
//如果没有满的话
//直接添加元素obj
data[size++]=obj;
//size++;
}
/**
已有元素 最大下标 新来下标
1 0 1
2 1 2
3 2 3
size size-1 size
*/
//如何删除元素:list.remove(4)
public void remove(int x){
//当我们想要从集合里面删除下标x的时候 其实底层从数组里面删除下标x对应的元素
System.arraycopy(data,x+1,data,x,size-- -(x+1));
//size--;
/**
45 66 72 19 88
0 1 2 3 4
删除下标0 从下标1开始复制 复制4=5-1个元素
删除下标1 从下标2开始复制 复制3=5-2个元素
删除下标2 从下标3开始复制 复制2=5-3个元素
删除下标x 从下标x+1开始复制 复制size - (x+1)
*/
}
//如何删除元素:list.remove(Object 元素)
public void remove(Object obj){
//当我们想要指定元素进行删除的时候 底层拿着被删除的元素和数组里面的每一个元素做equals比较
for(int i=0;i<size;i++){
if(obj.equals(data[i])){
//下标x对应的元素和obj视为相等对象
remove(i);
//一个remove方法只能删除一个对象
break;
}
}
}
//如何判断集合中是否包含某个元素
public boolean contains(Object obj){
int count =0;
for(int i=0;i<size;i++){
if(obj.equals(data[i])){
count++;//计数器记录true的个数
}
}
return count!=0;//count!=0表示该集合里包含obj这个元素,则是则返回true
}
@Override
//重写toString方法,打印集合里面的内容
public String toString(){
String x="[";//定义一个字符串来接数组data中的数据
for(int i=0;i<size;i++){
if(i==size-1){
x+=data[i];
}else{
x+=data[i]+",";
}
}
return x+"]";
}
}
ArrayList常见用法代码示例:
import java.util.*;
public class TestArrayList4{
public static void main(String[] args){
ArrayList<String> list=new ArrayList<>();
System.out.println("********向集合里添加元素********");
list.add("Andy");
list.add("Lee");
Collections.addAll(list,"Anron","Jack");
System.out.println("集合的大小:\t"+list.size());
System.out.println("第三个元素:\t"+list.get(2));
System.out.println("是否包含Lee名字:"+list.contains("Lee"));
for(String name:list){
if(name.startsWith("A")){
System.out.println("A开头的名字:\t"+name);
}
}
System.out.println("********迭代器遍历********");
for(Iterator<String> ite=list.iterator();ite.hasNext();){
String x=ite.next();
if(x.startsWith("A")){
System.out.println("A开头的名字:"+x);
}
}
System.out.println("********删除集合中的元素********");
//方法一
//while(list.size()!=0){ list.remove(0);}
//方法二
/*for(int i=list.size()-1;i>=0;i--){
list.remove(i);
}*/
//方法三
list.clear();
System.out.println(list);
}
}
10)内存图