本模块学习Java语言中常用API、String类、集合和泛型、并掌握内存中增删改查操作
以下博客是根据黑马视频写的Javase全集博客笔记:黑马程序员全套Java教程_Java基础入门视频教程,零基础小白自学Java必备教程
(一)Java语言基础
(二)Java面向对象编程
(三)Java核心类库之(常用API、字符串类、集合类、泛型)
(四) Java核心类库之(异常机制)
(五)Java核心类库之(字符集/编码集、File类、递归、IO流:字节流、字符流、特殊操作流)
(六)Java核心类库之(类加载器、反射机制、模块化)
(七)Java核心类库之(Lambda表达式)
(八)Java核心类库之(接口组成更新、方法引用、函数式接口)
(九)Java核心类库之(Stream流:生成、中间、终结、收集操作)
(十)Java核心类库之(多线程:实现多线程、线程同步)
(十一)Java核心类库之(网络编程:网络编程入门、UDP通信程序、TCP通信程序)
1 常用API
API(:Application Programming Interface ):应用程序编程接口
1.1 Math类
Math中没有构造方法,类的成员都是静态的(static修饰),通过类名就可以直接调用
常用方法
方法名 说明
public static int abs(int a) 获取参数a的绝对值
public static double ceil(double a) [ce’l] 向上取整
public static double floor(double a) 向下取整
public static long round(double a) 四舍五入取整
public static int max(int a,int b) 返回两个数中较大值
public static int min(int a,int b) 返回两个数中较小值
public static double pow(double a,double b) 获取a的b次幂
public static double random() 返回值为double类型随机数 [0.0~1.0)
范例
public class MathDemo { public static void main(String[] args) { //1、public static int abs(int a) 获取参数a的绝对值 System.out.println(Math.abs(88)); //88 System.out.println(Math.abs(-88)); //88 //2、public static double ceil(double a) 向上取整 System.out.println(Math.ceil(12.34)); //13.0 System.out.println(Math.ceil(12.56)); //13.0 //3、public static double floor(double a) 向下取整 System.out.println(Math.floor(12.34)); //12.0 System.out.println(Math.floor(12.56)); //12.0 //4、public static long round(double a) 四舍五入取整 System.out.println(Math.round(12.34)); //12 System.out.println(Math.round(12.56)); //13 //5、public static int max(int a,int b) 返回两个数中较大值 System.out.println(Math.max(66,88)); //88 //6、public static int min(int a,int b) 返回两个数中较小值 System.out.println(Math.min(66,88)); //66 //7、public static double pow(double a,double b) 获取a的b次幂 System.out.println(Math.pow(2.0,3.0)); //8.0 //8、public static double random() 返回值为double类型随机数 [0.0~1.0) System.out.println(Math.random()); //0.36896250602163483 System.out.println(Math.random()); //0.3507783145075083 } }
1.2 System类
System被静态修饰,通过类名访问
常用方法
方法名 说明
public static void exit(int status) 终止JVM虚拟机,非 0 是异常终止
public static long currentTimeMillis() 返回当前时间(以毫秒为单位)
范例
import java.text.SimpleDateFormat; public class SystemDemo { public static void main(String[] args) { /* System.out.println("开始"); //开始 //1、public static void exit(int status) 终止JVM虚拟机,非 0 是异常终止 System.exit(0); System.out.println("结束"); //没有输出结束 */ //2、public static long currentTimeMillis() 返回当前时间(以毫秒为单位) System.out.println(System.currentTimeMillis()); //1625491582918 long time = System.currentTimeMillis(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a"); System.out.println(sdf.format(time)); //2021年07月05日 21:26:22 星期一 下午 } }
1.3 Object类
Object 类是 Java 中的祖宗类,所有类都直接或者间接继承自该类
只有无参构造方法:public Object()
常用方法:
1、public String toString()
默认是返回当前对象在堆内存中的地址信息
直接输出对象名称,默认会调用 toString()方法,所以直接输出对象可以省略 toString()
所以 toString() 存在的意义是为了被子类重写,以便能够返回对象的数据内容输出
重写快捷键:按下Fn+Alt+Insert / 右键 -> generate -> toString -> OK
看方法的源码:选中方法,按Ctrl+B
package ceshi; public class Student extends Object{ private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } //自动生成重写toString()方法;按下Fn+Alt+Insert / 右键 -> generate -> toString -> OK @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
package ceshi; public class ObjectDemo { public static void main(String[] args) { Student s = new Student(); s.setName("yy"); s.setAge(20); System.out.println(s); //ceshi.Student@1b6d3586 System.out.println(s.toString()); //ceshi.Student@1b6d3586 //重写后输出 /*源码 Student{name='yy', age=20} Student{name='yy', age=20}*/ //选中方法Ctrl+B查看方法源码 /*public void println(Object x) { //1、x = s String s = String.valueOf(x); synchronized (this) { print(s); newLine(); } }*/ /*public static String valueOf(Object obj) { //2、obj = x return (obj == null) ? "null" : obj.toString(); }*/ /*public String toString() { //3、 return getClass().getName() + "@" + Integer.toHexString(hashCode()); //所以重写前才会输出ceshi.Student@1b6d3586 }*/ } }
2、public boolean equals(Object o)
默认是比较两个对象的地址是否相同,相同返回true
直接比较两个对象的地址是否完全相同,可以用"=="替代equals
所以 equals 存在的意义是为了被子类重写
重写快捷键:按下Fn+Alt+Insert -> generate -> equals() and hashCode() -> Template:选择 IntelliJ default -> 三个next > finsh ;然后删除hashCode()方法
package ceshi; public class Student extends Object{ private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } //自动生成重写equals()方法 @Override public boolean equals(Object o) { if (this == o) return true; //1、比较地址是否相同,如果相同就是同一个对象,直接返回true //2、先判断参数是否为null;判断连个对象是否来自同一个类;一个满足就返回false if (o == null || getClass() != o.getClass()) return false; //向下转型 Student student = (Student) o; //student = s2; //3、比较年龄是否相同,年龄相同往下走 if (age != student.age) return false; //比较名字是否相同,s1的name不是null才能取调方法 return name != null ? name.equals(student.name) : student.name == null; } }
package ceshi; public class ObjectDemo { public static void main(String[] args) { Student s1 = new Student(); s1.setName("yy"); s1.setAge(20); Student s2 = new Student(); s2.setName("yy"); s2.setAge(20); //比较两个对象内容是否相等 System.out.println(s1.equals(s2)); //重写前:false ; 重写后:true /*public boolean equals(Object obj) { //this---s1 //obj---s2 return (this == obj); //重写前==比较的是地址值,不是内容需要重写equals()方法 }*/ } }
1.4 Objects类
Objects类是 jdk 1.7 开始之后才有的
常用方法
方法名 说明
public static boolean equals(Object a, Object b) 比较两个对象内容是否相等
public static boolean isNull(Object obj) 判断变量是否为 null , 为 null 返回 true
public class ObjectsDemo { public static void main(String[] args) { Student s1 = new Student(); Student s2 = new Student(); System.out.println(s1.equals(s2)); System.out.println(Objects.equals(s1,s2)); // true // true //询问s1是否为null,为null返回true System.out.println(Objects.isNull(s1)); } }
1.5 Arrays类
Arrays类包含用于操作数组的各种方法
工具类的设计思想
构造方法用 private 修饰(防止外界创建对象)
成员用 public static 修饰(使用类名来访问)
常用方法
方法名 说明
public static String toString(int[] a) 返回指定数组的内容的字符串表示形式
public static void sort(int[] a) 按照数字排序指定的数组
冒泡排序
package ceshi; public class ArrayDemo { public static void main(String[] args) { int[] arr = {21,56,15,89,62}; System.out.println("排序前:"+arrayToString(arr)); //排序前:[21, 56, 15, 89, 62] //冒泡排序 for(int i=0;i<arr.length-1;i++) { for(int x=0;x< arr.length-1-i;x++) { if(arr[x] > arr[x+1]) { //当前一个大于后一个时,双方交换位置 int temp = arr[x]; arr[x] = arr[x+1]; arr[x+1] = temp; } } } System.out.println("排序后:"+arrayToString(arr)); //排序后:[15, 21, 56, 62, 89] } public static String arrayToString(int[] arr) { StringBuilder sb = new StringBuilder(); sb.append("["); for(int i=0;i<arr.length;i++) { if(i==arr.length-1) { sb.append(arr[i]); }else { sb.append(arr[i]).append(", "); } } sb.append("]"); String s = sb.toString(); return s; } }
Arrays方法范例
package ceshi; import java.util.Arrays; public class ArrayDemo { public static void main(String[] args) { int[] arr = {21,56,15,89,62}; //1、public static String toString(int[] a) 返回指定数组的内容的字符串表示形式 System.out.println("排序前:"+ Arrays.toString(arr)); //排序前:[21, 56, 15, 89, 62] //2、public static void sort(int[] a) 按照数字排序指定的数组 Arrays.sort(arr); System.out.println("排序后:"+Arrays.toString(arr)); //排序后:[15, 21, 56, 62, 89] } }
1.6 基本类型包装类
将基本数据类型封装成对象的好处在于在对象中定义更多的功能方法操作该数据
常用的操作之一:用于基本数据类型与字符串之间的转换
基本数据类型 包装类
byte Byte
short Short
int Integer(重点)
long Long
float Float
double Double
char Character(特殊)
boolean Boolean
1.6.1 Integer类概述和使用
Integer:包装一个对象中原始类型int的值
常用方法
方法名 说明
public static Integer vlaueOf(int i) 返回表示指定的int值的 Integer 实例
public static Integer vlaueOf(String s) 返回一个保存指定的 Integer 对象 String
public class IntegerDemo { public static void main(String[] args) { //1、public static Integer vlaueOf(int i) 返回表示指定的int值的 Integer 实例 Integer i1 = new Integer(100); System.out.println(i1); //100 //2、public static Integer vlaueOf(String s) 返回一个保存指定的 Integer 对象 String Integer i2 = new Integer("100"); // Integer i2 = new Integer("abc"); 报错,NumberFormatException System.out.println(i2); //100 } }
1.6.2 int 和 String 的相互转换
1、int 转换为 String 类型
public static String valueOf(int i):返回 int 参数的字符串表示形式。该方法是 String 类中的方法
2、String 转换为 int 类型
public static int parselnt(String s):将字符串解析为int类型。该方法是 Integer 类中的方法
package ceshi; public class IntegerDemo { public static void main(String[] args) { //int --- String int number = 10; //1、public static String valueOf (int i) String s = String.valueOf(number); System.out.println(s); //10 //String --- int String s1 = "100"; //2、public static int parseInt(String s) int i = Integer.parseInt(s1); System.out.println(i); //100 } }
1.6.3 案例:字符串中数据排序
package ceshi; import java.util.Arrays; public class IntegerTest { public static void main(String[] args) { String s = "15 8 45 32 21"; String[] strArray = s.split(" "); //以空格进行分割符传入数组 /*for(int i=0;i< strArray.length;i++) { System.out.print(strArray[i]+" "); //15 8 45 32 21 }*/ int[] arr = new int[strArray.length]; for (int i = 0; i < arr.length; i++) { arr[i] = Integer.parseInt(strArray[i]); //String 类型转换为int类型再赋值 } Arrays.sort(arr); StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { if (i == arr.length - 1) { sb.append(arr[i]); } else { sb.append(arr[i]).append(", "); } } String s1 = sb.toString(); System.out.println(s1); //8, 15, 21, 32, 45 } }
1.6.4 自动装箱和拆箱
自动装箱: 可以直接把基本数据类型的值或变量赋值给包装类
自动拆箱: 可以把包装类的变量直接赋值给基本数据类型
public class PackageClass { public static void main(String[] args) { //基本数据类型的值或变量赋值给包装类 Integer i = Integer.valueOf(100); //手动调方法装箱 Integer ii = 100; //默认调用Integer.valueOf(100); //拆箱 int i1 = ii; //自动拆箱,100 ii +=200; // System.out.println(ii) //300 //开发中如果是引用类型变量最好先做不为null判断 Integer iii = null; if(iii != null) { iii += 300; //NullPointerException } } }
注意:在使用包装类的时候,如果是操作最好先判断是否为null;推荐只要是对象,再使用前必须进行不为null判断
1.7 日期类
1.7.1 Date类
导包:java.util.Date
构造方法
方法名 说明
public Date() 创建当前系统的此刻日期时间对象
public Date(long time) 把时间毫秒值转换成日期对象
package ceshi; import java.util.Date; public class DateDemo { public static void main(String[] args) { //1、public Date() Date d1 = new Date(); System.out.println(d1); //Tue Jul 06 22:36:15 CST 2021 //2、public Date(long time) long date = 60; Date d2 = new Date(date); System.out.println(d2); //Thu Jan 01 08:00:00 CST 1970 } }
常用方法
方法名 说明
public long getTime() 获取日期对象从1970年1月1日00:00:00 到现在的毫秒值
public void setTime(long time) 设置时间,给的是毫秒值
package ceshi; import java.util.Date; public class DateDemo { public static void main(String[] args) { //1、public long getTime() 获取日期对象从1970年1月1日00:00:00 到现在的毫秒值 Date d = new Date(); System.out.println(d.getTime()); //1625582796041 //2、public void setTime(long time) 设置时间,给的是毫秒值 long time = 1000*60*60; d.setTime(time); System.out.println(d); //Thu Jan 01 09:00:00 CST 1970 } }
1.7.2 SimpleDateFormat类 [ˈsɪmpl]
可以对日期格式化和解析
日期和时间格式由日期和时间模式字符串指定,在日期和时间模式字符串中,从 ‘A’ 到 ‘Z’ 以及从 ‘a’ 到’z’ 引号的字母被解释为表示日期或时间字符串的组件的模式字母
常用的模式字母对应: y—年;M—月;d—日;H—时;m—分;s—秒;E—星期几;a—上午 / 下午
构造方法:
方法名 说明
public SimpleDateFormat() 使用默认模式和日期模式
public SimpleDateFormat(String pattern) 指定时间的格式创建简单日期格式化对象
格式化和解析日期方法
方法名 说明
public String format(Date date) 将日期格式化为日期 / 时间字符串
public String format(Object time) 将时间毫秒格式化为日期 / 时间字符串
public Date parse(String source) [pɑːz] 从给定的字符串开始解析文本生成日期
package ceshi; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class SimpleDateFormatDemo { public static void main(String[] args) throws ParseException { //格式化 Date》String Date d = new Date(); //1、 SimpleDateFormat sdf = new SimpleDateFormat(); //无参构造 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E a"); //2、带参构造 String s = sdf.format(d); System.out.println(s); //1、21-7-11 上午10:13 2、2021年07月11日 10:16:00 星期日 上午 //解析 String > date String s1 = "2020年1月1日 8:25:12"; SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); Date d1 = sdf1.parse(s1); //parse报错了,选中按下Alt+enter,默认选第一个 System.out.println(d1); //Wed Jan 01 08:25:12 CST 2020 } }
1.7.3 日期工具类
package ceshi; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /* 工具类 构造方法私有 成员方法静态 */ public class DateUtils { private DateUtils() { } //时间对象格式化 public static String dateToString(Date date, String format) { SimpleDateFormat sdf = new SimpleDateFormat(format); String s = sdf.format(date); return s; } //给定日期字符串解析为时间对象 public static Date stringDate(String s,String formart) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat(formart); Date d = sdf.parse(s); return d; } }
package ceshi; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateDemo { public static void main(String[] args) throws ParseException { Date d = new Date(); String s = DateUtils.dateToString(d, "yyyy年MM月dd日 HH:mm:ss"); System.out.println(s); //2021年07月07日 20:46:08 String s1 = "2022年12月5日"; Date d1 = DateUtils.stringDate(s1, "yyyy年MM月dd日"); System.out.println(d1); //Mon Dec 05 00:00:00 CST 2022 } }
1.7.4 Calendar日历类
Calendar 代表了系统此刻日期对应的日历对象
Calendar 是一个抽象类,不能直接创建对象
常用方法
方法名 说明
public static Calendar getInstance() 返回一个日历类的对象
public int get(int field) 返回给定日历的值
public void set(int field,int value) 修改日历的某个字段信息
public abstract void add(int field,int amount) 根据日历的规则,将指定的时间量添加或减去给定的日历字段
public final void set(int year,int month,int date) 设置当前日历年月日
package ceshi; import java.util.Calendar; public class CalendarDemo { public static void main(String[] args) { //1、获取Calendar对象 Calendar c = Calendar.getInstance(); //多态形式 //2、public int get (int field) 根据给的日历字段返回值 /* int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; //从0开始所以加个1 int date = c.get(Calendar.DATE); System.out.println(year+"年"+month+"月"+date+"日"); //2021年7月7日*/ //3、public void set(int field,int value) 修改日历的某个字段信息 //c.set(Calendar.YEAR,2099); // System.out.println(rightNow.get(Calendar.YEAR)); //2099 //4、public abstract void add(int field,int amount):根据日历的规则,将指定的时间量添加或减去给定的日历字段 //需求1:三年前 /* c.add(Calendar.YEAR,-3); int year = c.get(Calendar.YEAR); System.out.println(year); //2018,减了三年*/ //需求2:十年后,五天前 /*c.add(Calendar.YEAR,10); c.add(Calendar.DATE,-5); System.out.println(); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int date = c.get(Calendar.DATE); System.out.println(year+"年"+month+"月"+date+"日"); //2031年7月2日*/ //5、public final void set(int year,int month,int date):设置当前日历年月日 c.set(2022,1,1); int year = c.get(Calendar.YEAR); int month = c.get(Calendar.MONTH) + 1; int date = c.get(Calendar.DATE); System.out.println(year+"年"+month+"月"+date+"日"); //2022年2月1日 } }
2 String类
2.1 String概括
String 类 在java.lang包下,所以使用的时候不需要导包
java程序中所有的双引号字符串,都是String这个类的对象
特点:字符串不可变,它们的值在创建后不可改变
2.2 String构造方法
方法名 说明
public String() 创建一个空字符串对象,不包含任何内容
public String(chas[] chs) 根据字符数组内容,来创建字符串对象
public String(byte[] bys) 根据字节数组内容,来创建字符串对象
String s = “abc”; 直接赋值的方法创建字符串对象,内容就是abc
推荐使用直接赋值的方式
案例:
public class Demo{ public static void main(String[] args){ //1.public String() 创建一个空字符串对象,不包含任何内容 String s1 = new String(); System.out.println("s1:"+s1); //s1:(无内容) //2.public String(chas[] chs) 根据字符数组内容,来创建字符串对象 char[] chs = {'a','b','c'}; String s2 = new String(chs); System.out.println("s2:"+s2); //s2:abc //3.public String(byte[] bys) 根据字节数组内容,来创建字符串对象 byte[] bys = {97,98,99}; //对应计算机底层字符 String s3 = new String(bys); System.out.println("s3:"+s3); //s3:abc //4.String s = “abc”; 直接赋值的方法创建字符串对象,内容就是abc String s4 = "abc"; System.out.println("s4:"+s4); //s4:abc } }
2.3 String对象的区别
1.通过 new 创建字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同
2.以 “ ” 方式给出的字符串,只要字符串的序列相同(顺序和大小写),无论在程序中出现多少次,JVM都只会建立一个String对象,并在字符串池维护
内存
2.4 常考面试题
问题1:
问题2:
问题3:
问题4:
2.5 String字符串比较
使用双等号作比较
基本类型:比较的是数据值是否相同
引用类型:比较的是地址值是否相同
字符串是对象,它比较内容是否相同,是通过一个方法来实现的,这个方法叫做: equals()
范例:
public class Demo{ public static void main(String[] args){ //构造方法的方式得到对象 char[] chs = {'a','b','c'}; String s1 = new String(chs); String s2 = new String(chs); //直接赋值的方法得到对象 String s3 = "abc"; String s4 = "abc"; System.out.println(s1.equals(s2)); //true System.out.println(s1.equals(s3)); //true System.out.println(s3.equals(s4)); //true } }
2.6 案例
2.6.1 案例:用户登录
import java.util.Scanner; public class Demo{ public static void main(String[] args){ //1 String username = "YM"; String password = "123456"; Scanner sc = new Scanner(System.in); //4 for(int i=1;i<=3;i++) { //2 System.out.println("请输入用户名"); String name = sc.nextLine(); System.out.println("请输入密码"); String pwd = sc.nextLine(); //3 if(name.equals(username)&& pwd.equals(password)) { System.out.println("登录成功"); break; }else { if (3-i==0){ System.out.println("你的账户被锁定"); }else { System.out.println("登陆失败,你还有"+(3-i)+"次机会"); } } } } }
2.6.2 案例:遍历字符串
import java.util.Scanner; public class Demo{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串"); String line = sc.nextLine(); for(int i=0;i<line.length();i++) { //length():获取字符串长度 System.out.println(line.charAt(i)); } } }
9.2.6.3 案例:统计字符次数
import java.util.Scanner; public class Demo{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符"); String line = sc.nextLine(); int bigCount = 0; int smallCount = 0; int numberCount = 0; //遍历字符串,得到每个字符 for(int i=0;i<line.length();i++) { char ch = line.charAt(i); //判断字符类型,统计变量+1 if(ch>='A' && ch<='Z'){ bigCount++; }else if(ch>='a' && ch<='z'){ smallCount++; }else if(ch>='0' && ch<='9'){ numberCount++; } } System.out.println("大写字母:"+bigCount+"个"); System.out.println("小写字母:"+smallCount+"个"); System.out.println("数字:"+numberCount+"个"); } }
2.6.4 案例:字符串拼接
public class Demo { public static void main(String[] args) { int[] arr = {1,2,3}; String s = arrayToString(arr); System.out.println(s); //[1, 2, 3] } public static String arrayToString(int[] arr) { String s = ""; s += "["; for(int i=0;i<arr.length;i++) { if(i== arr.length-1) { s += arr[i]; }else { s += arr[i]+", "; } } s += "]"; return s; } }
2.6.5 案例:字符串反转
import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串"); String line = sc.nextLine(); //abc String s = myReverse(line); System.out.println(s); //cba } public static String myReverse(String s) { String ss = ""; for(int i=s.length()-1;i>=0;i--) { ss += s.charAt(i); } return ss; } }
2.6.6 案例:字符串截取
public class Demo { /* 截取字符串: String substring(int beginIndex): 从传入的索引位置处向后截取,一直截取到末尾,得到新字符串并返回 String substring(int beginIndex, int endIndex): 从beginIndex索引位置开始截取,截取到endIndex索引位置,得到新字符串并返回(包括头,不包括尾) */ public static void main(String[] args){ String s = "itheima"; String ss = s.substring(2); System.out.println(ss); //heima String sss = s.substring(0,2); System.out.println(sss); //it } }
2.6.7 案例:字符串替换
//String replace(CharSequence target,Char Sequense replacement) // 第一个参数为target(被替换的旧值)内容 // 第二个参数为replacement(替换的新值)进行替换 // 返回新的字符串 import java.util.Scanner public class Demo{ public static void main(String[] args){ // 1.键盘录入一个字符串 Scanner sc = new Scanner(System.in); System.out.println("请输入:"); String s = sc.nextLine(); // 2.进行敏感提替换 String result = s.replace("TMD","***"); // 3.输出结果 System.out.println(result); } }
3 StringBuilder可变字符串类
StringBuilder是一个可变的字符串类,内容可以改变
3.1 StringBuilder构造方法
范例
public class Demo { public static void main(String[] args) { //创建空白可改变字符串对象 StringBuilder sb = new StringBuilder(); System.out.println("sb:"+sb); //sb: System.out.println("sb.length():"+sb.length()); //sb.length():0 //根据字符串内容创建对象 StringBuilder sb2 = new StringBuilder("hello"); System.out.println("sb2:"+sb2); //sb2:hello System.out.println("sb2.length():"+sb2.length()); //5 } }
3.2 StringBuilder常用方法
方法名 说明
public StringBuilder append(任意类型) 添加数据,并返回对象本身
public StringBuilder reverse() 返回相反的字符序列
public int length() 返回长度(字符出现的个数)
范例:
public class Demo { public static void main(String[] args) { //创建对象 StringBuilder sb = new StringBuilder(); //1.public StringBuilder append(任意类型) 添加数据,并返回对象本身 // StringBuilder sb2 = sb.append("java"); // System.out.println("sb:"+sb); //sb:java,因为返回的是对象本身所以sb赋值了java // System.out.println("sb2:"+sb2); //sb2:java // System.out.println(sb==sb2); //true // sb.append("java"); // sb.append("word"); // sb.append(100); // System.out.println("sb:"+sb); //sb:javaword100 //链式编程 sb.append("java").append("word").append(100); System.out.println("sb:"+sb); //sb:javaword100 //2.public StringBuilder reverse() 返回相反的字符序列 sb.reverse(); System.out.println("sb:"+sb); //sb:001drowavaj } }
3.3 StringBuilder 和 String 相互转换
1.StringBuilder 转换为 String
public String toString() 通过toString()可以把StringBuilder 转换为 String
2.String 转换为 StringBuilder
public StringBuilder(String s) 通过构造方法就可以把String 转换为 StringBuilder
范例
public class Demo { public static void main(String[] args) { //1.StringBulider 转换为 String StringBuilder sb = new StringBuilder(); sb.append("hello"); //public String toString() 通过toString()可以把StringBuilder 转换为 String String s = sb.toString(); System.out.println("s:"+s); //s:hello //2.String 转换为 StringBulider String s1 = "hello"; //public StringBuilder(String s) 通过构造方法就可以把String 转换为 StringBuilder StringBuilder sb1 = new StringBuilder(s1); System.out.println("sb1:"+sb1); //sb1:hello } }
3.4 案例
3.4.1 案例1:拼接字符串
public class Demo { public static void main(String[] args) { //1 int[] arr = {1,2,3}; String s = arrayToString(arr); System.out.println(s); //[1, 2, 3] } //2,定义方法,拼接字符串 public static String arrayToString(int[] arr) { //3 StringBuilder sb = new StringBuilder(); sb.append("["); for(int i=0;i< arr.length;i++) { if(i==arr.length-1){ sb.append(arr[i]); }else { sb.append(arr[i]).append(", "); } } sb.append("]"); String s= sb.toString(); return s; } }
3.4.2 案例2:字符串反转
import java.util.Scanner; public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个字符串"); String line = sc.nextLine(); //abc String s = myReverse(line); System.out.println(s); //cba } public static String myReverse(String s) { //在方法使用StringBuilder实现字符串反转,并把结果转换为String返回 //String - StringBuilder - reverse() - String // StringBuilder sb = new StringBuilder(s); // sb.reverse(); // // String ss = sb.toString(); // return ss; //链式编程 return new StringBuilder(s).reverse().toString(); } }
4 集合结构体系
4 集合基础
集合提供一种存储空间可变的存储模型,存储的数据容量可以改变
ArrayLis<>:
可调整大小的数组实现
<>:是一种特殊的数据类型,泛型
可储存重复元素
怎么使用呢
在出现E的地方我们使用引用数据类型替换即可
举例:ArrayList<String>、ArrayList<Student>
4.1 集合与数组的区别
共同点:都是存储数据的容器
不同点:数组的容量是固定的,集合的容量是可变的
4.2 ArrayList 构造方法和添加方法
import java.util.ArrayList; public class Demo { public static void main(String[] args) { //创建集合对象 ArrayList<String> array = new ArrayList<>(); System.out.println(array); //[] //添加到集合末尾 array.add("hello"); array.add("word"); array.add("java"); System.out.println(array); //[hello, word, java] //指定位置,添加元素 array.add(1,"javase"); System.out.println(array); //[hello, javase, word, java] array.add(4,"javaee"); System.out.println(array); //[hello, javase, word, java, javaee] array.add(6,"javaweb"); System.out.println(array); //IndexOutOfBoundsException,不能中间跳一个位置 } }
4.3 ArrayList 常用方法
方法名 说明
public boolean remove(Object o) 删除指定的元素,返回删除是否成功
public E remove(int index) 删除指定索引处的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
public E get(int index) 返回指定索引处的元素
public int size() 返回集合中元素的个数
范例:
import java.util.ArrayList; public class Demo { public static void main(String[] args) { //创建集合对象 ArrayList<String> array = new ArrayList<>(); System.out.println(array); //[] //添加到集合末尾 array.add("hello"); array.add("word"); array.add("java"); System.out.println(array); //[hello, word, java] //1,public boolean remove(Object o) 删除指定的元素,返回删除是否成功 // System.out.println(array.remove("hello")); //true; 集合变为[word, java] // System.out.println(array.remove("javase")); //false; 集合变为[hello, word, java] //2,public E remove(int index) 删除指定索引处的元素,返回被删除的元素 // System.out.println(array.remove(1)); //word,集合变为[hello, java] //3,public E set(int index,E element) 修改指定索引处的元素,返回被修改的元素 // System.out.println(array.set(1,"javase")); //word;集合变为[hello, javase, java] //4,public E get(int index) 返回指定索引处的元素 // System.out.println(array.get(0)); //hello // System.out.println(array.get(1)); //word // System.out.println(array.get(2)); //java //5,public int size() 返回集合中元素的个数 System.out.println(array.size()); //3 } }
4.4 案例
4.4.1 案例1:存储字符串并遍历
import java.util.ArrayList; public class Demo { public static void main(String[] args) { //创建集合对象 ArrayList<String> array = new ArrayList<>(); //加元素 array.add("java"); array.add("天下"); array.add("第一"); for(int i=0;i<array.size();i++) { String s = array.get(i); System.out.print(s+" "); //java 天下 第一 } } }
4.4.2 案例2:存储学生对象并遍历
package ceshi; public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } }
测试类
package ceshi; import java.util.ArrayList; public class ArrayListStudent { public static void main(String[] args) { //定义集合对象 ArrayList<Student> array = new ArrayList<Student>(); //创建学生对象 Student stu1 = new Student("小白",20); Student stu2 = new Student("小明",21); Student stu3 = new Student("小黑",22); //添加学生对象到集合中 array.add(stu1); array.add(stu2); array.add(stu3); //遍历集合 for(int i=0;i<array.size();i++) { Student s = array.get(i); System.out.println(s.getName()+","+s.getAge()); //小白,20 //小明,21 //小黑,22 } } }
4.4.3 案例3:存储学生对象并遍历升级版
测试类
package ceshi; import java.util.ArrayList; import java.util.Scanner; public class ArrayListStudent { public static void main(String[] args) { ArrayList<Student> array = new ArrayList<Student>(); for(int i=1;i<4;i++) { addStudent(array); //调三次方法 } //遍历集合 for(int i=0;i<array.size();i++) { Student s = array.get(i); System.out.println(s.getName()+","+s.getAge()); } } public static void addStudent(ArrayList<Student> array) { Scanner sc = new Scanner(System.in); System.out.println("请输入一个名字"); String name = sc.nextLine(); System.out.println("请输入一个年龄"); String age = sc.nextLine(); //创建学生对象,把键盘录入的数据赋值给学生对象的成员变量 Student stu = new Student(); stu.setName(name); stu.setAge(age); //往集合里加学生对象 array.add(stu); } }
5 Collection集合
5.1 Collection集合概述
是单列集合的顶层接口,它表示一组对象,这些对象也称Collection元素
JDK不提供此接口的直接实现,它提供更具体的子接口(Set 和 List)实现
package ceshi; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { //创建Collection集合对象 Collection<String> c = new ArrayList<String>(); //添加元素 c.add("hello"); c.add("world"); c.add("java"); System.out.println(c); //[hello, world, java] } }
5.2 Collection集合常用方法(查看所有源码快捷键)
方法名 说明
public boolean add(E e) 把给定的元素添加到当前集合中
public boolean remove(E e) 把给定的对象在当前集合中删除
public void clear() 清空集合中所有的元素
public boolean contains(Object obj) [kənˈteɪnz] 包括 判断当前集合中是否存在指定的对象
public boolean isEmpty() [ˈenpti] 判断当前集合是否为空
public int size() 返回集合中元素的个数
public Object[] toArray( ) 把集合中的元素,储存到数组中
快捷键:Alt+7 打开源码中所有方法
package ceshi; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { //创建Collection集合对象 Collection<String> c = new ArrayList<String>(); //1、public boolean add(E e) 把给定的元素添加到当前集合中 c.add("hello"); c.add("hello"); System.out.println(c); //[hello, hello] ;ArrayList可以存储重复元素 //2、public boolean remove(E e) 把给定的对象在当前集合中删除 /*System.out.println(c.remove("hello")); //true System.out.println(c.remove("java")); //false System.out.println(c); //[hello]*/ //3、public void clear() 清空集合中所有的元素 /*c.clear(); System.out.println(c); //[]*/ //4、public boolean contains(Object obj) 判断当前集合中是否存在指定的对象 /*System.out.println(c.contains("java")); //false System.out.println(c.contains("hello")); //true*/ //5、public boolean isEmpty() 判断当前集合是否为空 // System.out.println(c.isEmpty()); //false //6、public int size() 返回集合中元素的个数 // System.out.println(c.size()); //2 //7、public Object[] toArray( 把集合中的元素,储存到数组中 Object[] arr = c.toArray(); for(int i= 0;i< arr.length;i++) { System.out.print(arr[i]+","); //hello,hello } } }
5.3 Collection集合的遍历
Collection 集合遍历有三种方法:
迭代器
foreach(增强for循环)
DK 1.8 开始的新技术 Lambda 表达式(了解)
5.3.1 Iterator['lɪtəreɪtə]迭代器遍历集合
lterator:迭代器,集合的专用遍历方式
Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
迭代器是通过集合的**iterator()**方法得到的,所以我们说它是依赖于集合而存在的
Iterator中的常用方法
方法名 说明
E next() 获取迭代中的下一个元素
boolean hasNext() 如果迭代具有更多元素,则返回true
package ceshi; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class IteratorDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<String>(); c.add("java"); c.add("天下"); c.add("无敌"); //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator0方法得到 Iterator<String> it = c.iterator(); //c.iterator();按下Ctrl+alt+v /*public Iterator<E> iterator() { return new ArrayList.Itr(); //返回的是实现类的对象 } private class Itr implements Iterator<E> {...} */ //E next() /*System.out.println(it.next()); //java System.out.println(it.next()); System.out.println(it.next()); System.out.println(it.next()); //NoSuchElementException:表示请求的元素不存在*/ //boolean hasNext() 如果迭代具有更多元素,则返回true /*if(it.hasNext()) { System.out.println(it.next()); //java } if(it.hasNext()) { System.out.println(it.next()); //天下 } if(it.hasNext()) { System.out.println(it.next()); //无敌 } if(it.hasNext()) { System.out.println(it.next()); //无输出 } */ //while循环改良 while(it.hasNext()) { String s = it.next(); System.out.println(s); //java //天下 //无敌 } } }
案例
package ceshi; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class CollectionDemo { public static void main(String[] args) { //2、创建Collection集合对象 Collection<Student> c = new ArrayList<Student>(); //3、创建学生对象 Student s1 = new Student("y1", 10); Student s2 = new Student("y2", 20); Student s3 = new Student("y3", 30); //4、把学生添加到集合 c.add(s1); c.add(s2); c.add(s3); //5、遍历集合 Iterator<Student> it = c.iterator(); //必须集合添加完毕后创建迭代器对象 while (it.hasNext()) { Student s = it.next(); System.out.println(s.getName() + "," + s.getAge()); /* y1,10 y2,20 y3,30 */ } } }
5.4 Collections工具类
包:java.util.Collections
Collections 并不属于集合,而是用来操作集合的工具类
常用方法(全是静态修饰,用类名调用)
方法名 说明
public static <T extends Comparable<?super T>> void sort(List list) 将指定的列表按升序排序
public static void reverse(List<?> list) 反转指定列表中元素顺序
public static void shuffle(List<?> list) 使用默认的随机源随机排序指定的列表
package ceshi; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class MapDemo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(30); list.add(20); list.add(50); list.add(10); list.add(40); System.out.println(list); //[30, 20, 50, 10, 40] //1,public static <T extends Comparable<?super T>> void sort(List list) 将指定的列表按升序排序 /*Collections.sort(list); System.out.println(list); //[10, 20, 30, 40, 50]*/ //2,public static void reverse(List<?> list) 反转指定列表中元素顺序 /*Collections.reverse(list); System.out.println(list); //[40, 10, 50, 20, 30]*/ //3,public static void shuffle(List<?> list) 使用默认的随机源随机排序指定的列表 Collections.shuffle(list); System.out.println(list); //第一次运行[10, 40, 30, 50, 20] //第二次运行[10, 30, 20, 50, 40] } }
6 List集合
List系列集合:添加的元素是有序,可重复,有索引
ArrayList: 添加的元素是有序,可重复,有索引
LinkedList: 添加的元素是有序,可重复,有索引
Vector :是线程安全的,速度慢,开发中很少使用
6.1 List集合概述和特点
List集合概述
1、有序集合(也称为序列),用户可以精确控制列表中每个元索的插入位置。用户可以通过整数索引访问元素,并获取列表中的元素
2、与Set集合不同,List集合允许重复的元素
List集合特点
1、有序: 存储和取出的元素顺序一致
2、可重复: 存储的元素可以重复
package ceshi; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ListDemo { public static void main(String[] args) { //创建集合对象 List<String> list = new ArrayList<>(); //添加元素 list.add("java"); list.add("天下"); list.add("无敌"); list.add("java"); System.out.println(list); //[java, 天下, 无敌, java] //迭代器遍历 Iterator<String> it = list.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); /*java 天下 无敌 java*/ } } }
6.2 List集合的特有方法
方法名 说明
public void add(int index,E element) 该集合中的指定位置上插入元素
public E remove(int index) 删除列表中指定位置的元素,返回被删除的元素
public E set(int index,E element) 修改指定索引的元素,返回被修改的元素
public E get(int index) 返回集合中指定位置的元素
package ceshi; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ListDemo { public static void main(String[] args) { //创建集合对象 List<String> list = new ArrayList<>(); //添加元素 list.add("java"); list.add("天下"); list.add("无敌"); list.add("java"); System.out.println(list); //[java, 天下, 无敌, java] //1、public void add(int index,E element) 该集合中的指定位置上插入元素 list.add(1,"javase"); System.out.println(list); //[java, javase, 天下, 无敌, java] //2、public E remove(int index) 删除列表中指定位置的元素,返回被删除的元素 System.out.println(list.remove(1)); //javase System.out.println(list); //[java, 天下, 无敌, java] //3、public E set(int index,E element) 修改指定索引的元素,返回被修改的元素 System.out.println(list.set(0,"java1")); //java System.out.println(list); //[java1, 天下, 无敌, java] //4、public E get(int index) 返回集合中指定位置的元素 System.out.println(list.get(2)); //无敌 //for循环遍历 for(int i=0;i< list.size();i++) { //5,public E get(int index) 返回集合中指定位置的元素 String s = list.get(i); System.out.println(s); /*java1 天下 无敌 java*/ } } }
案例
测试类
package ceshi; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ListDemo { public static void main(String[] args) { //2、创建集合对象 List<Student> list = new ArrayList<Student>(); //3、创建学生对象 Student s1 = new Student("y1",10); Student s2 = new Student("y2",20); Student s3 = new Student("y3",30); //4、学生对象添加到集合 list.add(s1); list.add(s2); list.add(s3); //5、遍历集合:迭代器方法 Iterator<Student> it = list.iterator(); while(it.hasNext()) { Student s = it.next(); System.out.println(s.getName()+","+s.getAge()); /*y1,10 y2,20 y3,30*/ } //5、遍历集合:for循环 for(int i=0;i<list.size();i++) { Student ss = list.get(i); System.out.println(ss.getName()+","+ss.getAge()); /*y1,10 y2,20 y3,30*/ } } }
6.3 ListIterator迭代器
Lstlterator:列表迭代器
通过List集合的listterator()方法得到,所以说它是List集合特有的迭代器
用于允许程序员沿任一方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
常用方法
方法名 说明
list.listIterator() 得到 listIterator 迭代器
E next() 返回迭代中的下一个元素
boolean hasNext() 如果迭代具有更多元素,则返回true
E previous() [ˈpriːviəs] 返回列表中的上一个元素
boolean hasPrevious() 如果此列表迭代器在相反方向遍历列表时具有更多元索,则返回true
void add(E e) 将指定的元索插入列表
package ceshi; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class ListIteratorDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("java"); list.add("python"); list.add("scala"); //通过list集合的listIterator() 方法得到迭代器 /*ListIterator<String> lit = list.listIterator(); while(lit.hasNext()) { String s = lit.next(); System.out.println(s); *//*java python scala*//* } System.out.println("---------"); //逆向遍历 *//*E previous0 返回列表中的上一个元素 boolean hasPrevious() 如果此列表迭代器在相反方向遍历列表时具有更多元索,则返回true*//* while(lit.hasPrevious()) { String s = lit.previous(); System.out.println(s); *//*scala python java*//* }*/ //获取列表迭代器 ListIterator<String> lit = list.listIterator(); while(lit.hasNext()) { String s = lit.next(); if(s.equals("java")) { lit.add("world"); } } System.out.println(list); //[java, world, python, scala] } }
6.4 foreach(增强for循环)
增强for:简化数组和Collection集合的遍历
实现Iterable接口的类允许其对象成为增强型 for语句的目标
它是JDK5之后出现的,其内部原理是一个Iterator迭代器
格式
for(元素类型 变量名: 数组名或collection集合){ } //范例 int[] arr = {1,2,3,4,5}; for(int i : arr) { System.out.println(i); }
范例:
package ceshi; import java.util.ArrayList; import java.util.List; public class ForDemo { public static void main(String[] args) { //int类型数组 int[] arr = {1,2,3,4,5}; for(int i : arr) { System.out.println(i); /* 1 2 3 4 5*/ } //String类型数组 String[] strArray = {"java","python","scala"}; for(String s : strArray) { System.out.println(s); /*java python scala*/ } //集合 List<String> list = new ArrayList<>(); list.add("y1"); list.add("y2"); list.add("y3"); for(String lt:list) { System.out.println(lt); /*y1 y2 y3*/ } //判断:内部原理是一个Iterator迭代器 for(String s:list) { if(s.equals("y1")) { list.add("y4"); //ConcurrentModificationException:并发修改异常 } } } }
6.5 案例:List集合存储学生对象用三种方式遍历
package ceshi; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ListDemo { public static void main(String[] args) { List<Student> list = new ArrayList<>(); Student s1 = new Student("y1",10); Student s2 = new Student("y2",20); Student s3 = new Student("y3",30); list.add(s1); list.add(s2); list.add(s3); //迭代器方式 Iterator<Student> it = list.iterator(); while(it.hasNext()) { Student s = it.next(); System.out.println(s.getName()+","+s.getAge()); } System.out.println("----------"); //for带索引方式 for(int i =0;i<list.size();i++) { Student s = list.get(i); System.out.println(s.getName()+","+s.getAge()); } System.out.println("----------"); //增强for for(Student s: list) { System.out.println(s.getName()+","+s.getAge()); } } }
6.6 List集合子类特点
ArrayList:底层数据结构数组实现,查询快,增删慢
LinkedList:底层数据结构链表实现,查询慢,增删快
范例:分别用ArrayList和LinkedList存储字符串并遍历
package ceshi; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class ListDemo { public static void main(String[] args) { //1、创建ArrayList集合对象 ArrayList<String> arraylist = new ArrayList<>(); arraylist.add("java"); arraylist.add("python"); arraylist.add("scala"); //增强for for(String s: arraylist) { System.out.println(s); } System.out.println("-------"); //普通for循环 for(int i=0;i< arraylist.size();i++) { String s = arraylist.get(i); System.out.println(s); } System.out.println("-------"); //迭代器的方式 Iterator<String> it = arraylist.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); } System.out.println("-------"); //2、创建LinkedList集合对象 LinkedList<String> linkedList = new LinkedList<>(); linkedList.add("a"); linkedList.add("b"); linkedList.add("c"); //增强for for(String s:linkedList) { System.out.println(s); } System.out.println("-------"); //普通for for(int i=0;i< linkedList.size();i++) { String s = linkedList.get(i); System.out.println(s); } System.out.println("-------"); //迭代器 Iterator<String> it1 = linkedList.iterator(); while(it1.hasNext()) { String s = it1.next(); System.out.println(s); } } }
6.7 LinkedList集合特有方法
方法名 说明
public void addFirst(E,e) 在该列表开头插入指定的元素
public void addLast(E,e) 将指定的元索追加到此列表的末尾
public E getFirst() 返回此列表中的第一个元索
public E getLast() 返回此列表中的最后一个元素
public E removeFirst 从此列表中删除并返回第一个元素
public E removeLast 从此列表中删除并返回最后一个元素
package ceshi; import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { //创建集合对象 LinkedList<String> linkedList = new LinkedList<>(); linkedList.add("java"); linkedList.add("python"); linkedList.add("scala"); System.out.println(linkedList); //[java, python, scala] //1、public void addFirst(E,e) 在该列表开头插入指定的元素 linkedList.addFirst("1"); System.out.println(linkedList); //[1, java, python, scala] //2、public void addLast(E,e) 将指定的元索追加到此列表的末尾 linkedList.addLast("5"); System.out.println(linkedList); //[1, java, python, scala, 5] //3、public E getFirst() 返回此列表中的第一个元索 System.out.println(linkedList.getFirst()); //1 //4、public E getLast() 返回此列表中的最后一个元素 System.out.println(linkedList.getLast()); //5 //5、public E removeFirst 从此列表中删除并返回第一个元素 System.out.println(linkedList.removeFirst()); //1 System.out.println(linkedList);//[java, python, scala, 5] //6、public E removeLast 从此列表中删除并返回最后一个元素 System.out.println(linkedList.removeLast()); //5 System.out.println(linkedList); //[java, python, scala] } }
7 Set集合
7.1 Set集合的概述和特点
Set集合的特点
不包含重复元素的集合
没有带索引的方法,所以不能使用普通for循环
Set集合是接口通过实现类实例化(多态的形式)
HashSet:添加的元素是无序,不重复,无索引的
LinkedHashSet: 添加的元素是有序,不重复,无索引的
TreeSet: 不重复,无索引,按照大小默认升序排列
package ceshi; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class SetDemo { public static void main(String[] args) { //创建Set集合对象 Set<String> set = new HashSet<>(); //添加元素 set.add("java"); set.add("python"); set.add("scala"); //不包含重复元素 set.add("java"); //两种遍历方式 for(String s:set) { System.out.println(s); /*python java scala*/ } System.out.println("--------"); Iterator<String> it = set.iterator(); while(it.hasNext()) { String s = it.next(); System.out.println(s); /*python java scala*/ } } }
7.2 哈希值
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
public int hashCode():返回对象的哈希码值
对象的哈希值特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写hashCode0方法,可以实现让不同对象的哈希值相同
package ceshi; public class HashDemo { public static void main(String[] args) { //创建学生对象 Student s1 = new Student("y1",10); //同一个对象多次调用hashCode()方法哈希值相同 System.out.println(s1.hashCode()); //460141958 System.out.println(s1.hashCode()); //460141958 System.out.println("---------"); //默认情况下,不同对象哈希值不同;重写hashCode()方法就可以使哈希值相同 Student s2 = new Student("y2",20); System.out.println(s2.hashCode()); //1163157884 System.out.println("---------"); System.out.println("java".hashCode()); //3254818 System.out.println("python".hashCode()); //-973197092 System.out.println("scala".hashCode()); //109250886 System.out.println("---------"); System.out.println("无".hashCode()); //26080 System.out.println("敌".hashCode()); //25932 } }
7.3 数据结构之哈希表
JDK8之前,底层采用数组+链表实现,可以说是一个元索为链表的数组(哈希表 = 数组 + 链表 + (哈希算法))
JDK8以后,在长度比较长的时候,底层实现了优化(哈希表 = 数组 + 链表 + 红黑树 + (哈希算法))
当链表长度超过 8 时,将链表转换为红黑树,这样大大减少了查找时间
7.4 HashSet集合概述和特点
HashSet集合特点
底层数据结构是哈希表
对集合的迭代顺序不作任何保证 ,也就是说不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合, 所以是不包含重复元素的集合
package ceshi; import java.util.HashSet; public class HashSetDemo { public static void main(String[] args) { HashSet<String> hs = new HashSet<>(); hs.add("java"); hs.add("python"); hs.add("scala"); hs.add("scala"); for(String s:hs) { System.out.println(s); /*python java scala*/ } } }
7.5 HashSet集合保证元素唯一性源码分析(重点面试常考)
HashSet<String> hs = new HashSet<>(); hs.add("java"); hs.add("python"); hs.add("scala"); hs.add("scala"); for(String s:hs) { System.out.println(s); /*python java scala*/ } ----------------------------------- public boolean add(E e) { return map.put(e, PRESENT)==null; } static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } public V put(K key, V value) { return putVal(hash(key), key, value, false, true); //上个方法的返回的值是hash(key)的值 } //hash值和元素的hashCode()方法 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //如果哈希表未初始化就对其初始化 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //根据对象的哈希值计算对象的存储位置, if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); //如果该位置没有元素,就存储新元素 //有元素就走else else { Node<K,V> e; K k; //存入的元素和以前的元素比哈希值 if (p.hash == hash && //二、如果哈希值相同,调用对象的equals()比较内容是否相同 //1、如果内容不同equals()返回false,就走一把元素添加到集合 //2、如果内容相同返回true,说明元素重复,走e = p;不存储 ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //一、如果哈希值不同,就走else存储元素到集合 else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); //新元素添加到集合 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
HashSet集合存储元素:要保证元素唯一性需要重写hashCode()和equals()方法
案例
Student类
package ceshi; public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } //重写快捷键:Fn+Alt+insert,选择equals() and hashCode() @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; if (age != student.age) return false; return name != null ? name.equals(student.name) : student.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; } }
测试类
package ceshi; import java.util.HashSet; public class HashSetDemo { public static void main(String[] args) { HashSet<Student> hs = new HashSet<>(); Student s1 = new Student("y1",10); Student s2 = new Student("y2",20); Student s3 = new Student("y3",30); Student s4 = new Student("y3",30); hs.add(s1); hs.add(s2); hs.add(s3); hs.add(s4); for(Student s: hs) { System.out.println(s.getName()+","+s.getAge()); /*y3,30 y2,20 y1,10 y3,30;s4内容和s3重复并存入了,需要重写hashCode()和equals() */ //重写后 /* y1,10 y3,30 y2,20*/ } } }
7.6 LinkedHashSet集合概述和特点
LinkedHashSet集合特点
哈希表和链表实现的Set接口, 具有可预测的迭代次序
由链表保证元素有序, 也就是说元索的存储和取出顺序是一致的
由哈希表保证元索唯一, 也就是说没有重复的元素
package ceshi; import java.util.LinkedHashSet; public class LinkedHashSetDemo { public static void main(String[] args) { LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(); linkedHashSet.add("java"); linkedHashSet.add("python"); linkedHashSet.add("scala"); linkedHashSet.add("scala"); for(String s:linkedHashSet) { System.out.println(s); /*java python scala*/ } } }
7.7 TreeSet集合概述和特点
TreeSet集合特点
元素有序, 这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator):根据指定的比较器进行排序
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以不包含重复元素的集合
package ceshi; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { TreeSet<Integer> ts = new TreeSet<>(); //jdk5以后添加元素自动装箱int》integer ts.add(10); ts.add(40); ts.add(30); ts.add(50); ts.add(20); ts.add(30); for(Integer i:ts) { System.out.println(i); /* 10 20 30 40 50*/ } } }
7.8 自然排序Comarable的使用
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论:
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
Student类
package ceshi; 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 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; } @Override public int compareTo(Student s) { // return 0; //返回0说明元素是重复的,只能存一个元素 // return 1; //整数是升序排序 // return -1; //负数是倒叙排序 //按照年龄排序 int num = this.age-s.age; //this是s2,s是s1 //年龄相同时,按照名字字母排序 int num2 = num==0 ? this.name.compareTo(s.name):num; return num2; } }
测试
package ceshi; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<>(); Student s1 = new Student("y1",10); Student s2 = new Student("y3",30); Student s3 = new Student("y2",20); Student s4 = new Student("y4",40); Student s5 = new Student("a4",40); //判断按字母排序 Student s6 = new Student("y4",40); //判断会存储重复值吗 ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); ts.add(s6); for(Student s:ts) { System.out.println(s.getName()+","+s.getAge()); /*y1,10 y2,20 y3,30 a4,40 y4,40*/ } } }
7.9 比较器排序Comparator[kəmˈpɜrətər]的使用
存储学生对象并遍历,创建TreeSet集合使用带参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
结论
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元索进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,T o2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
package ceshi; public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } }
测试
package ceshi; import java.util.Comparator; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<>(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("y2",20); Student s2 = new Student("y1",10); Student s3 = new Student("y3",30); Student s4 = new Student("y4",40); ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); for(Student s:ts) { System.out.println(s.getName()+","+s.getAge()); } } }
7.10 案例:不重复随机数
package ceshi; import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.TreeSet; public class SetDemo { public static void main(String[] args) { // Set<Integer> set = new HashSet<>(); Set<Integer> set = new TreeSet<>(); 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+" "); //1(哈希set集合):16 17 2 20 8 9 10 11 14 15 //2(TreeSet集合):1 3 4 5 6 7 8 10 16 19 } } }
8 Map集合
HashMap: 元素按照键是无序,不重复,无索引,值不做要求
LinkedHashMap: 元素按照键是有序,不重复,无索引,值不做要求
8.1 Map集合概述和特点
Map集合是一种双列集合,每个元素包含两个值
Interface Map<K,V>; K:键的类型,V:值的类型
Map集合的每个元素的格式:key = value(键值对元素)
Map集合也被称为“键值对集合”
Map集合特点:
Map 集合的键是无序,不重复,无索引的
Map 集合后面重复的键对应的元素会覆盖前面的整个元素
创建Map集合对象:
多态的方式
具体的实现类HashMap
package ceshi; import java.util.HashMap; import java.util.Map; public class MapDemo { public static void main(String[] args) { Map<String,String> map = new HashMap<>(); map.put("y1","10"); map.put("y2","20"); map.put("y2","30"); //键和前面相同时,会替换前面的值 map.put("y3","30"); System.out.println(map); //{y1=10, y3=30, y2=30} } }
8.2 Map集合的基本方法
方法名 说明
public V put(K key, V value) 添加元素
public V remove(Object key) 根据键删除键值对元素
public void clear() 移除所有键值对元素
public boolean containKey(Object key) [kənˈteɪn] 判断集合是否包含指定的键
public boolean containValue(Object value) 判断集合是否包含指定的值
public boolean isEmpty() 判断集合是否为空
public int size() 集合的长度,也就是集合中键值对个数
package ceshi; import java.util.HashMap; import java.util.Map; public class MapDemo { public static void main(String[] args) { Map<String,String> map = new HashMap<>(); //1,public V put(K key, V value) 添加元素 map.put("y1","10"); map.put("y2","20"); map.put("y3","30"); System.out.println(map); //{y1=10, y2=20, y3=30} //2,public V remove(Object key) 根据键删除键值对元素 /*map.remove("y2"); System.out.println(map); //{y1=10, y3=30} */ //3,public void clear() 移除所有键值对元素 /* map.clear(); System.out.println(map); //{} */ //4,public boolean containKey(Object key) [kənˈteɪn] 判断集合是否包含指定的键 /*System.out.println(map.containsKey("y2")); //ture System.out.println(map.containsKey("y4")); //false*/ //5,public boolean containValue(Object value) 判断集合是否包含指定的值 // System.out.println(map.containsValue("10")); //true //6,public boolean isEmpty() 判断集合是否为空 // System.out.println(map.isEmpty()); //false //7,public int size() 集合的长度,也就是集合中键值对个数 System.out.println(map.size()); //3 } }
8.3 Map集合的获取方法(重点)
方法名 说明
public V get(Object key) 根据键获取值
public Set<K> keySet() 获取所有键的集合,存储到Set集合中
public Collection<V> values() 获取所有值的集合,存储到Collection集合中
public Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合(Set集合)
package ceshi; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { Map<String,String> map = new HashMap<>(); //public V put(K key, V value) 添加元素 map.put("y1","10"); map.put("y2","20"); map.put("y3","30"); System.out.println(map); //{y1=10, y2=20, y3=30} //1,public V get(Object key) 根据键获取值 System.out.println(map.get("y1")); //10 System.out.println(map.get("y4")); //null //2,public Set<K> keySet() 获取所有键的集合,存储到Set集合中 Set<String> key = map.keySet(); for(String s:key) { System.out.println(s); /*y1 y2 y3*/ } //3,public Collection<V> values() 获取所有值的集合,存储到Collection集合中 Collection<String> vlaues = map.values(); for(String s:vlaues) { System.out.println(s); /*10 20 30*/ } //4,public Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合(Set集合) Set<Map.Entry<String, String>> entries = map.entrySet(); for(Map.Entry<String, String> s:entries) { System.out.println(s); /* y1=10 y2=20 y3=30*/ } } }
8.4 Map集合的遍历
Map 集合遍历有三种方式:
"键找值"的方式遍历
"键值对"的方式遍历
Lambda 表达式(JDK1.8开始之后的新技术)
8.4.1 "键找值"的方式遍历(常用)
1、获取所有键的集合:用keySet()方法实现
2、遍历键的集合,获取到每一个键:用增强for遍历实现
3、根据键去找值:在增强for中,用get(Object key)方法实现
package ceshi; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); //public V put(K key, V value) 添加元素 map.put("y1", "10"); map.put("y2", "20"); map.put("y3", "30"); System.out.println(map); //{y1=10, y2=20, y3=30} //1、获取所有键的集合:用keySet()方法实现 Set<String> keySet = map.keySet(); //2、遍历键的集合,获取到每一个键:用增强for遍历实现 for (String key : keySet) { //3、根据键去找值:在增强for中,用get(Object key)方法实现 String value = map.get(key); System.out.println(key + "=" + value); /* y1=10 y2=20 y3=30*/ } } }
8.4.2 "键值对"的方式遍历
1、获取所有键值对对象的集合:Set<Map.Entry<K,V>> entrySet()
2、遍历键值对对象的集合,得到每一个键值对对象:用增强for实现,得到每一个Map.Entry
3、根据键值对对象获取键和值:在增强for中,用geKey()得到键;用getValue()得到值
package ceshi; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); //public V put(K key, V value) 添加元素 map.put("y1", "10"); map.put("y2", "20"); map.put("y3", "30"); System.out.println(map); //{y1=10, y2=20, y3=30} //1、获取所有键值对对象的集合:Set<Map.Entry<K,V>> entrySet() Set<Map.Entry<String, String>> entrySet = map.entrySet(); //2、遍历键值对对象的集合,得到每一个键值对对象:用增强for实现,得到每一个Map.Entry for(Map.Entry<String, String> me:entrySet) { //3、根据键值对对象获取键和值:在增强for中,用geKey()得到键;用getValue()得到值 String key = me.getKey(); String value = me.getValue(); System.out.println(key+"="+value); /* y1=10 y2=20 y3=30*/ } } }
8.4.3 Lambda [ˈlæmdə] 表达式方式遍历
package ceshi; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); //public V put(K key, V value) 添加元素 map.put("y1", "10"); map.put("y2", "20"); map.put("y3", "30"); System.out.println(map); //{y1=10, y2=20, y3=30} map.forEach((k , v) -> { System.out.println(k+"="+v); /* y1=10 y2=20 y3=30*/ }); } }
8.5 Map集合存储自定义类型
Map集合的键和值都可以存储自定义类型
如果希望Map集合认为自定义类型的键对象重复了,必须重写对象的hashCode()和equals()方法
8.6 LinkedHashMap(HashMap子类)
LinkedHashMap集合是有序不重复的键值对集合
public class LinkedHashMapDemo { public static void main(String[] args) { Map<String , Integer> map = new LinkedHashMap<>(); map.put("y1",10); map.put("y2",20); map.put("y3",30); map.put("y3",100); //键不变,只是替换其值 System.out.println(map);// {y1=10, y2=20, y3=100} } }
8.7 TreeMap
TreeMap 集合按照键是可排序不重复的键值对集合(默认升序)
8.8 案例
8.8.1 集合遍历
package ceshi; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo { public static void main(String[] args) { //创建HashMap集合对象 HashMap<String,Student> hm =new HashMap<>(); Student s1 = new Student("y1",10); Student s2 = new Student("y2",20); Student s3 = new Student("y3",30); hm.put("itheima1",s1); hm.put("itheima2",s2); hm.put("itheima3",s3); //键找值 Set<String> keySet = hm.keySet(); for(String key:keySet) { Student value = hm.get(key); System.out.println(key+","+value.getName()+","+value.getAge()); /*itheima3,y3,30 itheima1,y1,10 itheima2,y2,20*/ } System.out.println("---------"); //键值对 Set<Map.Entry<String, Student>> entrySet= hm.entrySet(); for(Map.Entry<String, Student> me:entrySet) { String key = me.getKey(); Student value = me.getValue(); System.out.println(key+","+value.getName()+","+value.getAge()); /*itheima3,y3,30 itheima1,y1,10 itheima2,y2,20*/ } } }
8.8.2 集合嵌套之 ArrayList嵌套HashMap
package ceshi; import java.util.*; public class MapDemo { public static void main(String[] args) { //1,创建ArrayList集合对象 ArrayList<HashMap<String,String>> array = new ArrayList<>(); //2,创建HashMap集合,并添加键值对元素 HashMap<String,String> hm1 = new HashMap<>(); hm1.put("y1","10"); HashMap<String,String> hm2 = new HashMap<>(); hm1.put("y2","20"); HashMap<String,String> hm3 = new HashMap<>(); hm1.put("y3","30"); //3,把HashMap作为元素添加到Arraylist array.add(hm1); array.add(hm2); array.add(hm3); //遍历Arraylist 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); /*y1,10 y2,20 y3,30*/ } } } }
8.8.3 统计字符串中每个字符出现的次数
9 泛型
9.1 泛型的概述和好处
泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
泛型定义格式:
<类型>:指定一种类型的格式。这里的类型可以看成是形参
<类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参, 并粗实参的类型只能是引用数据类型
JDK 1.7开始之后,泛型后面的申明可以省略不写
泛型和集合都只能支持引用数据类型,不支持基本数据类型
ArrayList<String> lists = new ArrayList<String>(); ArrayList<String> lists = new ArrayList<>(); // JDK 1.7开始之后,泛型后面的申明可以省略不写!!
泛型的好处:
把运行的错误提前到编译时期
避免了强制类型转换
Collection<String> c = new ArrayList<>(); c.add("java"); // c.add(100); //报错 // c.add(false); //报错
9.2 泛型类
泛型类的概念:使用了泛型定义的类就是泛型类
常用泛型变量:T、E、V、K等形式的参数用来表示泛型
格式
修饰符 class 类名<泛型变量>{} //范例 public class Generic<T> {}
泛型类的核心思想:是把出现泛型变量的地方全部替换成传输的真实数据类型
泛型类
package ceshi; public class Generic<T> { private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } }
测试类
package ceshi; public class GenericDemo { public static void main(String[] args) { Generic<String> g1 = new Generic<>(); g1.setT("y1"); Generic<Integer> g2 = new Generic<>(); g2.setT(20); System.out.println(g1.getT()+","+g2.getT()); //y1,20 Generic<Boolean> g3 = new Generic<>(); g3.setT(true); System.out.println(g3.getT()); //true } }
9.3 泛型方法
泛型方法定义格式
修饰符 <类型> 返回值类型 方法名(类型 变量名){} //范例 public <T> void show(T t) {}
泛型方法定义
package ceshi; /*public class Generic { public void show(String s) { System.out.println(s); } public void show(Integer i) { System.out.println(i); } public void show(Boolean b) { System.out.println(b); } }*/ //泛型类改进 /* public class Generic<T> { public void show(T t) { System.out.println(t); } } */ //泛型方法 public class Generic { public <T> void show (T t) { System.out.println(t); } }
测试类
package ceshi; public class GenericDemo { public static void main(String[] args) { /*Generic g1 = new Generic(); g1.show("y1"); g1.show(30); g1.show(true);*/ //泛型类 /*Generic<String> g1 = new Generic<>(); g1.show("y1"); Generic<Integer> g2 = new Generic<>(); g2.show(10);*/ //泛型方法 Generic g = new Generic(); g.show("y1"); g.show(10); g.show(true); g.show(13.14); /*y1 10 true 13.14*/ } }
9.4 泛型接口
泛型接口定义格式
修饰符 interface 接口名称<类型> {} //范例 public interface Generic<T> {}
泛型接口
package ceshi; public interface Generic<T> { void show(T t); }
实现类
package ceshi; public class GenericImpl<T> implements Generic<T>{ @Override public void show(T t) { System.out.println(t); } }
测试类
package ceshi; public class GenericDemo { public static void main(String[] args) { GenericImpl g1 = new GenericImpl(); g1.show("y1"); g1.show(10); } }
9.5 类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符: <?>
List<?>:表示元素类型未知的List,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限
类型通配符 上限: <? extends类型>
List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
类型通配符 下限::<?super 类型>
List<? super Number>:它表示的类型是Number或者其父类型
package ceshi; import java.util.ArrayList; import java.util.List; public class GenericDemo { public static void main(String[] args) { //类型通配符: <?> List<?> list1 = new ArrayList<Number>(); List<?> list2 = new ArrayList<String>(); List<?> list3 = new ArrayList<Integer>(); //类型通配符上限: <? extends类型> // List<? extends Number> list4 = new ArrayList<Object>(); 报错,超过上限 List<? extends Number> list5 = new ArrayList<Number>(); List<? extends Number> list6 = new ArrayList<Integer>(); //类型通配符 下限::<?super 类型> List<? super Number> list7 = new ArrayList<Object>(); List<? super Number> list8 = new ArrayList<Number>(); // List<? super Number> list9 = new ArrayList<Integer>(); 报错 } }
9.6 可变参数
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
格式:修饰符 返回值类型 方法名(数据类型…变量名){ }
范例:public static int sum(int...a) {}
注意事项
这里的变量其实是一个数组
一个方法有多个参数,包含可变参数,可变参数放最后
范例:public static int sum(int b,int...a) {}
package ceshi; import java.util.ArrayList; import java.util.List; public class GenericDemo { public static void main(String[] args) { System.out.println(sum(10,20)); System.out.println(sum(10,20,30)); System.out.println(sum(10,20,30,40)); /* 30 60 100*/ } public static int sum(int...a) { //a为数组 int sum =0; for(int i:a) { sum +=i; } return sum; } //一个方法有多个参数,可变参数放最后 /*public static int sum(int b,int...a) { return 0; }*/ }
9.7 可变参数的使用
1、Arrays工具类中有一个静态方法:
public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
返回的集合不能做增删操作,可以做修改
2、List接口中有一个静态方法:(JDK9以上)
public static <E> List<E> of(E... elements):返回包含任意数元素的不可变列表
返回的集合不能做增删改操作
3、Set接口中有一个静态方法: (JDK9以上)
-public static <E> Set<E> of(E.... elements):返回一个包含任意数量元素的不可变集合
在给元素的时候,不能给重复值
返回的集合不能做增删操作,没有修改方法
package ceshi; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; public class GenericDemo { public static void main(String[] args) { //1、public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表 /* List<String> list = Arrays.asList("java", "python", "scala"); System.out.println(list); //[java, python, scala] // list.add("javase"); //UnsupportedOperationException;不支持请求操作 // list.remove("java"); //UnsupportedOperationException;不支持请求操作 list.set(0,"javase"); System.out.println(list); //[javase, python, scala]*/ //2、public static <E> List<E> of(E... elements):返回包含任意数元素的不可变列表 List<String> list = List.of("java","python","scala","java") System.out.println(list); //[javase, python, scala,java] //list.add("javaee"); //UnsupportedOperationException //list.remove("java"); //UnsupportedOperationException //list.set(0,"javaee") //UnsupportedOperationException //3、public static <E> Set<E> of(E.... elements):返回-一个包含任意数量元素的不可变集合 //Set<String> set = Arrays.of("java", "python", "scala","java"); //set集合不能重复 Set<String> set = Arrays.of("java", "python", "scala"); System.out.println(set); //[java, python, scala] //set.add("javaee"); //UnsupportedOperationException //set.remove("java"); //UnsupportedOperationException } }