目录
7.7.2ArrayList集合存储HashMap元素并遍历
7.7.3 HashMap集合存储ArrayList元素并遍历
本篇基于对课程的记录与想法
1.异常
1.1 异常概述
异常:就是程序出现了不正常的情况
异常体系:
Error:问题严重,不需要处理
Exception:称为异常类,他表示程序本身可以处理的问题
- RuntimeException:在编译期是不检查的,出现问题后,需要我们回来修改代码
- 非RuntimeException:编译期间就必须处理,否则不能通过编译,更无法运行
1.2 JVM的默认处理方案
如果程序出现了问题,我们没有做任何处理,最终JVM会做默认的处理
- 把异常的名称,异常原因以及异常出现的位置等信息输出在了控制台
- 程序停止执行
1.3 异常处理
如果程序出现问题,有两种方案:
- try...catch...
- throws
1.4 异常处理之try...catch...
格式:
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
执行流程:
程序从try里面的代码开始执行,出现异常,会自动生成一个异常类对象,该类对象被提交给Java运行时系统
当Java运行时系统接收到异常对象时,会到catch中寻找匹配的异常类,找到后进行异常处理,执行完毕后,程序可以继续运行
public class T1{
public static void main(String[]args){
System.out.println("开始");
method();
System.out.println("停止");
}
public static void method() {
try{
int []arr= {1,2,3};
System.out.println(arr[3]);
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
}
}
//结果
开始
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at myGame/com.T1.method(T1.java:12)
at myGame/com.T1.main(T1.java:5)
停止
1.5 Throwable的成员方法
方法名 | 说明 |
public String getMessage() | 返回此throwable的详细信息字符串2 |
public String toString() | 返回此可抛出的简短具体描述3 |
public void printStackTrace() | 把异常的所有错误信息输出在控制台1 |
1.6 编译时异常和运行时异常的区别
Java 中的异常被分为两大类:编译时异常和运行时异常,也被称为受检异常和非受检异常
所有的 RuntimeException类及其子类被称为运行时异常,其他的异常都是编译时异常
- 编译时异常:必须显示处理,否则程序就会发生错误,无法通过编译
- 运行时异常:无需显示处理,也可以和编译时异常一样处理
1.7 异常处理之throws
虽然我们通过 try...catch..可以对异常进行处理,但是并不是所有的情况我们都有权限进行异常的处理也就是说,有些时候可能出现的异常是我们处理不了的,针对这种情况,Java提供了throws的处理方案
格式:方法定义()throws 异常类名{}
throws仅仅是抛出异常与try...catch...不同
但无论是运行时异常还是编译时异常都可以在定义方法时在后面使用throws异常,但他不会做出实际的处理,真正的处理还得用try...catch...
总结:
编译时异常必须要进行处理,两种处理方案:try..catch...或者throws,如果采用throws 这种方案,将来谁调用谁处理
运行时异常可以不处理,出现问题后,需要我们回来修改代码
1.8 自定义异常
格式:
public class 异常类名 extends Exception{
无参构造
带参构造
}
案例:检查分数是否在0-100范围内的异常
//定义异常类
public ScoreException extends Exception{
public ScoreException(){}
public ScoreException(String message){
super(name);
}
}
//定义老师类
public class Teacher() throws ScoreException{
public void checkScore(int score){
if(score<0||score>100){
throw new ScoreException("你的分数有误");//要手动抛出异常
}else{
System.out.println("输入的分数正常");
}
}
}
//定义测试
public class T throws ScoreException{
public static void main(String[]args){
Scanner sc=new Scanner(System.in);
System.out.println("请输入分数:");
int score =sc.nextInt();
Teacher t=new Teacher();
try{
t.checkScore(sc);
}catch(ScoreException e){
e.printStcakTrace();
}
}
}
1.9 throws和throw的区别
throws
- 用在方法声明后,跟的是异常类名
- 表示抛出异常,由该方法的调用者来处理
- 表示出现异常的可能性,并不一定发生这些异常
throw
- 用在方法体内,跟的是异常对象名
- 表示抛出异常,在方法体内的语句处理
- 执行throw时一定抛出了某种异常
2.集合引入
集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变
集合类体系结构:
3.Collection
3.1 Collection的概述
Collection的集合概述
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元系
- JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
Interface Collection<E>
创建Collection集合的对象
- 多态的方式
- 具体的实现类ArrayList
3.2 Collection集合使用方法
方法名 | 说明 |
boolean add(E e) | 添加元素(对象直接调用) |
boolean remove(Object O) | 从集合中移除指定的元素 |
void clear() | 清空集合中的元素 |
boolean contain(Object O) | 判断集合中是否存在指定元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
3.3 集合的遍历
lterator:迭代器,集合的专用遍历方式
- lterator<E>iterator0):返回此集合中元素的选代器,通过集合的iterator0方法得到
- 迭代器是通过集合的iterator0方法得到的,所以我们说它是依赖于集合而存在的
lterator中的常用方法
- E next0:返回迭代中的下一个元索
- boolean hasNext():如果迭代具有更多元素,则返回true
Collection<String> c=new ArrayList<String>();
c.add("asd");
Iterator<String> it=c.iterator;
//while循环
while(it.hasNext()){
String s=it.next();
System.out.println(s);
}
3.4 集合的使用步骤
publie statie void main(stringll args){
Collection<String>c = new ArrayList<String>();
c.add("hello");
c.add("world");
c.add("java");
Iterator<String> it=c.iterator();
while(it.haswext()){
String s= it.next();
System.out.println(s);
}
a.创建一个集合对象c,将三个元素插入
b.进行遍历,通过集合对象获取迭代器对象
c.判断语句,通过迭代器对象的hasNext()的方法判断是否有元素,当最后一个遍历完成后,循环结束
3.5 Collection集合存储学生对象并遍历
需求:创建一个存储学生对象的集合,存储3个学生对象
//定义学生类
public class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void show(){
System.out.println(name+","+age);
}
}
public class T{
public static void main(String[]args){
//创建Collection对象
Collection<Student> c=new ArrayList<Student>();
//创建学生对象
Student s1=new Student("Jack",18);
Student s2=new Student("Nancy",16);
Student s3=new Student("Nick",19);
//把学生添加到集合
c.add(s1);
c.add(s2);
c.add(s3);
//遍历集合(迭代器方式)
Iterator<Student> it=c.iterator();
while(it.hasNext){
String s =it.next();
System.out.println(s.getName()+","+s.getAge());
}
}
}
4.List
4.1 List集合概述和特点
List集合概述
- 有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素并搜索列表中的元素
- 与Set集合不同,列表通常允许重复的元素
List集合特点
- 有序:存储和取出的元素顺序一致
- 可重复:存储的元素可以重复
同Collection遍历方式一样(迭代器对象的next方法)
4.2 List集合特有的方法
方法 | 说明 |
void add(int Index,E element) | 在此集合中的指定位置插入指定元素 |
E remove(int Index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int Index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int Index) | 返回指定索引处的元素 |
4.3 案例
创建一个存储学生对象的集合,存储3个对象
//定义学生类
public class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void show(){
System.out.println(name+","+age);
}
}
public class T{
public static void main(String[]args){
//创建List对象
List<Student> list=new ArrayList<Student>();
//创建学生对象
Student s1=new Student("Jack",18);
Student s2=new Student("Nancy",16);
Student s3=new Student("Nick",19);
//把学生添加到集合
list.add(s1);
list.add(s2);
list.add(s3);
//遍历集合(迭代器方式)
Iterator<Student> it=list.iterator();
while(it.hasNext){
String s =it.next();
System.out.println(s.getName()+","+s.getAge());
}
}
//for循环遍历
for(int i=0;i<list.length;i++){
Student s=list.get(i);
System.out.println(s.getName()+","+s.getAge())
}
}
4.4 并发修改异常
并发修改异常
- ConcurrentModificationException
产生原因
- Iterator迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致
解决方案
- 用for循环遍历,然后用集合对象做对应的操作即可
4.5 ListIterator
Listlterator:列表迭代器
- 通过List集合的listlterator()方法得到,所以说它是List集合特有的迭代器
- 用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
Listlterator中的常用方法
- Enext():返回迭代中的下一个元素
- boolean hasNext():如果迭代具有更多元素,则返回 true
- E previous():返回列表中的上一个元素
- boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true
- void add(E e):将指定的元素插入列表
import java.util.*;
public class T1{
public static void main(String[]args){
List<String> list=new ArrayList<String>();
list.add("abc");
list.add("java");
list.add("ghi");
ListIterator<String> lit=list.listIterator();
while(lit.hasNext()) {
String s=lit.next();
if(s.equals("java")) {
lit.add("jave");
}
}
System.out.println(list);
}
}
4.6 增强for循环
增强for:简化数组和Collection集合的遍历
实现lterable接口的类允许其对象成为增强型for语句的目标
它是IDK5之后出现的,其内部原理是一个lterator迭代器
格式:
for(元素数据类型变量名:数组或者Collection集合){//在此处使用变量即可,该变虽就是元素
}
范例:
int[] arr = {1,2, 3, 4, 5};for(inei : arr) {
System.out.printin(i);}
import java.util.*;
public class T1{
public static void main(String[]args){
int[] arr= {1,2,3,4,5};
for(int i:arr) {
System.out.println(i);
}
String[] strarr= {"abc","def","hig"};
for(String s:strarr) {
System.out.println(s);
}
List<String> list=new ArrayList<String>();
list.add("ABC");
list.add("DEF");
list.add("HIG");
for(String s:list) {
System.out.println(s);
}
}
}
4.7 案例
创建一个存储学生对象的集合,存储3个学生对象
//定义学生类
public class Student{
private String name;
private int age;
public Student(){}
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age=age;
}
public int getAge(){
return age;
}
public void show(){
System.out.println(name+","+age);
}
}
public class T{
public static void main(String[]args){
//创建List对象
List<Student> list=new ArrayList<Student>();
//创建学生对象
Student s1=new Student("Jack",18);
Student s2=new Student("Nancy",16);
Student s3=new Student("Nick",19);
//把学生添加到集合
list.add(s1);
list.add(s2);
list.add(s3);
//遍历集合(迭代器方式)
Iterator<Student> it=list.iterator();
while(it.hasNext){
String s =it.next();
System.out.println(s.getName()+","+s.getAge());
}
}
//for循环遍历
for(int i=0;i<list.length;i++){
Student s=list.get(i);
System.out.println(s.getName()+","+s.getAge());
}
//for增强
for(Student stu:list){
System.out.println(s.getName()+","+s.getAge());
}
}
4.8 List集合子类的特点
List集合常用子类:ArrayList,LinkedList
- ArrayList:底层数据结构是数组,查询快,增删
- LinkedList:底层数据结构是链表,查询慢,增删快
4.9 LinkedList集合的特有功能
方法名 | 说明 |
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
5.Set
5.1 Set集合概述和特点
Set集合特点
- 不包含重复元素的集合
- 没有带索引的方法,所以不能使用普通for循环遍历
5.2 哈希值
对象.hashCode()
s1.hashCode()
"hello".hashCode()
"汉字".hashCode()//汉字字符串重写了hashCode方法
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
- public int hashCode():返回对象的哈希码值
对象的哈希值特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode0方法,可以实现让不同对象的哈希值相同
5.3 HashSet集合概述和特点
HashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以是不包含重复元素的集合
5.4 HashSet集合保证元素唯一性
元素添加过程:
要保证元素的唯一性,需要重写hashCode()和equals()
Alt+insert自动生成方法
5.5 LinkedHashSet集合概述和特点
LinkedHashSet集合特点
- 哈希表和链表实现的Set接口,具有可预测的选代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺是一致的
- 由哈希表保证元素唯一,也就是说没有重复的元素
public class T1{
public static void main(String[]args){
LinkedHashSet<String> lhs=new LinkedHashSet<String>();
lhs.add("abc");
lhs.add("def");
lhs.add("hig");
for(String s:lhs) {
System.out.println(s);
}
}
}
5.6 TreeSet集合概述和特点
TreeSet集合特点
- 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以不包含重复元素的集台
public class T1{
public static void main(String[]args){
TreeSet<Integer> ts=new TreeSet<Integer>();
ts.add(20);
ts.add(150);
ts.add(120);
for(Integer i:ts) {
System.out.println(i);
}
}
}
/*运行结果
20
120
150
*/
5.7 自然排序Comparable的使用
Interface Comparable<E>
- 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
//Student类
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {}
public Student(String name,int age) {
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
public int compareTo(Student s) {
int num=this.age-s.age;
int num2=num==0?this.name.compareTo(s.name):num;
return num2;
}
}
//实际测试
public class T1{
public static void main(String[]args){
TreeSet<Student> ts=new TreeSet<Student>();
Student s1=new Student("Jack",18);
Student s2=new Student("Nancy",16);
Student s3=new Student("Nick",19);
Student s4=new Student("Nick",20);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for(Student stu:ts) {
System.out.println(stu.getName()+","+stu.getAge());
}
}
}
结论:
- 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
- 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(To)方法
5.8 比较器排序Comparator的使用
- 存储学生对象并遍历,创建TreeSet集合使用有参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
import java.util.*;
public class T1{
public static void main(String[]args){
TreeSet<Student> ts=new TreeSet<Student>(new Comparator<Student>(){
@Override
public int compare(Student s1,Student s2) {
int num=s1.getAge()-s2.getAge();
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
Student s1=new Student("Jack",18);
Student s2=new Student("Nancy",16);
Student s3=new Student("Nick",19);
Student s4=new Student("Nick",20);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for(Student stu:ts) {
System.out.println(stu.getName()+","+stu.getAge());
}
}
}
//定义学生类
public class Student {
private String name;
private int age;
public Student() {}
public Student(String name,int age) {
this.name=name;
this.age=age;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age=age;
}
public int getAge() {
return age;
}
}
结论
- 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,To2)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
5.9 案例
5.9.1 成绩排序
需求:用TreeSet集合存储多个学生信息(姓名,语文成绩,数学成绩),并遍历该集合要求:按照总分从高到低出现
import java.util.*;
public class T1{
public static void main(String[]args){
TreeSet<Student> ts=new TreeSet<Student>(new Comparator<Student>(){
@Override
public int compare(Student s1,Student s2) {
int num=s1.getChinese()+s1.getEnglish()-s2.getChinese()-s2.getEnglish();
int num2=num==0?s1.getChinese()-s2.getChinese:num;
int num3=num2==0?s1.getName().compareTo(s2.getName()):num2;
return num3;
}
});
Student s1=new Student("Jack",87,86);
Student s2=new Student("Nancy",99,96);
Student s3=new Student("Nick",91,89);
Student s4=new Student("Oracle",94,99);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for(Student stu:ts) {
System.out.println(stu.getName()+","+stu.getChinese()+","+stu.getEnglish());
}
}
}
//定义学生类
public class Student {
private String name;
private int Chinese;
private int English;
public Student() {}
public Student(String name,int Chinese,int English) {
this.name=name;
this.Chinese=Chinese;
this.English=English;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setChinese(int Chinese) {
this.Chinese=Chinese;
}
public int getChinese() {
return Chinese;
}
public void setEnglish(int English) {
this.English=English;
}
public int getEnglish() {
return English;
}
public class Student implements Comparable<Student>{
private String name;
private int Chinese;
private int English;
public Student() {}
public Student(String name,int Chinese,int English) {
this.name=name;
this.Chinese=Chinese;
this.English=English;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setChinese(int Chinese) {
this.Chinese=Chinese;
}
public int getChinese() {
return Chinese;
}
public void setEnglish(int English) {
this.English=English;
}
public int getEnglish() {
return English;
}
public int compareTo(Student s) {
int num=this.Chinese+this.English-s.Chinese-s.English;
int num2=num==0?this.Chinese-s.Chinese:num;
int num3=num2==0?this.name.compareTo(s.name):num2;
return num2;
}
public class T1{
public static void main(String[]args){
TreeSet<Student> ts=new TreeSet<Student>();
Student s1=new Student("Jack",87,86);
Student s2=new Student("Nancy",99,96);
Student s3=new Student("Nick",91,89);
Student s4=new Student("Oracle",94,99);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for(Student stu:ts) {
System.out.println(stu.getName()+","+stu.getChinese()+","+stu.getEnglish());
}
}
}
5.9.2 不重复的随机数
需求:编写一个程序,获取10个1到20之间的随机数,要求随机数不能重复
import java.util.*;
public class T1{
public static void main(String[]args){
//创建Set集合对象
Set<Integer>set =new HashSet<Integer>();
//创建随机数对象
Random r= new Random();
//判断集合的长度是不是小于10
while(set.size()<10){
//产生一个随机数,添加到集合
int number =r.nextInt( 20)+ 1;
set.add(number);
}
//遍历集合
for(Integer i:set)
System.out.print(i+" ");
}
}
//TreeSet会自动排序
6.泛型
6.1 泛型概述
泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
泛型定义格式:
- <类型>:指定一种类型的格式。这里的类型可以看成是形参
- <类型1,类型2.>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
- 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
泛型的好处
- 把运行时期的问题提前到了编译期
- 避免了强制类型转换
6.2 泛型类
泛型类的定义格式:
修饰符 class 类名<类型>{}
eg:public class Generic<T>{}
此处的T可以随便谢伟任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型
public class T1{
public static void main(String[]args){
Generic<String> g1=new Generic<String>();
g1.setT("Nick");
Generic<Integer> g2=new Generic<Integer>();
g2.setT(1500);
System.out.println(g1.getT());
System.out.println(g2.getT());
}
}
//Generic泛型类
public class Generic <T>{
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t=t;
}
}
6.3 泛型方法
泛型方法的定义格式:
格式:修饰符<类型>返回值类型方法名(类型 变量名){}
范例:public <T> void show(T t){}
6.4 泛型接口
泛型接口的定义格式:
格式:修饰符interface 接口名<类型>{}
范例:public interface Generic<T>{}
6.5 类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
- 类型通配符:<?>
- List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
- 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限
- 类型通配符上限:<?extends类型>
- List<?extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
- 类型通配符下限:<?super 类型>
- List<?super Number>:它表示的类型是Number或者其父类型
//类型通配符
List<?>list1=new ArrayList<Object>()
List<?> list2 = new ArrayList<Number>();
List<?> list3 =new ArrayList<Integer>();
System.out.println("-------");
//类型通配符上限
List<?extends Number>list4=new ArrayList<Object>()//不可行
List<? extends Number> list5 = new ArrayList<Number>();
List<?extends Number> list6 =new ArrayList<Integer>();
System.out.println("-------");
//类型通配符下限:<?super 类型>
List<?super Number>list7 = new ArrayList<Object>();//不可行
List<? super Number>list8 = new ArrayList<Number>();
List<? super Number> list9 = new ArrayList<Integer>();//不可行
6.6 可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
- 格式:修饰符返回值类型 方法名(数据类型..变量名){}。
- 范例:publicstaticintsum(int...a){}
可变参数注意事项
- 这里的变量其实是一个数组
- 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
public class T1{
public static void main(String[]args){
System.out.println(sun(10));
System.out.println(sun(10,20));
System.out.println(sun(10,20,30));
System.out.println(sun(10,20,30,40));
System.out.println(sun(10,20,30,40,60));
System.out.println(sun(10,20,30,40,50,60,70));
}
public static int sun(int...a) {
int num=0;
for(int n:a) {
num+=n;
}
return num;
}
}
6.7 可变参数的应用
Arrays工具类中有一个静态方法:
- public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
- 返回的集合不能做增删操作,可以做修改操作
List接口中有一个静态方法:
- public static <E>List<E> of([E..elements):返回包含任意数量元素的不可变列表
- 返回的集合不能做增删改操作
Set接口中有一个静态方法:
- public static <E>Set<E>of([... elements):返回一个包含任意数量元素的不可变集合
- 在给元素的时候,不能给重复的元素
- 返回的集合不能做增删操作,没有改的方法
7.Map
7.1 Map集合的概述和使用
Map集合概述
- Interface Map<K,V> K:键的类型;V:值的类型
- 将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
- 如果键一样的情况下添加元素,后一个元素会覆盖前一个元素
- 输入的类型不能是原始数据类型
- HashMap:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需 要重写键的hashCode()方法、equals()方法。
- LinkedHashMap:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链 表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的 hashCode()方法、equals()方法。
tips:Map接口中的集合都有两个泛型变量,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量的数 据类型可以相同,也可以不同。
创建Map集合的对象
- 多态的方式
- 具体实现类HashMap
举例:
import java.util.Map;
import java.util.HashMap;
public class T1{
public static void main(String[]args){
Map<String,String> map=new HashMap<>();
map.put("001", "Nick");
map.put("002", "Nancy");
System.out.println(map);
}
}
//运行结果:{001=Nick, 002=Nancy}
7.2 Map集合的基本功能
方法 | 说明 |
V put(K key,V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素,返回value值 |
void clear() | 移除所有键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
7.3 Map集合的获取功能
方法 | 说明 |
V get(object key) | 根据键获取值 |
Set<K>keySet() | 获取所有键的集合 |
Collection<V> values() | 获取所有值的集合 |
Set<Map.Entry<K,V>>entrySet() | 获取所有键值对对象的集合 |
演示代码:
import java.util.*;
public class T1{
public static void main(String[]args){
Map<Integer,String> map=new HashMap<>();
map.put(001, "Nick");
map.put(002, "Nancy");
map.put(003,"Creaty");
System.out.println(map.get(001));
System.out.println(map.get(002));//Nick Nancy
Set<Integer> keySet=map.keySet();
for(int a:keySet) {
System.out.print(a+" ");//1 2 3
}
Collection<String> values=map.values();
for(String s:values) {
System.out.print(s+" ");//Nick Nancy Creaty
}
}
}
7.4 Map集合遍历键找值方法
键找值方式:即通过元素中的键,获取键所对应的值
分析步骤:
- 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示: keyset()
- 遍历键的Set集合,得到每一个键。
- 根据键,获取键所对应的值。方法提示: get(K key)
演示代码:
import java.util.*;
public class T1{
public static void main(String[]args){
Map<Integer,String> map=new HashMap<>();
map.put(001, "Nick");
map.put(002, "Nancy");
map.put(003,"Creaty");
Set<Integer> keys = map.keySet();
// 遍历键集 得到 每一个键
for (Integer key : keys) {
//key 就是键
//获取对应值
String value = map.get(key);
System.out.println(key+"是"+value);
}
}
}
7.5 Entry键值对对象
我们已经知道, Map 中存放的是两种对象,一种称为key(键),一种称为value(值),它们在在 Map 中是一一对应关 系,这一对对象又称做 Map 中的一个 Entry(项) 。
Entry 将键值对的对应关系封装成了对象。即键值对对象,这 样我们在遍历 Map 集合时,就可以从每一个键值对( Entry )对象中获取对应的键与对应的值。
既然Entry表示了一对键和值,那么也同样提供了获取对应键和对应值得方法:
- public K getKey() :获取Entry对象中的键。
- public V getValue() :获取Entry对象中的值。
在Map集合中也提供了获取所有Entry对象的方法:
- public Set> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。
7.6 Map集合遍历键值对方式
键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。
操作步骤:
- 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示: entrySet() 。
- 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。
import java.util.*;
import java.util.Map.Entry;
public class T1{
public static void main(String[]args){
HashMap<Integer, String> map = new HashMap<Integer,String>();
// 添加元素到集合
map.put(1, "Nick");
map.put(2, "Nancy");
map.put(3, "Creaty");
// 获取 所有的 entry对象 entrySet
Set<Entry<Integer, String>> entrySet = map.entrySet();
// 遍历得到每一个entry对象
for (Entry<Integer, String> entry : entrySet) {
// 解析
int key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"是:"+value);
}
}
}
//或者
import java.util.*;
import java.util.Map.Entry;
public class T1{
public static void main(String[]args){
Map<Integer, String> map = new HashMap<Integer,String>();
// 添加元素到集合
map.put(1, "Nick");
map.put(2, "Nancy");
map.put(3, "Creaty");
// 获取 所有的 entry对象 entrySet
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
// 遍历得到每一个entry对象
for (Map.Entry<Integer, String> entry : entrySet) {
// 解析
int key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"是:"+value);
}
}
}
7.7案例
7.7.1HashMap集合存储学生对象并遍历
创建一个HashMap集合,键是学号,值是学生对象,存储三个键值对元素,并遍历
import java.util.*;
import java.util.Map.Entry;
public class T1{
public static void main(String[]args){
HashMap<Integer, Student> map = new HashMap<Integer,Student>();
//创建学生对象
Student s1=new Student("Nick",99,81);
Student s2=new Student("Nancy",96,85);
Student s3=new Student("Creaty",90,92);
// 添加元素到集合
map.put(10001, s1);
map.put(10002, s2);
map.put(10003, s3);
//方法1:键找值
Set<Integer> keySet=map.keySet();
for(int key:keySet) {
Student value=map.get(key);
System.out.println(key+":"+value.getName()+","+value.getChinese()+","+value.getEnglish());
}
System.out.println("------------");
//方法2:键值对对象找键和值
Set<Map.Entry<Integer, Student>> entrySet = map.entrySet();
for (Map.Entry<Integer, Student> entry : entrySet) {
int key = entry.getKey();
Student value = entry.getValue();
System.out.println(key+":"+value.getName()+","+value.getChinese()+","+value.getEnglish());
}
}
}
/*运行结果
10001:Nick,99,81
10002:Nancy,96,85
10003:Creaty,90,92
------------
10001:Nick,99,81
10002:Nancy,96,85
10003:Creaty,90,92
*/
//学生类
public class Student {
private String name;
private int Chinese;
private int English;
public Student() {}
public Student(String name,int Chinese,int English) {
this.name=name;
this.Chinese=Chinese;
this.English=English;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setChinese(int Chinese) {
this.Chinese=Chinese;
}
public int getChinese() {
return Chinese;
}
public void setEnglish(int English) {
this.English=English;
}
public int getEnglish() {
return English;
}
}
7.7.2ArrayList集合存储HashMap元素并遍历
创建一个ArrayList集合,存诸三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历
import java.util.*;
import java.util.Map.Entry;
public class T1{
public static void main(String[]args){
ArrayList<HashMap<String,String>> array=new ArrayList<HashMap<String,String>>();
//创建hashmap集合,并添加键值对元素
HashMap<String,String> hm1=new HashMap<String,String>();
hm1.put("aaa", "bbb");
hm1.put("ddd", "eee");
array.add(hm1);
HashMap<String,String> hm2=new HashMap<String,String>();
hm1.put("zzz", "xxx");
hm1.put("ggg", "jjj");
array.add(hm2);
HashMap<String,String> hm3=new HashMap<String,String>();
hm1.put("ppp", "qqq");
hm1.put("mmm", "nnn");
array.add(hm3);
for(HashMap<String,String> hm:array) {
Set<String> keySet=hm.keySet();
for(String key:keySet) {
String value=hm.get(key);
System.out.println(key+","+value);
}
}
}
}
7.7.3 HashMap集合存储ArrayList元素并遍历
import java.util.*;
import java.util.Map.Entry;
public class T1{
public static void main(String[]args){
HashMap<String,ArrayList<String>> hm=new HashMap<String,ArrayList<String>>();
//创建ArrayList集合并添加元素
ArrayList<String> arr1=new ArrayList<String>();
arr1.add("aaa");
arr1.add("bbb");
arr1.add("ccc");
hm.put("小写字母", arr1);
ArrayList<String> arr2=new ArrayList<String>();
arr2.add("AAA");
arr2.add("BBB");
arr2.add("CCC");
hm.put("大写字母", arr2);
//遍历HashMap集合
Set<String> keySet=hm.keySet();
for(String key:keySet) {
System.out.println(key);
ArrayList<String> value=hm.get(key);
for(String s:value) {
System.out.println("\t"+s);
}
}
}
}
/*
*
小写字母
aaa
bbb
ccc
大写字母
AAA
BBB
CCC*/
7.8 Map集合练习
需求: 计算一个字符串中每个字符出现次数。
分析:
- 获取一个字符串对象
- 创建一个Map集合,键代表字符,值代表次数。
- 遍历字符串得到每个字符
- 判断Map中是否有该键
- 如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
- 打印最终结果
方法1:
public class MapTest {
public static void main(String[] args) {
//友情提示
System.out.println("请录入一个字符串:");
String line = new Scanner(System.in).nextLine();
// 定义 每个字符出现次数的方法
findChar(line);
}
private static void findChar(String line) {
//1:创建一个集合 存储 字符 以及其出现的次数
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
//2:遍历字符串
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
//判断 该字符 是否在键集中
if (!map.containsKey(c)) {//说明这个字符没有出现过
//那就是第一次
map.put(c, 1);
} else {
//先获取之前的次数
Integer count = map.get(c);
//count++;
//再次存入 更新
map.put(c, ++count);
}
}
System.out.println(map);
}
}
方法2(优化):
import java.util.*;
public class MapTest {
public static void main(String[] args) {
//友情提示
System.out.println("请录入一个字符串:");
String line = new Scanner(System.in).nextLine();
//创建TreeMap集合,键是Character,值是Integer
TreeMap<Character,Integer> hm=new TreeMap<Character,Integer>();
//遍历字符串,得到每一个字符
for(int i=0;i<line.length();i++) {
char key=line.charAt(i);
//得到的每一个字符作为键去找对应值
Integer value=hm.get(key);
if(value==null) {
hm.put(key, 1);
}else {
value++;
hm.put(key, value);
}
}
StringBuilder sb=new StringBuilder();
Set<Character> keySet=hm.keySet();
for(Character key:keySet) {
Integer value=hm.get(key);
sb.append(key).append("(").append(value).append(")");
}
String s=sb.toString();
System.out.println(s);
}
}