(一)可变参数
案例:假如需要定义一个方法求和,该方法可以灵活的完成如下需求:
l 计算 1 个数据的和 。l 计算 2 个数据的和。l 计算 3 个数据的和。l 计算 n 个数据的和,甚至可以支持不接收参数进行调用。
package MyCollections;import java.util.Arrays;/*认识可变参数,掌握作用*/
public class ParamTest {public static void main(String[] args) {//test();//不传数据test(10);test(10,20,30);//传多个数据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)一个形参列表中,只能有一个可变参数
(2)可变参数必须放在形参列表的最后面
(3)可变参数在方法内部就是一个数组
(二)工具类Collections
Collections:是一个用来操作集合的工具类
Collections提供的常用静态方法:
方法名称 | 说明 |
public static <T> boolean addAll(Collection<? super T> c, T... elements) | 给集合批量添加元素 |
public static void shuffle(List<?> list) | 打乱List集合中的元素顺序 |
public static <T> void sort(List<T> list) | 对List集合中的元素进行升序排序 |
public static <T> void sort(List<T> list,Comparator<? super T> c) | 对List集合中元素,按照比较器对象 指定的规则进行排序 |
public static <T> boolean addAll(Collection<? super T> c, T... elements) 分析:
(1)
public static
:这表明该方法是公共的静态方法,可直接通过Collections
类调用,无需创建Collections
类的实例(2)该方法的返回类型为
boolean
,表示操作是否成功(3)
Collection<? super T> c
:此为方法的第一个参数,是一个Collection
类型的集合。? super T
是泛型通配符,代表该集合可以是T
类型或者T
的某个父类型的集合。这就保证了集合能够容纳T
类型的元素。(4)
T... elements
:这是一个可变参数,意味着可以传入任意数量(包括零个)的T
类型元素。在方法内部,可变参数会被当作T
类型的数组来处理
package MyCollections;import java.util.*;public class MyCollectionTest {public static void main(String[] args) {//1.public static <T> boolean addAll(Collection<? super T> c, T... elements) 给集合批量添加元素List<String> lis=new ArrayList<>();//Collectios 是工具类,不是List本身自带的方法,所以需要区分Collections.addAll(lis,"a1","a2","a3","a4");System.out.println(lis);//2.public static void shuffle(List<?> list) 打乱List集合中的元素顺序Collections.shuffle(lis);//3.public static <T> void sort(List<T> list) 对List集合中的元素进行升序排序List<Integer> list2=new ArrayList<>();list2.add(2);list2.add(0);list2.add(7);list2.add(5);Collections.sort(list2);System.out.println(list2);//3.2 对自定义对象进行排序(在对象中重写compareTo 实现指定排序方式)List<Student> listS=new ArrayList<>();Student s1=new Student("李彪",99,12.9);Student s2=new Student("Lisa",123,98.9);Student s3=new Student("Tom",79,32.9);Student s4=new Student("Jerry",66,21.3);listS.add(s1);listS.add(s2);listS.add(s3);listS.add(s4);Collections.sort(listS);System.out.println(listS); //注意,要重写toString方法才能实现获得对象的具体值,否则输出对象地址//public static <T> void sort(List<T> list,Comparator<? super T> c) 对List集合中元素,按照比较器对象指定的规则进行排序Collections.sort(listS, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// return o1.getHeight()-o2.getHeight(); 返回的是 double 类型的值,而 compare 方法要求返回 int 类型return Double.compare(o1.getHeight(),o2.getHeight());}});System.out.println(listS);}
}
(三)综合案例
分析业务需求
总共有54张牌点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2“花色: "♠", "♥", "♣", "♦“大小王: "👲" , "🃏“斗地主:发出51张牌,剩下3张做为底牌。
(1)创建一个牌的对象,用于记录一张牌的花色,大小和数字
package Example;public class Pai {String color;String num;int size; //用于区分当前牌的大小public Pai(String color, String num, int size) {this.color = color;this.num = num;this.size = size;}public Pai() {}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public String getNum() {return num;}public void setNum(String num) {this.num = num;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public String toString(){return color+","+num+","+size;}
}
(2)创建一个房间,房间里有初始化创建一副新牌操作和开始游戏后发牌操作
package Example;import java.util.*;public class hintDiZhu {/*总共有54张牌
点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2“
花色: "♠", "♥", "♣", "♦“
大小王: "👲" , "🃏“
斗地主:发出51张牌,剩下3张做为底牌。*/private List<Pai> PaiList=new ArrayList<>();public hintDiZhu(){//无参构造器//生成一铺牌List<String> nums=new ArrayList<>();Collections.addAll(nums,"3","4","5","6","7","8","9","10","J","Q","K","A","2");//System.out.println(nums);List<String> colors=new ArrayList<>();Collections.addAll(colors,"♠", "♥", "♣", "♦");// System.out.println(colors);int size=1;for (int i = 0; i < nums.size(); i++) {for (int i1 = 0; i1 < colors.size(); i1++) {Pai p=new Pai(colors.get(i1),nums.get(i),size);//System.out.println(p.toString());PaiList.add(p);}size++;}//单独存入大小王Pai p1=new Pai("","🃏",++size);Pai p2=new Pai("","👲",++size);PaiList.add(p1);PaiList.add(p2);System.out.print(PaiList);}public void Start(){////将牌打乱,进行发牌Collections.shuffle(PaiList);System.out.println(PaiList);//创建三个数组,代表三个人List<Pai> a1=new ArrayList<>();List<Pai> b1=new ArrayList<>();List<Pai> c1=new ArrayList<>();//开始发牌,依次发,共51张,剩下3张作为地主牌for (int i = 0; i < PaiList.size(); i++) {if(i%3==0){a1.add(PaiList.get(i));}else if(i%3==1){b1.add(PaiList.get(i));}else if(i%3==2){c1.add(PaiList.get(i));}}//对各自的牌进行排序Collections.sort(a1, new Comparator<Pai>() {@Overridepublic int compare(Pai o1, Pai o2) {return Integer.compare(o1.getSize(),o2.getSize());}});Collections.sort(b1,(o1,o2)->Integer.compare(o1.getSize(),o2.getSize()));Collections.sort(c1,(o1,o2)->Integer.compare(o1.getSize(),o2.getSize()));System.out.println("A的牌:");System.out.println(a1);System.out.println("B的牌:");System.out.println(b1);System.out.println("C的牌:");System.out.println(c1);}
}
(3)主函数,用于调用新的房间,启动游戏
package Example;public class Room {public static void main(String[] args) {hintDiZhu r1=new hintDiZhu();//启动游戏r1.Start();}
}
(四)Map集合
(1)认识Map
(2) Map的使用场景
需要存储一一对应的数据时,可以考虑使用map来存储
package MyMap;import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;/*目标:掌握Map集合的特点*/
public class MapTest {public static void main(String[] args) {//HashMap:无序,不重复,无索引Map<String,Integer> map1=new HashMap<>();map1.put("手表",100);map1.put("电话",1982);map1.put("娃娃",87);map1.put("夏天才手表",1990);map1.put("电话移动段",982);map1.put("小娃娃",97);System.out.println(map1);//{手表=100, 电话移动段=982, 夏天才手表=1990, 电话=1982, 娃娃=87, 小娃娃=97}//2.LinkedHashMap 有序(指插入LinkedHashMap的顺序),不重复,无索引Map<String,Integer> map2=new LinkedHashMap<>(); //多态写法,Map是LinkedHashMap的父类map2.put("手表",100);map2.put("电话",1982);map2.put("娃娃",87);map2.put("夏天才手表",1990);map2.put("电话移动段",982);map2.put("小娃娃",97);System.out.println(map2);//{手表=100, 电话=1982, 娃娃=87, 夏天才手表=1990, 电话移动段=982, 小娃娃=97}//3.TreeMap 可排序,不重复,无索引Map<Integer,String> map3=new TreeMap<>();map3.put(12,"djihsah");map3.put(89,"水表");map3.put(78,"董事会决议");map3.put(56,"najhc");map3.put(27,"不知道");System.out.println(map3); //{12=djihsah, 27=不知道, 56=najhc, 78=董事会决议, 89=水表}}
}
1. Map 集合 是什么?什么时候可以考虑使用 Map 集合 ?Map 集合是键值对集合需要存储一一对应的数据时,就可以考虑使用 Map 集合来做2. Map 集合的实现类有哪些?各自的特点是?HashMap: 元素按照键是无序,不重复,无索引,值不做要求。LinkedHashMap: 元素按照键是 有序 ,不重复,无索引,值不做要求。 TreeMap :元素按照建是 排序 ,不重复,无索引的, 值不做要求。
(3)map的常见方法
为什么要先学习Map的常用方法 ?lMap是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的
Map的常用方法如下:
方法名称 | 说明 |
public V put(K key,V value) | 添加元素 |
public int size() | 获取集合的大小 |
public void clear() | 清空集合 |
public boolean isEmpty() | 判断集合是否为空,为空返回true , 反之 |
public V get(Object key) | 根据键获取对应值 |
public V remove(Object key) | 根据键删除整个元素 |
public boolean containsKey(Object key) | 判断是否包含某个键 |
public boolean containsValue(Object value) | 判断是否包含某个值 |
public Set<K> keySet() | 获取全部键的集合 |
public Collection<V> values() | 获取Map集合的全部值 |
package MyMap;import java.util.HashMap;
import java.util.Map;public class MapMethod {public static void main(String[] args) {Map<String,Integer> map1=new HashMap<>();map1.put("手表",100);map1.put("电话",1982);map1.put("娃娃",87);map1.put("夏天才手表",1990);map1.put("电话移动段",982);map1.put("小娃娃",97);System.out.println(map1);//public int size() 获取集合的大小System.out.println(map1.size());//public void clear() 清空集合// map1.clear();//public boolean isEmpty() 判断集合是否为空,为空返回true , 反之System.out.println(map1.isEmpty());//public V get(Object key) 根据键获取对应值System.out.println(map1.get("电话"));//public V remove(Object key) 根据键删除整个元素,返回值为被删除的值System.out.println(map1.remove(map1.remove("电话")));//public boolean containsKey(Object key) 判断是否包含某个键System.out.println(map1.containsKey("小娃娃"));//public boolean containsValue(Object value) 判断是否包含某个值System.out.println(map1.containsValue(97));//public Set<K> keySet() 获取全部键的集合System.out.println(map1.keySet());//public Collection<V> values() 获取Map集合的全部值System.out.println(map1.values());}
}
(4)map的遍历方式
1.通过键找值:先获取Map集合的全部键,再通过遍历键来找值
2.键值对:把”键值对“看为一个整体进行遍历 (使用Map.Entry<String,Integer>将一一对应的键值对作为一个整体(Entry对象))
Set<map.Entry<String,Integer>> :
调用map集合提供的entrySet方法,将map集合替换成键值对类型的Set集合
3.Lambda表达式,JDK1.8之后开始的新技术(代码简单)
package MyMap;import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;public class SearchMethods {public static void main(String[] args) {//HashMap:无序,不重复,无索引Map<String,Integer> map1=new HashMap<>();map1.put("手表",100);map1.put("电话",1982);map1.put("娃娃",87);map1.put("夏天才手表",1990);map1.put("电话移动段",982);map1.put("小娃娃",97);//1.通过键找值:先获取Map集合的全部键,再通过遍历键来找值Set<String> Keys=map1.keySet(); //注意集合没有索引,所以不能使用for,但能使用for增强for (String key : Keys) {System.out.println(key+"------------->"+map1.get(key));// System.out.printf("键:%s ------------值:%d\n",key,map1.get(key));}//2.键值对:把”键值对“看为一个整体进行遍历Set<Map.Entry<String,Integer>> entries=map1.entrySet();for (Map.Entry<String, Integer> entry : entries) {System.out.println(entry);}//3.Lambda表达式,JDK1.8之后开始的新技术(代码简单)System.out.println("--------------Lambda-------------");map1.forEach(new BiConsumer<String, Integer>() {@Overridepublic void accept(String k, Integer v) {System.out.println(k+"---"+v);}});//map1.forEach((k,v)->System.out.println(k+"---"+v)); //简化写法}
}
Lambda表达式内部实现代码:本质还是使用Entry()实现的
default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);for (Map.Entry<K, V> entry : entrySet()) {K k;V v;try {k = entry.getKey();v = entry.getValue();} catch (IllegalStateException ise) {// this usually means the entry is no longer in the map.throw new ConcurrentModificationException(ise);}action.accept(k, v);}}
(5)map集合的案例
package MyMap;import java.util.HashMap;
import java.util.Map;
import java.util.Random;public class MapExample {public static void main(String[] args) {Map<String,Integer> num=new HashMap<>();//用一个String数组存储可选择的景点String[] s1={"A","B","C","D"};//创建一个随机对象Random r=new Random();int i=0;while(i<80){i++;int index=r.nextInt(4);//0123String key=s1[index];//System.out.println(key);if(num.containsKey(key)){num.put(key,num.get(key)+1);}else{num.put(key,1);}}System.out.println(num);}
}
(五)HashMap底层原理
1、HashMap的特点和底层原理?
由键决定:无序、不重复、无索引。 HashMap 底层是哈希表结构的。基于哈希表。增删改查的性能都较好。2、HashMap如何实现键的唯一性的?
依赖 hashCode 方法和 equals 方法保证 键 的唯一。如果 键 要存储的是自定义对象,需要重写 hashCode 和 equals 方法。
package MyMap;import MySet.Student;import java.util.HashMap;
import java.util.Map;//HashMap 存储对象
public class MyHashMap {public static void main(String[] args) {Map<Student, String> map=new HashMap<>(); //map.put(new MySet.Student("牛魔王",888,99.8),"居住洞");map.put(new MySet.Student("牛魔王",888,99.8),"居住洞");map.put(new MySet.Student("小灰灰",18,50.2),"狼堡");map.put(new MySet.Student("喜羊羊",69,78.9),"羊村");System.out.println(map);//设置HashCode和equals之后,才能将名字重复的对象是为同一个对象进行去重}
}
package MyMap;import java.util.Objects;public class Student implements Comparable<Student>{String name;int age;double height;
//this指当前对象 o 指传入的待比较对象@Overridepublic int compareTo(Student o){return this.age-o.age; //当age是puBlic 时可以直接使用.获取到值,若是private才需要通过Get,Set方法获取}public Student(String name, int age, double height) {this.name = name;this.age = age;this.height = height;}
//------------------------重写的方法
//
// @Override
// public boolean equals(Object o) {
// if (o == null || getClass() != o.getClass()) return false;
// Student student = (Student) o; //将传入的对象强制转换为学生对象,
// return age == student.age && Double.compare(height, student.height) == 0 && Objects.equals(name, student.name); //当两个对象的值相同时判定为相等
// }
//
// @Override
// public int hashCode() {
// return Objects.hash(name, age, height);
// }
//---------------------------@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}public Student() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}
}
(2)HashMap的案例
package MyMap;import java.util.HashMap;
import java.util.Map;
import java.util.Set;public class HashMapExample {public static void main(String[] args) {//2.创建HashMap集合对象用于存储StudentHashMap<Student,Integer> s=new HashMap<>();//3.创建学生对象Student s1=new Student("牛魔王",888,99.8);Student s2=new Student("小灰灰",18,50.2);Student s3=new Student("喜羊羊",69,78.9);//4.把学生对象添加到集合中s.put(s1,188);s.put(s2,69);s.put(s3,78);//遍历//1.先获取所有的键,再遍历键获取值Set<Student> keys=s.keySet();for(Student key:keys){System.out.println(key+"--->"+s.get(key));}//2只需要知道值:先获取所有的值s.values(),再遍历输出各个值for(Integer value:s.values()){System.out.println(value);}//3.1.遍历键值对:使用s.entrySet() 将键值对看作一个整体Set<Map.Entry<Student,Integer>> entryset= s.entrySet();for (Map.Entry<Student, Integer> studentIntegerEntry : entryset) {System.out.println(studentIntegerEntry.getKey()+"--->"+studentIntegerEntry.getValue());}//3.2.遍历键值对:使用Lambda表达式s.forEach((k,v)-> System.out.println(k+":"+v));}
}
(五)LinkedHashMap底层原理(有序,不重复,无索引)
package MyMap;import java.util.LinkedHashMap;
import java.util.Map;public class MyLinkedHashMap {public static void main(String[] args) {Map<Integer,String> map=new LinkedHashMap<>();map.put(2,"B");map.put(5,"E");map.put(4,"D");map.put(3,"C");map.put(1,"A");System.out.println(map); // 有序(指插入的顺序){2=B, 5=E, 4=D, 3=C, 1=A}}
}
(六)TreeMap底层原理(默认按键大小升序排序,不重复,无索引)
package MyMap;import java.util.Map;
import java.util.TreeMap;public class MyTreeMap {public static void main(String[] args) {Map<Integer,String> map=new TreeMap<>();map.put(2,"B");map.put(5,"E");map.put(4,"D");map.put(3,"C");map.put(1,"A");System.out.println(map); //{1=A, 2=B, 3=C, 4=D, 5=E}}
}
(七)Map综合案例
package MyMap;import java.util.*;public class MyMapExample {public static void main(String[] args) {
//江苏省 = 南京市,扬州市,苏州市,无锡市,常州市
//湖北省 = 武汉市,孝感市,十堰市,宜昌市,鄂州市
//河北省 = 石家庄市,唐山市,邢台市,保定市,张家口市HashMap<String,List<String>> pro=new HashMap<>();//List<String> citys1=new ArrayList<>();Collections.addAll(citys1, "南京市","扬州市","苏州市","无锡市","常州市");pro.put("江苏省",citys1);List<String> citys2=new ArrayList<>();Collections.addAll(citys2,"武汉市","孝感市","十堰市","宜昌市","鄂州市");pro.put("湖北省",citys2);List<String> citys3=new ArrayList<>();Collections.addAll(citys3,"石家庄市","唐山市","邢台市","保定市","张家口市");pro.put("河北省",citys3);//进行遍历//1 获取所有的键,遍历键获取值Set<String> p=pro.keySet();for (String k : p) {System.out.println(k+":"+pro.get(k));//江苏省:[南京市, 扬州市, 苏州市, 无锡市, 常州市]//湖北省:[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市]//河北省:[石家庄市, 唐山市, 邢台市, 保定市, 张家口市]}//方法2:使用entrySet()将键值对视为一个整体for(Map.Entry<String,List<String>> entry:pro.entrySet()){System.out.println(entry.getKey()+"--->"+entry.getValue());}//方法3 使用Lambda表达式pro.forEach((k,v)-> System.out.println(k+"--->"+v));}
}
(八)Steam流
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");需求:把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合。
package MySteam;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;public class Introduce {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张无忌");list.add("周芷若");list.add("赵敏");list.add("张强");list.add("张三丰");//需求:把集合中所有以“张”开头,且是3个字的元素存储到一个新的集合。List<String> List2=new ArrayList<>();for (String s : list) {if(s.startsWith("张") && s.length()==3){List2.add(s);}}System.out.println(List2);//使用Steam实现List<String> List3=list.stream().filter(s->s.startsWith("张")).filter(s->s.length()==3).collect(Collectors.toList());System.out.println(List3);}
}
Ps:
(Add1 :Java的自动装箱和拆箱机制)
注意:Java 的泛型是基于引用类型设计的,泛型类型参数必须是引用类型,不能是基本数据类型。
List
作为泛型类,其类型参数也必须是引用类型 。错误代码示范// 编译错误,泛型类型参数不能是基本数据类型
List<int> intList = new ArrayList<>();
虽然泛型不支持基本数据类型,但 Java 提供了自动装箱和拆箱机制,让基本数据类型和对应的包装类可以自动转换。Integer
是 int
的包装类,当你把 int
类型的值添加到 List<Integer>
中时,Java 编译器会自动将 int
装箱为 Integer
import java.util.ArrayList;
import java.util.List;public class AutoboxingExample {public static void main(String[] args) {List<Integer> integerList = new ArrayList<>();// 自动装箱:int 类型的值 1 被装箱为 Integer 对象integerList.add(1); int num = integerList.get(0); // 自动拆箱:Integer 对象被拆箱为 int 类型的值System.out.println(num); }
}
整数类型
基本数据类型 | 包装类 | 描述 |
---|---|---|
byte | Byte | 8 位有符号整数,取值范围是 -128 到 127。 |
short | Short | 16 位有符号整数,取值范围是 -32768 到 32767。 |
int | Integer | 32 位有符号整数,取值范围是 -2147483648 到 2147483647。 |
long | Long | 64 位有符号整数,取值范围是 -9223372036854775808 到 9223372036854775807。需要注意的是,在给 long 类型的变量赋值时,如果值超过了 int 的范围,需要在数字后面加上 L 或 l ,例如 long num = 1234567890123L; 。 |
浮点类型
基本数据类型 | 包装类 | 描述 |
---|---|---|
float | Float | 单精度 32 位浮点数。在给 float 类型的变量赋值时,需要在数字后面加上 F 或 f ,例如 float num = 3.14F; 。 |
double | Double | 双精度 64 位浮点数,是 Java 中默认的浮点类型,例如 double num = 3.14; 。 |
字符类型
基本数据类型 | 包装类 | 描述 |
---|---|---|
char | Character | 表示单个 16 位 Unicode 字符,用单引号括起来,例如 char c = 'A'; 。 |
布尔类型
基本数据类型 | 包装类 | 描述 |
---|---|---|
boolean | Boolean | 表示布尔值,只有两个取值:true 和 false 。 |