集合类的总认识
集合中储存的是元素的什么信息
集合中储存的是元素的地址
无序是指先添加的元素跑到后面 ,最终获取的元素顺序与添加的元素顺序不一样
无索引意味着不能使用get(i)方法
import java.util.ArrayList;
import java.util.HashSet;
public class CollectionTest1 {
public static void main(String[] args) {
//简单确认一下Collection集合的特点
ArrayList<String> list =new ArrayList<>();
//有序,可重复,有索引
list.add("java1");
list.add("java2");
list.add("java1");
list.add("java2");
System.out.println(list);
System.out.println("----------------");
HashSet<String> sets =new HashSet<>();
//无序,不重复,无索引
sets.add("java1");
sets.add("java2");
sets.add("java1");
sets.add("java3");
System.out.println(sets);
}
}
Collection 集合
collection的常用方法9个
1.add方法,添加元素,添加成功返回true
//多态
Collection<String> c =new ArrayList<>();
c.add("java2");
System.out.println(c.add("java1"));//ture
c.add("java3");
c.add("java1");
c.add("java2");
2.claer 清空集合数据
//2.claer 清空集合数据
c.clear();
System.out.println(c);
c.add("java3");
c.add("java1");
c.add("java2");
3. isEmpty判断集合是否为空,为空返回true。反之false
//3. isEmpty判断集合是否为空,为空返回true。反之false
c.clear();
System.out.println(c.isEmpty());//true
c.add("java3");
c.add("java1");
c.add("java2");
System.out.println(c.isEmpty());
4.size()获取集合大小
5.contains()判断集合中是否包含某个元素
//4.size()获取集合大小
System.out.println(c.size());
//5.contains()判断集合中是否包含某个元素
System.out.println(c.contains("java1"));//true
System.out.println(c.contains("java"));//false
6.remove 删除某个元素,如果有多个重复元素,默认删除第一个元素
//6.remove 删除某个元素,如果有多个重复元素,默认删除第一个元素
c.add("java1");
System.out.println(c);
System.out.println(c.remove("java1"));
System.out.println(c);
7.toArray 把集合转换成数组
用Object类型接数据,原因为虽然使用泛型,String。但是由于泛型在运行阶段已经擦除了
用Object接使得数据更全面
//7.toArray 把集合转换成数组
//用Object类型接数据,原因为虽然使用泛型,String。但是由于泛型在运行阶段已经擦除了
//用Object接使得数据更全面
Object[]arr = c.toArray();
System.out.println(Arrays.toString(arr));
8.指定类型数组(保证添加的元素全为字符串)
//指定类型数组(保证添加的元素全为字符串)
String [] arr2 =c.toArray(new String[c.size()]);
System.out.println(Arrays.toString(arr2));
9.addAll把一个集合的全部数据倒进另一个集合中去(保证类型相同)
//addAll把一个集合的全部数据倒进另一个集合中去(保证类型相同)
Collection<String> c1 =new ArrayList<>();
c1.add("java3");
c1.add("java1");
c1.add("java2");
Collection<String> c2 =new ArrayList<>();
c2.add("java5");
c2.add("java6");
c2.add("java7");
//把c2放入c1中
c1.addAll(c2);
System.out.println(c1);
System.out.println(c2);
Collection遍历方式
迭代器(Iterator)
Collection<String> c = new ArrayList<>();
Iterator<String> it = c.iterator();
while (it.hasNext()) {
String ele = it.next();
System.out.print(ele);
}
//使用迭代器遍历
public class CollectionDemo1 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("赵敏");
c.add("小昭");
c.add("素素");
c.add("灭绝");
System.out.println(c);
//使用迭代器遍历集合
//1.从集合对象中获取迭代器对象
Iterator<String> it = c.iterator();
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
// System.out.println(it.next());//报错原因超范围了
//2.我们应该使用循环迭代集合
while (it.hasNext()) {
String ele = it.next();
System.out.print(ele);
}
增强for循环
3,增强for循环
for (String ele1 : c) {
System.out.println(ele1);
}
for (String s : c) {
}
快捷键c.for直接进行打印c for (String s : c) { }
lambda表达式
System.out.println("----------------");
c.forEach(s -> System.out.println(s));
c.forEach(System.out::println);
List集合
List集合特点是有序,可重复,有索引
List<String> list =new ArrayList<>();
ArrayList与LinkedList有什么区别
ArrayList
查询快,增删慢
LinkedList
查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的
总结
ArrayList:
- 随机访问:由于底层是数组,支持 O(1) 时间复杂度的随机访问操作。
- 插入和删除:在数组中间插入或删除元素会导致元素的移动,时间复杂度为 O(n)。尾部插入(如果不需要扩展数组)为 O(1)。
LinkedList:
- 随机访问:需要遍历链表来访问元素,时间复杂度为 O(n)。
- 插入和删除:在链表的头部或尾部插入或删除元素为 O(1) 时间复杂度;在链表中间插入或删除元素也为 O(1),但需要先定位到插入点,定位操作为 O(n)。
ArrayList
:适合频繁的随机访问,但在插入和删除操作时可能效率较低。LinkedList
:适合频繁的插入和删除操作,但在随机访问时效率较低。
List<String> list = new ArrayList<>();
list = new LinkedList<>(list);
实现将list转化为LinkedList
创建了一个新的
LinkedList
实例,并将ArrayList
中的元素复制到这个新的LinkedList
中。
1.add(int index, E element) 在某个索引位置插入元素前面
List<String> list =new ArrayList<>();
list.add("赵敏");
list.add("小昭");
list.add("素素");
list.add("灭绝");
System.out.println(list);
//1.add(int index, E element) 在某个索引位置插入元素
list.add(2,"加入到素素前面元素");
System.out.println(list);
2.remove 根据索引删除数据,并且返回删除元素
//2.remove 根据索引删除数据,并且返回删除元素
System.out.println(list.remove(2));//加入到素素前面元素
3.get 返回集合中指定位置的元素
//3.get 返回集合中指定位置的元素
System.out.println(list.get(1));//小昭
4.set 修改索引位置元素,修改成功后,会返回原来的数据
//4.set 修改索引位置元素,修改成功后,会返回原来的数据
System.out.println(list.set(3, "牛魔王"));//灭绝
System.out.println(list);//[赵敏, 小昭, 素素, 牛魔王]
四种循环
package com.itheima.d3_list;
import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListTest2 {
public static void main(String[] args) {
List<String> list =new ArrayList<>();
list.add("赵敏");
list.add("小昭");
list.add("素素");
list.add("灭绝");
//for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//迭代器
Iterator<String> it =list.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
//增强for循环
for (String s : list) {
System.out.println(s);
}
//lambda表达式
list.forEach(s-> System.out.println(s));
}
}
ArrayList集合的底层原理
查询快,增删慢
链表的简单认识
LinkedList集合的底层原理
查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的
LinkedList的特有方法
package com.itheima.d3_list;
import java.util.LinkedList;
//案例
public class ListTest3case {
public static void main(String[] args) {
//创建一个对列
LinkedList<String> quene =new LinkedList<>();
quene.add("第一个");
quene.add("第二个");
quene.add("第三个");
System.out.println(quene);
System.out.println("-----------------");
System.out.println(quene.removeFirst());//第一个
quene.removeFirst();
System.out.println(quene);//[第三个]
}
}
push相当于addFirst
pop相当于removeFirst
栈的应用:弹夹
//创建一个栈对象 LinkedList<String> stack =new LinkedList<>(); //压栈(push) // stack.addFirst("第一个子弹"); // stack.addFirst("第二个子弹"); // stack.addFirst("第三个子弹"); // stack.addFirst("第四个子弹"); stack.push("第一个子弹"); stack.push("第二个子弹"); stack.push("第三个子弹"); stack.push("第四个子弹"); System.out.println(stack); //出栈(pop) // System.out.println(stack.removeFirst()); // System.out.println(stack.removeFirst()); // System.out.println(stack); System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack);
set集合
set集合的特点:无序,添加数据的顺序和获取出的数据顺序不一致;不重复,无索引
哈希值的简单认识
SetTest2_Student s1 =new SetTest2_Student("蜘蛛精",25,169.5);
SetTest2_Student s2 =new SetTest2_Student("紫霞",22,166.5);
System.out.println(s1.hashCode());//1324119927
System.out.println(s1.hashCode());//1324119927
System.out.println(s2.hashCode());//990368553
//两者哈希值相同
String str1= new String("abc");
String strr2 =new String( "acD");
System.out.println(str1.hashCode());//96354
System.out.println(strr2.hashCode());//96354
HashSet-哈希表
无序,不重复,无索引
Set<SetTest2_Student> students =new HashSet<>();
无序:是指HashSet是通过从前往后依次遍历与HashSet的存入数据的哈希值算法不同。
导致去遍历是无序的
如果数组快占满了,就去扩容,默认的加载因子为0.75 去用数组长度去乘于0.75
二叉树的简单认识
规则:小的存左边,大的存右边,一样的不存
HashSet去自定义重复的方法
内容一样的两个学生对象存到HashSet集合中去,不能去重复
原因:HashSet对于创建的不同对象都有不同的哈希值,再拿不同的哈希进行求余得到不同的结果
如何让HashSet集合实现对内容一样的两个不同对象去重复
去重写equals与hasCode方法(用快捷键:generate)
//只要两个对象内容一样就返回true
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SetTest2_Student that = (SetTest2_Student) o;
return age == that.age && Double.compare(that.height, height) == 0 && Objects.equals(name, that.name);
}
//只要两个内容一样就返回一样的哈希值
@Override
public int hashCode() {
return Objects.hash(name, age, height);
}
public class SetTest2 {
public static void main(String[] args) {
Set<SetTest2_Student> students =new HashSet<>();
SetTest2_Student s1 =new SetTest2_Student("蜘蛛精",25,169.5);
SetTest2_Student s2 =new SetTest2_Student("紫霞",22,166.5);
SetTest2_Student s3 =new SetTest2_Student("蜘蛛精",25,169.5);
SetTest2_Student s4 =new SetTest2_Student("牛魔王",33,178);
System.out.println(s1.hashCode());
System.out.println(s3.hashCode());
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
//实现去重复(让两个蜘蛛精对象只保留一个)
System.out.println(students);
}
}
LinkedHashSet-双链表
有序,不重复,无索引
LinkedHashSet实现有序通过双链表去完成,在此方法中通过记录前后元素位置
TreeSet
特点:不重复,无索引,可排序,(默认为升序,按照元素的大小,由小到大排序)
底层是基于红黑树去实现排序的
例如在下面这段代码中。我先加入5让它成为树根,然后去加4,4比5小放左边,再加7,7比5大放在数的右边。再到4,放左边看到重复了就不存了。(图示类似于下图,数据不同)
Set<Integer> set =new TreeSet<>();
set.add(5);
set.add(4);
set.add(7);
set.add(4);
System.out.println(set);//[4, 5, 7]
解决TreeSet自定义排序的方法
联想126节Arrays中自定义排序
方式一
年龄升序
this.age-o.age
年龄降序
o.age-this.age
比较年龄
Set<SetTest2_Student> students =new TreeSet<>();
students.add(new SetTest2_Student("蜘蛛精",23,145));
students.add(new SetTest2_Student("紫霞",22,169.8));
students.add(new SetTest2_Student("至尊宝",23,145));
students.add(new SetTest2_Student("刘",24,123));
System.out.println(students);
public class SetTest2_Student implements Comparable<SetTest2_Student>{
//this o
@Override
public int compareTo(SetTest2_Student o) {
//如果认为左边的对象大于右边的对象就返回正整数
//如果左边的对象等于右边的对象就返回0
//如果左边的对象小于右边的对象就返回负整数
return this.age-o.age;
}
}
结果:[SetTest2_Student{name='紫霞', age=22, height=169.8}, SetTest2_Student{name='蜘蛛精', age=23, height=145.0},
SetTest2_Student{name='刘', age=24, height=123.0}]
此时自定义按照年龄去排序但是没有至尊宝。原因为至尊宝与蜘蛛精年龄相同就不保存
方式二(比较身高)依旧遵循身高相同只保留一个的思想
Set<SetTest2_Student> students =new TreeSet<>(new Comparator<SetTest2_Student>() {
@Override
public int compare(SetTest2_Student o1, SetTest2_Student o2) {
//按照身高进行排序
return Double.compare(o1.getHeight(),o2.getHeight());
}
});
简化版
//身高升序
Set<SetTest2_Student> students =new TreeSet<>( (o1,o2)-> Double.compare(o1.getHeight(),o2.getHeight()));
//身高降序
Set<SetTest2_Student> students1 =new TreeSet<>( (o1,o2)-> Double.compare(o2.getHeight(),o1.getHeight()));
注:当有多个比较规则TreeSet会就近选择一个方法进行比较
下面就会先执行比较身高的方法
//这是主函数
Set<SetTest2_Student> students =new TreeSet<>(new Comparator<SetTest2_Student>() {
@Override
public int compare(SetTest2_Student o1, SetTest2_Student o2) {
//按照身高进行排序
return Double.compare(o1.getHeight(),o2.getHeight());
}
});
students.add(new SetTest2_Student("蜘蛛精",23,145));
students.add(new SetTest2_Student("紫霞",22,169.8));
students.add(new SetTest2_Student("至尊宝",23,145));
students.add(new SetTest2_Student("刘",24,123));
System.out.println(students);
public class SetTest2_Student implements Comparable<SetTest2_Student>{
//this o
@Override
public int compareTo(SetTest2_Student o) {
//如果认为左边的对象大于右边的对象就返回正整数
//如果左边的对象等于右边的对象就返回0
//如果左边的对象小于右边的对象就返回负整数
return this.age-o.age;
}
}
集合的并发修改异常问题
使用增强for循环与lambda表达式是不能修改成功
例子删除名字中有李的名字
System.out.println("使用迭代器版");
Iterator<String> it =list.iterator();
while (it.hasNext())
{
String name =it.next();
if(name.contains("李"))
{
//
it.remove();
}
}
System.out.println(list);
it.remove()
删除迭代器当前遍历到的数据,每删除一个数据后
//相当于在底层进行i--
public class CollectionTest1 {
public static void main(String[] args) {
//需求:找出名字中有李的并删除
List<String> list =new ArrayList<>();
list.add("王麻子");
list.add("小李子");
list.add("李爱华");
list.add("张全蛋");
list.add("小李");
list.add("李玉刚");
System.out.println(list);
// Iterator<String> it =list.iterator();
// while (it.hasNext())
// {
// String name =it.next();
// if(name.contains("李"))
// {
// list.remove(name);
// }
//
// }
// System.out.println(list);//会出现异常
//使用for循环会出现漏删情况
// for (int i = 0; i < list.size(); i++) {
// String name =list.get(i);
// if(name.contains("李"))
// {
// list.remove(name);
// }
//
// }
// System.out.println(list);
//修改成功版
for (int i = 0; i < list.size(); i++) {
String name =list.get(i);
if(name.contains("李"))
{
list.remove(name);
i--;
}
}
System.out.println(list);
System.out.println("使用迭代器版");
Iterator<String> it =list.iterator();
while (it.hasNext())
{
String name =it.next();
if(name.contains("李"))
{
// list.remove(name);//并发修改异常的错误
it.remove();//删除迭代器当前遍历到的数据,每删除一个数据后
//相当于在底层进行i--
}
}
System.out.println(list);
}
}
前置知识:可变参数
可变参数对外就是参数,对内就是数组。定义在方法或构造器上用于灵活接收数据
可变参数:int..nums
//认识可变参数
public class paramTest {
public static void main(String[] args) {
test();
test(10,11);
test(10,34,55,66);
test(new int[]{10,20,30,40});
}
public static void test( int...nums){
System.out.println(nums.length);
System.out.println(Arrays.toString(nums));
System.out.println("--------------------");
}
}
注意事项:
1.一个形参列表中,只能有一个可变参数
报错,形参列表中只能写一个参数
public static void test( int...nums,int...nums2){
System.out.println(nums.length);
System.out.println(Arrays.toString(nums));
System.out.println("--------------------");
}
2.可变参数必须放在形参列表的最后一个
Collections
1.addAll 为一起collection的集合批量增添数据
//1.addAll 为一起collection的集合批量增添数据
List<String> name =new ArrayList<>();
Collections.addAll(name,"刘翀羽","宋森康","马俊杰","高晨凯","刘星");
System.out.println(name);
2.shuffle 打乱list集合中的元素顺序因为list集合是有序的,其他都是无序的不需要
//2.shuffle 打乱list集合中的元素顺序因为list集合是有序的,其他都是无序的不需要
//斗地主应用打乱牌
List<String> name =new ArrayList<>();
Collections.addAll(name,"刘翀羽","宋森康","马俊杰","高晨凯","刘星");
System.out.println(name);
Collections.shuffle(name);
System.out.println(name);
3.sort对list集合的元素进行升序排序
注意:sort想要对Set进行排序需要转换
List<String> list =new ArrayList<>(set);
Collections.sort(list);
Set<String> sortedSet = new LinkedHashSet<>(list);
Set<String> set =new LinkedHashSet<>();
set.add("java");
set.add("apple");
set.add("banban");
List<String> list =new ArrayList<>(set);
Collections.sort(list);
Set<String> sortedSet = new LinkedHashSet<>(list);
System.out.println(sortedSet);
//3.sort对list集合的元素进行升序排序
List<Integer> list =new ArrayList<>();
list.add(3);
list.add(5);
list.add(2);
Collections.sort(list);
System.out.println(list);
4.sort自定义 让Collections对自定义进行排序必须定义规则
//4.sort自定义 让Collections对自定义进行排序必须定义规则
//注意:允许年龄重复
List<Student> students =new ArrayList<>();
students.add(new Student("蜘蛛精",25,169.5));
students.add(new Student("紫霞",22,166.5));
students.add(new Student("蜘蛛精",25,169.5));
students.add(new Student("牛魔王",33,178));
Collections.sort(students);
System.out.println(students);
用Comparator接口进行比较(按照身高进行排序)
//使用Comparator接口进行比较(按照身高进行排序)
List<Student> students =new ArrayList<>();
students.add(new Student("蜘蛛精",25,169.5));
students.add(new Student("紫霞",22,166.5));
students.add(new Student("蜘蛛精",25,169.5));
students.add(new Student("牛魔王",33,178));
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o1.getHeight(),o2.getHeight());
}
});
System.out.println(students);
Collection案例:斗地主
package com.itheima.d8_collection_test;
//目标:斗地主游戏的案例进行开发
/*案例分析
业务:总共有54张牌
点数:3,4,5,6,7,8,9,10,J,Q,K,A,1,2
花色:
大小王
点数分别为要组合四种花色,大小王各一张
斗地主,发出51张,剩下3张作为底牌
*/
public class GameDemo {
public static void main(String[] args) {
//1.牌类
//2.房间
Room m =new Room();
m.start();
}
}
package com.itheima.d8_collection_test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
//房间
public class Room {
//必须有一张牌
private List<Card> allCards =new ArrayList<>();
public Room() {
//1.做出54张牌,存入到Collection集合中
//a.点数,个数确定了类型也确定、
String numbers[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"};
//b.花色,点数确定了,类型确定
String[] colors = {"♠", "♥", "♣", "♦"};
int size = 0;//表示每张牌的大小
//c.遍历点数,在遍历花色,组织牌
for (String number : numbers) {
//number= "3"
size++;
for (String color : colors) {
//得到一种牌
Card c =new Card(number,color,size);
allCards.add(c);//存入牌
}
}
//单独存入小大王
Card c1 =new Card("","🃏",++size);
Card c2 =new Card("","🃏",++size);
Collections.addAll(allCards,c1,c2);
System.out.println("新牌"+allCards);
}
/*
游戏启动
*/
public void start() {
//利用shuffle每次洗牌都不一样
Collections.shuffle(allCards);
System.out.println("洗牌后"+allCards);
/*
2.发牌,首先肯定要定义三个玩家,
虽然使用Set(TreeSet)可以自动完成升序,但是会使得没有重复牌。
所以使用List(ArrayList)更方便
*/
4.看牌
ArrayList<Card> liuchongyu =new ArrayList<>();
ArrayList<Card> songsenkang =new ArrayList<>();
ArrayList<Card> majunjie =new ArrayList<>();
for (int i = 0; i < allCards.size()-3; i++) {
Card card= allCards.get(i);
if(i%3==0){
liuchongyu.add(card);
}
else if(i%3==1)
{
songsenkang.add(card);
}
else if(i%3==2)
{
majunjie.add(card);
}
}
//3.对3位玩家的牌进行排序
sortCards(liuchongyu);
sortCards(songsenkang);
sortCards(majunjie);
System.out.println("刘翀羽的牌"+liuchongyu);
System.out.println("宋森康"+songsenkang);
System.out.println("马俊杰"+majunjie);
//处理最后三张牌
// System.out.println(allCards.get(53));
// System.out.println(allCards.get(52));
// System.out.println(allCards.get(51));
List<Card> list = allCards.subList(allCards.size() - 3, allCards.size());
System.out.println("底牌"+list);
songsenkang.addAll(list);
sortCards(songsenkang);
System.out.println("宋森康抢到地主"+songsenkang);
}
/*
集中进行排序
*/
private void sortCards(ArrayList<Card> cards) {
Collections.sort(cards, new Comparator<Card>() {
@Override
public int compare(Card o1, Card o2) {
//进行升序牌
// return o1.getSize()-o2.getSize();
//进行降序牌
return o2.getSize()-o1.getSize();
}
});
}
}
package com.itheima.d8_collection_test;
//牌类
public class Card {
private String number;
private String color;
//每张牌有大小
private int size;//0 1 2 3 4 ...13
@Override
public String toString() {
return color+number;
}
public Card() {
}
public Card(String number, String color, int size) {
this.number = number;
this.color = color;
this.size = size;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
结果
Map集合
map是一个泛型接口
无序是指先添加的元素跑到后面 ,最终获取的元素顺序与添加的元素顺序不一样
无索引意味着不能使用get(i)方法
Map<String,Integer> map =new HashMap<>();
Map<String,Integer> map =new HashMap<>();
//按照键 无序 不重复 无索引
map.put("手机",12);
map.put("相机",1);
map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
map.put(null,null);
System.out.println(map);
Map<String,Integer> map =new LinkedHashMap<>();
//按照键 有序 不重复 无索引
map.put("手机",12);
map.put("相机",1);
map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
map.put(null,null);
System.out.println(map);
Map<String,Integer> map =new LinkedHashMap<>();
//按照键 有序 不重复 无索引
map.put("手机",12);
map.put("相机",1);
map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
map.put(null,null);
System.out.println(map);
结果
{手机=100, 相机=1, null=null}
//可排序,不重复,无索引
Map<Integer,String> map1 =new TreeMap<>();
map1.put(23,"java");
map1.put(24,"kobe");
map1.put(23,"乔丹");
map1.put(16,"男孩");
System.out.println(map1);
{16=男孩, 23=乔丹, 24=kobe}
Map集合
Map的常用方法 11
1.put()添加集合
Map<String,Integer> map =new HashMap<>();
//按照键 无序 不重复 无索引
map.put("手机",12);
map.put("相机",1);
map.put("手机",100);//后面重复的数据会覆盖前面的数据(键)
map.put(null,null);
map.put("手表",15);
System.out.println(map);
2.size() 获取集合的大小
//1.size() 获取集合的大小
System.out.println(map.size());
3.claer() 清空集合
//2.claer() 清空集合
//map.clear();
System.out.println(map);
4.isEmpty 判断集合是否为空,为空返回true反之false
//3.isEmpty 判断集合是否为空,为空返回true反之false
System.out.println(map.isEmpty());
5.get(key)根据键获取值
//4.get(key)根据键获取值
System.out.println(map.get("手机"));
//若键不存在就返回null
System.out.println(map.get("1"));//null
6.remove根据键删除某个元素(删除会返回键的值)
//5.remove根据键删除某个元素(删除会返回键的值)
System.out.println(map.remove("手表"));//15
System.out.println(map);
7.containsKey 判断是否包含某个键,包含返回true ,不包含返回false
8.containsValue 判断是否包含某个值
//6.containsKey 判断是否包含某个键,包含返回true ,不包含返回false
System.out.println(map.containsKey("手机"));//true
//7.containsValue 判断是否包含某个值
System.out.println(map.containsValue(100));
//注意类型一致不要字符串
System.out.println(map.containsValue("100"));
9.set<K> KeySet() 获取Map集合的全部键
10.Collection<V> values() 获取Map集合的全部值
不放到Set集合 原因不重复 collection的原因可以重复
8.set<K> KeySet() 获取Map集合的全部键
Set<String> keys =map.keySet();
System.out.println(keys);
//9.Collection<V> values() 获取Map集合的全部值
//放到Set集合 不重复collection的原因可以重复
Collection<Integer> values =map.values();
System.out.println(values);
11.putAll 把其他Map集合的数据倒入在自己集合中来
10. putAll 把其他Map集合的数据倒入在自己集合中来
Map<String,Integer> map1 =new HashMap<>();
map1.put("java1",10);
map1.put("java2",20);
Map<String,Integer> map2 =new HashMap<>();
map2.put("java3",10);
map2.put("java1",200);//重复留下新加入的
map1.putAll(map2);
System.out.println(map1);
Map的遍历
1.键找值
public static void main(String[] args) {
//准备一个map集合遍历数据
Map<String,Double> map =new HashMap<>();
map.put("牛魔王",156.4);
map.put("白蛇传",178.3);
map.put("白娘子",145.6);
map.put("牛魔王",178.9);
System.out.println(map);
//1.获取map的集合的所有键
Set<String> keys =map.keySet();
System.out.println(keys);
//2.遍历全部的键,根据键来获取其对应的值
for (String key : keys) {
double value =map.get(key);
System.out.println(key+"====>"+value);
}
2.键找值
调用map集合提供的entrySet方法,把Map集合转化成键值对类型的Set集合
Set<Map.Entry<String, Double>> entries = map.entrySet();
List 可能不太适合 Map 的 entrySet() 主要有以下原因:
唯一性要求:Map 的每个键值对都是唯一的,Set 自带唯一性保证,
而 List 允许重复项,不适合直接表示唯一的键值对。
//1.调用map集合提供的entrySet方法,把Map集合转化成键值对类型的Set集合
Set<Map.Entry<String, Double>> entries = map.entrySet();
for (Map.Entry<String, Double> entry : entries) {
String key =entry.getKey();
double value=entry.getValue();
System.out.println(key+"----->"+value);
}
3.lambda表达式
map.forEach((k,v)->{
System.out.println(k+"---->"+v);
});
map.forEach(new BiConsumer<String, Double>() {
@Override
public void accept(String k, Double v) {
System.out.println(k+"----->"+v);
}
});
System.out.println("--------------");
//简化版
map.forEach((k,v)->{
System.out.println(k+"---->"+v);
});
Map的案例
package com.itmap.d2_map_traverse;
import java.util.*;
public class MapTest4 {
public static void main(String[] args) {
List<String> date =new ArrayList<>();
String [] selects ={"A","B","C","D"};
Random r =new Random();
for (int i = 0; i < 80; i++) {
//生成0,1,2,3四个索引去拿到abcd
int indiex = r.nextInt(4);
date.add(selects[indiex]);
}
System.out.println(date);
//2.开始统计每个景点的投票人数
//准备一个Map集合用于统计最终的结果
Map<String,Integer> result =new HashMap<>();
//3.开始遍历80个景点数据
for (String s : date) {
//问问Map集合中是否包含四个景点
if(result.containsKey(s))
{
//说明这个景点之前统计过,要加一
result.put(s, result.get(s)+1);
}
else {
//说明之前没有统计,再结果对应的值赋值为1
result.put(s,1);
}
}
System.out.println(result);
}
}
HashMap-哈希表
无序,不重复,无索引(用的最多)
在下列的代码中出现两个相同的信息(重复)但是由于两者哈希值不一样,要解决必须自定义重写hasCode与equals方法
Map<Student,String> map =new HashMap<>();
map.put(new Student("刘翀羽",19,175.5),"九班");
map.put(new Student("宋森康",17,176),"十班");
map.put(new Student("马俊杰",20,183),"11班");
map.put(new Student("刘星",21,189),"12班");
map.put(new Student("刘翀羽",19,175.5),"九班");
System.out.println(map);
在学生类中增加此行代码(genegrate右键)重新启动代码将出现一个刘翀羽信息
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Double.compare(student.height, height) == 0 && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, height);
}
LinkedHashMap-双链表
按照键 有序 不重复 无索引
Map<String,Integer> map =new LinkedHashMap<>();
//Map<String,Integer> map =new HashMap<>();
// 按照键 有序 不重复 无索引
Map<String,Integer> map =new LinkedHashMap<>();
map.put("手表",100);
map.put("手表",220);
map.put("手机",2);
map.put("Java",2);
map.put(null,null);
System.out.println(map);
TreeMap
特点 :不重复,无索引,可排序(按照键的大小默认升序排序,只能对键排序)
不进行自定义比较规则会报错,TreeMap会对键排序
Map<Student ,String> map =new TreeMap<>();
map.put(new Student("刘翀羽",19,175.5),"九班");
map.put(new Student("宋森康",17,176),"十班");
map.put(new Student("马俊杰",20,183),"11班");
map.put(new Student("刘星",21,189),"12班");
map.put(new Student("刘翀羽",19,175.5),"九班");
System.out.println(map);
解决方法一
让类实现Coparable接口,重写比较规则
其中进行年龄升序排序,记住一定是对键里的东西排序
若是年龄降序排序就是 o.age-this.age
记住弄完接口直接放上面按上alt+Enter就可以完成重写
public class Student implements Comparable<Student>{
@Override
// this o
public int compareTo(Student o) {
//年龄升序排序
return this.age-o.age;
}
}
解决方法二
TreeMap有一个有参构造器,支持创建Comparable比较器对象,以方便用来指定比较规则
下面进行的是身高降序排序 (将不会去比较年龄大小)
Map<Student ,String> map =new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o2.getHeight(),o1.getHeight());
}
});
使用lambda表达式简化代码
Map<Student ,String> map =new TreeMap<>( (o1, o2) ->Double.compare(o2.getHeight(),o1.getHeight()));
其中当你使用该方法在有参数构造器时制定了比较规则,即使再学生类中重写,
但是会优先去执行有参数比较器的规则
集合的嵌套
定义:集合中的元素又是一个集合
Map<String, List<String>> map= new HashMap<>();
//1.定义一个Map集合存储全部省份信息,和其对应的城市信息
Map<String, List<String>> map= new HashMap<>();
List<String> cities1 =new ArrayList<>();
Collections.addAll(cities1,"苏州市","无锡市","常州市","镇江市","扬州市","泰州市");
map.put("江苏省",cities1);
System.out.println(map);
遍历值
List<String> list = map.get("江苏省");
for (String s : list) {
System.out.println(s);
}
苏州市
无锡市
常州市
镇江市
扬州市
泰州市
map.forEach((p,c) ->
{
System.out.println(c);
});
[苏州市, 无锡市, 常州市, 镇江市, 扬州市, 泰州市]
map.forEach((p,c)->
{
System.out.println(p+"->"+c);
});
结果
江苏省->[苏州市, 无锡市, 常州市, 镇江市, 扬州市, 泰州市]
思考与总结
Collection<String> c =new ArrayList<>();
ArrayList<String> c1 =new ArrayList<>();
这两段代码有什么区别
Collection<String> c = new ArrayList<>();
解释:
- 接口 vs 实现:这里
c
是一个Collection<String>
类型的变量,而ArrayList<String>
是Collection
接口的一个实现类。ArrayList
实现了Collection
接口,因此可以将ArrayList<String>
对象赋值给Collection<String>
类型的变量。 - 优点:
- 编程接口:使用
Collection<String>
类型可以让你的代码更加灵活。你可以轻松地更改c
的实现类而不影响使用它的代码,例如改为LinkedList
或其他Collection
的实现,只要这些实现类符合Collection
接口。 - 抽象化:这种写法提供了一层抽象,有助于遵循面向接口编程的原则,提高代码的可维护性和扩展性。
- 编程接口:使用
2. ArrayList<String> c1 = new ArrayList<>();
解释:
- 具体实现:这里
c1
是一个ArrayList<String>
类型的变量,这直接表示你正在使用ArrayList
类。ArrayList
是Collection
接口的一个实现。 - 优点:
- 明确实现:这种写法明确指定了使用
ArrayList
作为集合的具体实现。如果你知道自己总是需要ArrayList
的特性,比如动态数组的特性和随机访问能力,直接使用ArrayList
是合适的。 - 直接访问实现特有方法:如果你需要使用
ArrayList
特有的方法(例如ensureCapacity
或trimToSize
),你可以直接调用这些方法,而不需要先将c1
强制转换为ArrayList
类型。
- 明确实现:这种写法明确指定了使用
总结
- 使用
Collection<String>
:提供了更高的抽象层次,使得代码更具灵活性和扩展性。你可以轻松地改变集合的具体实现而不需要修改代码的其他部分。 - 使用
ArrayList<String>
:明确地指定了集合的实现,可能在一些情况下会有特定的实现相关的优势,比如使用实现类的特定方法。
在实际编程中,推荐使用 Collection
类型来定义变量和方法的参数,这样可以使代码更具通用性和可维护性。具体实现类则可以在实际需要时使用。