文章图片及参考资料均来自黑马成程序员B站课程:https://www.bilibili.com/video/BV17F411T7Ao,侵删。
idea常用快捷键
选中类名按ctrl+B | 查看该类源码 |
---|---|
进入Java类中后按ctrl+F12 | 在该类中搜索 |
ctrl+alt+v | 自动补全左边代码 |
ctrl+shift+u | 快速切换大小写 |
alt+insert | 插入构造方法 |
ctrl+O | 重写方法 |
ctrl+shift+向上箭头 | 把代码上移一行 |
ctrl+alt+m | 抽取方法 |
ctrl+alt+左箭头 | 返回上一步 |
Math类
System类
![]](https://img-blog.csdnimg.cn/c8f96e79610c4400abb7d4c7305692ab.png)
runtime类
Runtime表示当前那虚拟机的运行环境,由于由于这个类里面的对象不是static的,调用方法前需要线获取Runtime对象。
Runtime无法直接new一个对象,查看源码可知,Runtime在自己的类里边new了一个Runtime对象,并用final修饰(无法修改),然后用一个静态方法getRuntime返回,而把自己的构造方法写成了私有,即无法从类的外部再创建对象。
这样写的一个好处就是,外界调用getRuntime方法时,不管什么时候调用在哪里调用,所调用的都是同一个对象,无法new出很多个对象来(因为虚拟机只有一个)。
public class RuntimeTest {
public static void main(String[] args) throws IOException {
Runtime rt1 = Runtime.getRuntime();
Runtime rt2 = Runtime.getRuntime();
System.out.println(rt1 == rt2);
rt1.exit(0);//退出虚拟机
System.out.println("看看执行了没");
System.out.println(rt1.availableProcessors());//获取CPU线程数
System.out.println(rt1.maxMemory()/1024/1024);//总内存大小,单位byte
System.out.println(rt1.totalMemory() / 1024 / 1024);//已经获取的内存大小
System.out.println(rt1.freeMemory()/1024/1024);//剩余内存大小
//运行CMD命令
rt1.exec("notepad");//打开记事本
/*关机操作shutdown
-s:默认一分钟后关机
-s -t 指定时间:再指定时间后关机
-a:取消关机操作
-r:关机并重启*/
rt1.exec("shutdown -s -t 3600");
rt1.exec("shutdown -a");
}
}
Object类
Object类是Java中的顶级父类,所有类都直接或间接地继承于Object类。
Object类中的方法可以被所有子类访问。
Object类中一共有11个成员方法。
toString方法
toString()方法返回对象的地址值。
如下图,Object类中的toString()方法与sout打印出来的效果是一样的,因为sout方法在底层就是调用了Object类中的toString方法。
如果不想打印地址值,而希望打印子类中的属性值,那么可以直接重写(@override)子类中的toString方法。
Equals方法
Object类中的equals()方法默认比较两个对象的地址值,String类中对其进行了重写。
clone方法
对象克隆:把A对象属性值完全拷贝给B对象,即为对象克隆。
用protected修饰的方法可以在本包中的类和其他包中的子类被调用。
clone方法前用protected修饰,用protected修饰的方法可以在其他包中的子类当中访问,但不能在其他类中用子类对象访问。
即:不能再测试类中通过子类对象调用clone方法。
因此,子类要调用clone方法,需要在子类中重写一下clone方法:
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
另外,需要在子类定义的开头加上一个implement Cloneable接口,变成一个实现类。
但是实际上,Cloneable是一个没有任何抽象方法的接口:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Vz5Uh7o-1669103793390)(C:\Users\cong\AppData\Roaming\Typora\typora-user-images\image-20221112200234063.png)]
如果一个接口中没有抽象方法,表示这个接口是一个标记性的接口。
如,Cloneable接口一旦被实现,表示当前类的对象就可以被克隆,若没有实现,当前类对象就不能被克隆。
浅克隆,基本数据类型复制其数据,引用数据类型复制其地址值。
弊端:修改一个对象中的引用数据(如修改数组中的值),会同步修改另一个克隆对象的引用数据。
浅克隆VS深克隆:
object中默认的clone方法是浅克隆,要实现深克隆需要在子类中重写clone方法。
Objects工具类
Objects是一个工具类,提供了一些方法去完成一些功能。
BigInteger和BigDecimal类
BigInteger类的构造方法
BigInteger对象一旦创建,内部记录的值将不再改变。
BigInteger类的成员方法
BigInteger类的存储方式
先将大整数转换成二进制补码,以32位为一组拆成若干段(如上图是拆成了3段)存入一个数组中。其中,第一位是无符号位。
BigDecimal类
小数在计算机中的存储模式
BigDecima的作用:①用于小数的精确计算;②用来表示很大的小数
如果是除不尽的小数,需要设置精确几位和舍入模式。
BigDecima的存储模式
把输入的字符参数拆开,存储对应的ASCII数值放到一个数组中。
可以使用debug功能分析Java的底层运算。
正则表达式
正则表达式作用:①校验字符串是否满足规则;②在一段文本中查找满足要求的内容
[a-z&&[def]] //a-z和def的交集。为:d,e,f
//细节:如果要求两个范围的交集,那么需要写符号8&
//如果写成了一个&,那么此时&表示就不是交集了,而是一个简简单单的&符号
System.out.println("a".matches("[a-z&&[d-f]]"));
System.out.println("&".matches("[a-z&&[d-f]]"));
System.out.println("a".matches("[a-z&[d-f]]"));
System.out.println("&".matches("[a-z&[d-f]]"));
“\”在Java中表示转义字符。
//忽略大小写:(?i),会忽略在这之后的字母的大小写
String regex4="a((?i)b)c";
System. out. println("------------");
System.out.println("abc". matches(regex4));//true
System.out.println("WBC". matches(regex4));//false
System.out.println("aBc". matches(regex4));//true
正则表达式总结
正则表达式在字符串方法中的使用
分组
Q:正则表达式中的[]和()什么区别?
分组就是一个小括号
//需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符
//举例:ai23a b456b 17891&abc&a123b(false)
String r1 = "(.).+\\1";
String str1 = "ai23a还是短发b456b的防护等级17891&abc&a123b";
extracted(r1,str1);
System.out.println("ai23a".matches(r1));
System.out.println("b456b".matches(r1));
System.out.println("17891&abc&a123b".matches(r1));
System.out.println("ai23a还是短发b456b的防护等级17891&abc&a123b".matches(r1));
System.out.println("-------------------");
//需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
//举例:abc123abc b456b123789123&l@abc&!@abc123abd(false)
String r2 = "(.+).+\\1";
System.out.println("abc123abc".matches(r2));
System.out.println("b456b".matches(r2));
System.out.println("123789123".matches(r2));
System.out.println("&!@abc&!@".matches(r2));
System.out.println("abc123abd".matches(r2));
System.out.println("-------------------");
//需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致
//举例:aaa123aaabbb456bbb111789111&&abc&&
/*(.):把首字母看做一组
\\2:把首字母拿出来再次使用
+:作用于\\2,表示后面重复的内容出现1次或多次*/
String r3 = "((.)\\2+).+\\1";
System.out.println("aaa123aaa".matches(r3));
System.out.println("bbb456bbb".matches(r3));
System.out.println("111789111".matches(r3));
System.out.println("&&abc&&".matches(r3));
System.out.println("aaa123aad".matches(r3));
System.out.println("-------------------");
后续还要继续使用本组数据:
- 正则内部使用:\\组号
- 正则外部使用:$组号
/*需求:
将字符串:我要学学编编编编程程程程程程
替换为:我要学编程*/
String s = "我要学学编编编编程程程程程程";
//(.)表示把重复内容的第一个字符看做一组
//\\1表示第一字符再次出现
//+至少一次
//$1表示把正则表达式中第一组的内容,再拿出来用
String r = "(.)\\1*";
System.out.println(s.replaceAll(r,"$1"));
捕获分组和非捕获分组
非捕获分组:仅仅是把括号括起来,而不占用组号
/*
需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号。
需求2:爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11Java17 Java17
需求3:爬取除了版本号为8,11,17的Java文本,*/
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为"+
"这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台。"
String r1 = "((?i)Java)(?=8|11|17)"; //需求1
String r21 = "((?i)Java)(8|11|17)"; //需求2
String r22 = "((?i)Java)(?:8|11|17)"; //需求2
String r3 = "((?i)Java)(?!8|11|17)"; //需求3
Pattern p = Pattern.compile(r1);
Matcher m = p.matcher(str);
while (m.find()) {
String g = m.group();
System.out.println(g);
}
Q:正则表达式中?
到底怎么用?
package api;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaa" +
"经历了很多版本,目前企业中用的最多的是JAva8和JaVa11," +
"因为这两个是长期支持版本,下一个长期支持版本是JavA17,相信在未来不久JAvA17也会逐渐登上历史舞台";
//extracted1(str);
/*有如下文本,请按照要求爬取数据。”
Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaa
经历了很多版本,目前企业中用的最多的是Java8和Java11,
因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台
需求1:按照ab+的方式爬取ab,b尽可能多获取
需求2:按照ab+的方式爬取ab,b尽可能少获取
贪婪爬取:在爬取数据时尽可能多获取数据
非贪婪爬取:在爬取数据时尽可能少获取数据
Java中默认是贪婪爬取*/
String s1 = "ab+"; //需求1,贪婪爬取
String s2 = "ab+?"; //需求2,非贪婪爬取
Pattern p = Pattern.compile(s2);
Matcher m = p.matcher(str);
while (m.find()) {
String g = m.group();
System.out.println(g);
}
}
private static void extracted1(String str) {
/*有文本:Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,
因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台
需求1:爬取版本号为8,11,17的Java文本,但是只要Java,不显示版本号。
需求2:爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11Java17 Java17
需求3:爬取除了版本号为8,11,17的Java文本,*/
String s1 = "((?i)Java)(?=8|11|17)"; //需求1
String s21 = "((?i)Java)(8|11|17)"; //需求2
String s22 = "((?i)Java)(?:8|11|17)"; //需求2
String s3 = "((?i)Java)(?!8|11|17)"; //需求3
Pattern p = Pattern.compile(s3);
Matcher m = p.matcher(str);
while (m.find()) {
String g = m.group();
System.out.println(g);
}
}
}
时间相关类
JDK7前的时间相关类
Date | 时间 |
---|---|
SimpleDateFormat | 格式化时间 |
Calendar | 日历 |
世界标准时间:
- 格林尼治时间/格林威治时间(Greenwich Mean Time)简称(GMT),计算核心:地球自转一天是24小时,太阳直射本初子午线时为政务12点。
- 原子钟:利用铯原子的振动频率计算出来的时间,作为世界标准时间(UTC),原子每振动9,192,631,770次等于1秒。
中国标准时间:世界标准时间+8小时
Date类
Date类是一个JDK写好的JavaBean类,用来描述时间,精确到毫秒。
SimpleDateFormat类
作用:
- 格式化:把时间变成我们喜欢的格式(2022年11月16日、2022-11-16、2022/11/16)
- 解析:把字符串表示的时间变成Date对象
Calendar类
Calendar是一个抽象类,不能直接new一个对象。
//1.获取日历对象
//细:1:Calendar是一个抽象类,不能直接new,而是通过一个静态方法获取到子类对象
//底层原理:
//会根据系统的不同时区来获取不同的日历对象,默认表示当前时间。
//把会把时间中的纪元,年,月,日,时,分,秒,星期,等等的都放到一个数组当中
//0:纪元
//1:年
//2:月
//3:一年中的第几周
//4:一个月中的第几周
//5:一个月中的第几天
//....一直到16
//细节2:
//月份:范围0~11如果获取出来的是0.那么实际上是1月。
//星期:在老外的眼里,星期日是一周中的第一天
//1(星期日)2(星期一)3(星期二)4(星期三)5(星期四)6(星期五)7(星期六)
Calendar c = Calendar.getInstance();
//Date d = c.getTime();
Date d = new Date(0L);
c.setTime(d);
System.out.println(d);
c.set(Calendar.YEAR,2022);
c.set(Calendar.MONTH,10);
c.set(Calendar.DAY_OF_MONTH,17);
c.add(Calendar.YEAR,2);
c.add(Calendar.DAY_OF_MONTH,-5);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
int week = c.get(Calendar.DAY_OF_WEEK);
System.out.println(year+" "+month+" "+day+" "+week);
JDK8新增时间相关类
JDK8新增的时间日期对象都是不可变的,如果我们修改、减少、增加了时间,调用者是保护会发生改变的,而是产生一个新的时间对象。
Date类
Java中一共定义了600个时区。
//1.获取当前时间对象(带时区)
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
//2.获取指定的时间对象(带时区)
//年月日时分秒纳秒方式指定
ZonedDateTime time1 = ZonedDateTime.of(2023,10,1,11,12,12,0,ZoneId.of("Asia/Shanghai"));
System.out.println(time1);
//通过Instant +时区的方式指定获取时间对象
Instant instant = Instant.ofEpochMilli(0L);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime time2 = ZonedDateTime.ofInstant(instant,zoneId);
System.out.println(time2);
//3.withXxx 修改时间系列的方法
ZonedDateTime time3 = time2.withYear(2000);
System.out.println(time3);
//4.减少时间
ZonedDateTime time4 = time3.minusYears(1);
System.out.println(time4);
//5.增加时间
ZonedDateTime time5 = time4.plusYears(1);
System.out.println(time5);
//解析/格式化器
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EE a");
//格式化
System.out.println(dtf1.format(now));
Calendar类
- get开头的方法表示获取相应的时间对象。
- is开头的表示判断。
时间工具类
- to开头的方法,获取对应的年/月/日/时/分/秒等(toDays等)
包装类
包装类:基本数据类型对应的引用数据类型。
为什么会有包装类?——Java的兼容性、集合中不能存储基本数据类型,只能存储引用数据类型。
Integer类
//底层原理:
//因为在实际开发中,-128~127之间的数据,用的比较多。
//如果每次使用都是new对象,那么太浪费内存了
//所以,提前把这个范围之内的每一个数据都创建好对象
//如果要用到了不会创建新的,而是返回已经创建好的对象。
Integer i6 = Integer.valueOf(127);
Integer i7 = Integer.valueOf(127);
System.out.println(i6 == i7);//t
Integer i8 = Integer.valueOf(128);
Integer i9 = Integer.valueOf(128);
System.out.println(i8 == i9);//f
Integer i10 = new Integer(127);
Integer i11 = new Integer(127);
System.out.println(i10 == i11);//f
Integer i12 = new Integer(128);
Integer i13 = new Integer(128);
System.out.println(i12 == i13);//f
JDK5以前,Java对整型的运算,需要先把引用数据类型拆箱成基本数据类型,用基本数据类型进行计算之后再进行装箱,变回引用数据类型。
JDK5之后,Java可以进行自动拆箱和装箱。因此JDK5之后,int和Integer可以堪称时同一个东西,因为条码再内部可以自动转化。
Integer类成员方法
Java是一种强类型语言,每种数据再在Java内部都有其各自的数据类型。在计算时,如果不是同一种数据类型,是无法直接计算的。
parseInt:将字符串转换成int类型的整数。在类型转换时,字符串中只能时纯数字,不能夹带其他字母或符号。
8种包装类当中,除了Character都有对应的parseXxx方法,将字符串转换成对应的包装类。
//将字符串类型的整数转成int类型的整数
//强类型语言:每种数据在java中都有各自的数据类型
//在计算的时候,如果不是同一种数据类型,是无法直接计算的.
int i = Integer.parseInt("123");
System.out.println(i);
System.out.println(i + 1);//124
//细节1:
//在类型转换的时候,括号中的参数只能是数字不能是其他,否则代码会报错
//细节2:
//8种包装类当中,除了Character都有对应的parseXxx的方法,进行类型转换
String str ="true";
boolean b = Boolean.parseBoolean(str);
System.out.println(b);
键盘录入的改进:
//键盘录入的改进:
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = sc.next();
System.out.println(str);*/
//弊端:
//当我们在使用next,nextInt,nextDouble在接收数据的时候,遇到空格,回车,制表符的时候就停止了,
//键盘录入的是123 123那么此时只能接收到空格前面的数据
//我想要的是接收一整行数据
//以后我们如果想要键盘录入,不管什么类型,统一使用nextLine
//nextLine特点遇到回车才停止
String line = sc.nextLine();
System.out.println(line);
double v = Double.parseDouble(line);
System.out.println(v + 1)
Arrays类
Arrays类:操作数组的工具类。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeHXsBdn-1669103793416)(C:\Users\cong\AppData\Roaming\Typora\typora-user-images\image-20221119152426235.png)]
//toString:将数组拼接成字符串
int[] arr = {1,2,3,4,5,6,7,8,9,10};
System.out.println(Arrays.toString(arr));
//binarySearch:二分查找法查找元素
//细节1:二分查找的前提:数组中的元素必须是有序,数组中的元素必须是升序的1/细节2:如果要查找的元素是存在的,那么返回的是真实的索引1/但是,如果要查找的元素是不存在的,返回的是-插入点-1
//疑问:为什么要减1呢?
//解释:如果此时,我现在要查找数字e,那么如果返回的值是-插入点,就会出现问题了。
//如果要查找数字0,此时0是不存在的,但是按照上面的规则-插入点,应该就是-0
//为了避免这样的情况,Java在这个基础上又减一。
System.out.println(Arrays.binarySearch(arr, 5));
System.out.println(Arrays.binarySearch(arr, 3));
System.out.println(Arrays.binarySearch(arr, 20));
//copyOf:拷贝数组
//参数一:老数组
//参数二:新数组的长度
//方法的底层会根据第二个参数来创建新的数组
//如果新数组的长度是小于老数组的长度,会部分拷贝1/如果新数组的长度是等于老数组的长度,会完全拷贝
//如果新数组的长度是大于老数组的长度,会补上默认初始值
//copyOfRange:拷贝数组(指定范围)
//细节:包头不包尾,包左不包右
int[] newArr1 = Arrays.copyOf(arr,20);
int[] newArr2 = Arrays.copyOfRange(arr,3,8);
System.out.println(Arrays.toString(newArr1));
System.out.println(Arrays.toString(newArr2));
Arrays.fill(arr,100);
System.out.println(Arrays.toString(arr));
//sort:排序.默认情况下,给基本数据类型进行升序排列.底层使用的是快速排序.
int[] arr2 = {10,2,3,5,6,1,7,8,4,9};
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
/*sort的重写方法:public static void sort(数组,排序规则)
按照指定的规则排序
参数一:要排序的数组
参数二:排序的规则
细节:只能给引用数据类型的数组进行排序
如果数组是基本数据类型的,需要变成其对应的包装类*/
Integer[] arr3 = {2, 3, 1, 5, 6, 7, 8, 4, 9};
//第二个参数是一个接口,所以我们在调用方法的时候,需要传递这个接口的实现类对象,作为排序的规则。
// 但是这个实现类,我只要使用一次,所以就没有必要单独的去写一个类,直接采取匿名内部类的方式就可以了
//
//底层原理:
//利用插入排序+二分查找的方式进行排序的。
//默认把0索引的数据当做是有序的序列,1索引到最后认为是无序的序列。
// 遍历无序的序列得到里面的每一个元素,假设当前遍历得到的元素是A元素
// 把A往有序序列中进行插入,在插入的时候,是利用二分查找确定A元素的插入点。
//拿着A元素,跟插入点的元素进行比较,比较的规则就是compare方法的方法体
//如果方法的返回值是负数,拿着A继续跟前面的数据进行比较
//如果方法的返回值是正数,拿着A继续跟后面的数据进行比较
//如果方法的返回值是0,也拿着A跟后面的数据进行比较
//直到能确定A的最终位置为止。
//compare方法的形式参数:
//参数一01:表示在无序序列中,遍历得到的每一个元素
// 参数二02:有序序列中的元素
//返回值:
//负数:表示当前要插入的元素是小的,放在前面
// 正数:表示当前要插入的元素是大的,放在后面
//0:表示当前要插入的元素跟现在的元素比是一样的,也会放在后面
//o1-o2:升序
//o2-o1:降序
Arrays.sort(arr3, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
/*System.out.println("------");
System.out.println("o1:"+o1);
System.out.println("o2:"+o2);*/
//为什么打印出来1和3比了2次?
// 前面的有序数组是按照二分法来查找的,然后把后边的无需数组通过插入法排序
// 1和3比了两次是因为,第一次数组[2,3]折半后的索引值是(0+(2-1))/2=0,0索引对应的值是2
// 然后就想不明白了,找不到源码
return o1-o2;
}
});
System.out.println(Arrays.toString(arr3));
lambda表达式
//将上面的Array.sort方法写成lambda表达式的形式
Integer[] arr3 = {2, 3, 1, 5, 6, 7, 8, 4, 9};
Arrays.sort(arr3, (Integer o1, Integer o2)-> {
return o1 - o2;
});
System.out.println(Arrays.toString(arr3));
lambda表达式其实就是把接口当成一个方法来用 ,所以如果接口有多个方法就不行了(匿名内部方法?)
lambda的省略规则——可推导,可省略:
1.参数类型可以省略不写。
2.如果只有一个参数,参数类型可以省略,同时()也可以省略。
3.如果Lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略。
//lambda表达式的进一步省略
//小括号:数据类型可以省略,如果参数只有一个,小括号还可以省略
//大括号:如果方法体只有一行,return,分号,大括号都可以省略
Arrays.sort(arr3, (o1,o2)->o2-o1);
System.out.println(Arrays.toString(arr3));