0. Intellij Idea

快捷键

ALT+SHIFT+0:生成构造器或setter、getter

IDEA的Debug

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

IDEA导入已有的模块

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1 字符串相关的类

1.1 String类

String源码

public final class String implements java.io.Serializable, Comparable<String>, CharSequence{
	private final char value[];
	private int hash;
	...
}

String的实例化

String s1="hello";//字面量实例化
String s2=new String();//本质是this.value=new char[0];
String s3=new String(String original);//本质是this.value=original.value;
String s4=new String(char[] a);//this.value=Arrays.copyOf(value, value.length);
String s5=new String(char[] a, int startIndex, int count);

总体来说:
String的实例化方式:
 * 方式1:通过字面量定义的方式:存放到方法区中的字符串常量池中
 * 方式2:通过new + 构造器的方式:存放到堆中

String:字符串,使用一对""引起来表示

  • 1.String声明为final的,不可被继承
  • 2.String实现Serializable接口:表示字符串是支持序列化的
    实现Comparable接口:表示字符串可以比较大小
  • 3.String内部定义了final char[] value用于存储字符串数据
  • 4.String代表不可变的字符序列。简称:不可变性
    体现:1.当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原有的value进行赋值。//见内存解析
    2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。s1+="def";则内存地址已经变了
    3.当调用String的replace()方法修改指定的字符或字符串时,也需要重新指定内存区域赋值。String s3="abc"; String s4=s3.replace('a', 'm');
  • 5.通过字面量的方式(如String s1=“abc”;)(区别于new的方式)给一个字符串赋值,此时的字符串值声明在方法区的字符串常量池中
  • 6.字符串常量池中是不会存储相同内容的字符串的

面试

面试题:String s=new String(“abc”);方式创建对象,在内存中创建了几个对象?
2个:1个是堆空间中new的String的结构value,另一个是char[]对应的字符串常量池中的数据,即"abc"

内存解析1

在这里插入图片描述

内存解析2

在这里插入图片描述

内存解析3

在这里插入图片描述

内存解析4

小结论

1.常量与常量的拼接结果在常量池中,且常量池中不会存在相同内容的常量
2.只要其中有一个是变量,结果就在堆中
3.intern()方法可以返回字符串常量池中的地址值

String s1="hello";
String s2="world";
String S3="helloworld";
String s4="hello"+"world";
String s5=s1+"world";
String s6=s1+s2;
String s7=s5.intern();//此时返回的s7是常量池中已经存在的"helloworld"的地址值

解析:
在这里插入图片描述

1.2 String的一些方法

  • 1.int length():返回字符串的长度
  • 2.char charAt(int index):返回某索引处的字符
  • 3.boolean isEmpty():判断是否是空字符串
  • 4.String toLowerCase():使用默认语言环境,将String中的所有字符转换为小写
  • 5.String toUpperCase():使用默认语言环境,将String中的所有字符转换为大写
  • 6.String trim():返回字符串的副本,忽略前导空白和尾部空白如" h ello "返回的是"h ello"
  • 7.boolean equals(Object obj):比较字符串的内容是否相等
  • 8.boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
  • 9.String concat(String str):将字符串str连接到此字符串的结尾。等价于”+“
  • 10.int compareTo(String anotherString):比较两个字符串的大小
    若返回是负数,则当前对象小;返回0,相等。对比是把字符串从前往后的每一个字符的ASCII码做对比
  • 11.String substring(int beginIndex):返回一个新的字符串,它是此字符串从beginIndex开始截取到最后一个的子字符串
  • 12.String substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串
    一般java中都是左闭右开的
  • 13.boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
  • 14.boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
  • 15.boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始//意思就是字符串中的第toffset个开始的字符串是否是prefix
  • 16.boolean contains(CharSequence s):当且仅当此字符串包含字符序列(字符串)s时,返回true
  • 17.int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的开头索引,若没有找到,则返回-1
  • 18.int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
  • 19.int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
  • 20.int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
    注:indexOf和lastIndexOf方法如果未找到都是返回-1。调用indexOf(str)和lastIndexOf(str)返回值相同的情况:存在唯一的str或不存在str
  • 21.String replace(char oldChar, char newChar):返回一个新的字符串,它是通过newChar替换此字符串中出现的所有oldChar得到的
  • 22.String replace(CharSequence target, CharSequence replacement):使用指定的字符序列替换所有的目标字符序列
  • 23.String replaceAll(String regex, String replacement):使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串
  • 24.String replaceFirst(String regex, String replacement):使用给定的replacement替换此字符串匹配给定的正则表达式的第一个字符串
  • 25.boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
  • 26.String[] split(String regex):(切片)根据正则表达式的匹配拆分此字符串
  • 27.String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。

String与char[]之间的转换

String—>char[]:调用String的一个方法toCharArray():char[] arr=str.toCharArray();
char[]—>String:调用String的构造器:String str = new String(arr);

String与byte[]之间的转换

String—>byte[]:调用String的一个方法getBytes():byte[] b = str.getBytes();
byte[]—>String:调用String的构造器:String str = new String(b);

  • 编码:字符集—>字节(看得懂—>看不懂的二进制数据)(String—>byte[])
  • 解码:编码的逆过程,字节—>字符串(看不懂的二进制数据—>看得懂)(byte[]—>String)
    说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码
String s1="abc123中国";
byte[] b = s1.getBytes();//使用默认的字符集进行转换编码,因为我们之前给idea设置的是utf-8,所以默认的是utf-8
System.out.println(Arrays.toString(b));

byte[] b2 = s1.getBytes("gbk");//使用gbk字符集来进行编码
System.out.println(Arrays.toString(b2));
//utf-8和gbk都可以把汉字编码成数字,前者用三个数字来表述一个汉字,后者用两个数字表述一个汉字;二者存放英文字符的编码都是一样的

String s2 = new String(b);//使用默认的字符集进行解码,即使用utf-8来解码
System.out.println(s2);

String s3 = new String(b2, "gbk");//需要使用gbk来解码,若使用utf-8解码,则会出现乱码
System.out.println(s3);

1.3 StringBuffer和StringBuilder

String,StringBuffer,StringBuilder三者的异同?

  • String:不可变的字符序列
  • StringBuffer:可变的字符序列:线程安全的(里面的方法都是同步方法),效率低
  • StringBuilder:可变的字符序列:线程不安全的,效率高
    三者底层都是使用char[]存储的,只不过String加了final,后面两个没加

正是因为String是不可变的字符序列,所以它的对字符串操作的一些方法都有返回值类型,如String toUpperCase()
而StringBuffer和StringBuilder是可变的字符序列,所以对字符串操作的一些方法虽然有返回值类型的,如StringBuffer append(xxx),但是一般不接受,如str.append(),因为str已经变了,很少用另一个字符串去接收

String与StringBuffer、StringBuilder之间的转换

  • String—>StringBuffer,StringBuilder:调用StringBuffer,StringBuilder的构造器
  • StringBuffer,StringBuilder—>String:调用String的构造器或者调用StringBuffer,StringBuilder的toString()方法

对比String,StringBuffer,StringBuilder的效率:
从高到低排列:StringBuilder > StringBuffer > String

String源码分析:
String s=new String();/底层是char[] value=new char[0];
String s=new String(“abc”);底层是char[] value=new char[]{'a', 'b', 'c'};
StringBuffer源码分析(StringBuilder类似):
StringBuffer s=new StringBuffer();char[] value=new char[16];底层创建了一个长度是16的char数组
s.append(‘a’);value[0]='a';
StringBuffer s=new StringBuffer(“abc”);char[] value=new char["abc".length()+16];底层创建了一个长度为3+16=19的char数组
StringBuffer常见问题和错误(StringBuilder类似)

  • 问题1:System.out.println(s);//输出是3
  • 问题2:扩容问题:如果要添加的数据底层的数组存不下了,那就需要扩容底层的数组。默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。特殊情况见源码
  • 指导意义:开发中如果需要一个字符串经常变,如经常调用append(),则尽量用StringBuffer(当可能出现线程安全问题时)和StringBuilder(当没有线程安全问题时),而少使用String。开发中建议使用StringBuffer(int capacity)和StringBuilder(int capacity)构造器,尽量避免去扩容

1.4 StringBuffer和StringBuilder的方法

  • 1.StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串的拼接s1.append(1);s1.append('1');
  • 2.StringBuffer delete(int start, int end):删除指定位置的内容s1.delete(2,4);
  • 3.StringBuffer replace(int start, int end, String str):把[start, end)位置替换为strs2.replace(2,4,"hello");
  • 4.StringBuffer insert(int offset, xxx):在指定位置插入xxxs3.insert(2,false);
  • 5.StringBuffer reverse():把当前字符序列反转s3.reverse();
  • 6.public int indexOf(String str):返回str在字符串中首次出现的位置
  • 7.public String subString(int start, int end):返回[start, end)的子字符串,此时此StringBuffer或StringBuilder的字符串没有改变,只是返回String类型的子串
  • 8.public int length()
  • 9.public char charAt(int n):返回第n个的字符
  • 10.public void setCharAt(int n, char ch):将第n个的字符换成ch

由于append()等方法返回的是StringBuffer或StringBuilder字符串本身,因此可以使用方法链原理,即多次调用:s.append().append().append().append();
总结

  • 增:append(xxx)
  • 删:delete(int start, int end)
  • 改:setCharAt(int n, char ch) 和 replace(int start, int end, String str)
  • 查:charAt(int n)
  • 插:insert(int offset, xxx)
  • 长度:length()
  • 遍历:直接sout输出,或sout输出toString()方法,或for循环+charAt(n)输出

1.5 练习题:滑动窗口

import org.junit.Test;

import java.util.Arrays;

/**
 * @author JiaMing
 * @create 08-22 18:05
 * @description 获取两个字符串中最大相同字串。比如:str1="abcwerthelloyuiodef12345",str="cvghellobnm12345"
 * 提示:将短的那个串进行长度依次递减的子串与较长串比较
 */
public class Exer5 {
    public String maxSubString(String s1, String s2){
        //由于可能存在多个长度相同的最大相同子串,因此创建builder等会方便存进去,不用数组存是因为不知道有几个最大相同子串,所以不知道数组的长度该创建多大
        StringBuilder builder = new StringBuilder();
        //先选出哪个长哪个短
        String maxStr = s1.length() >= s2.length() ? s1 : s2;
        String minStr = s1.length() < s2.length() ? s1 : s2;

        //外层循环逐次加一
        for (int i = 0; i < maxStr.length(); i++) {
            //内层循环的意思是:第一次比较的是subStr即"cvghellobnm12345",maxStr不包含subStr
            //第二次比较的是:subStr="cvghellobnm1234","vghellobnm12345",maxStr不包含subStr
            //第三次比较的是:subStr="cvghellobnm123","vghellobnm1234","ghellobnm12345",maxStr不包含subStr
            //...这样依次循环
            for (int x=0,y=minStr.length()-i; y<=minStr.length(); x++,y++) {
                String subStr=minStr.substring(x,y);
                if(maxStr.contains(subStr)){
                    //如果maxStr包含subStr,则存到builder中,并且把此次循环继续执行,看看是否有多个长度相同的最大相同子串并存到builder中
                    builder.append(subStr+",");
                }
            }
            //当这一次的内层循环结束并且builder中已经有最大子串时,则结束外层循环,不需要再找了
            if(builder.length()!=0){
                break;
            }
        }

        //先把builder转换成String类型,再去掉最后的","   然后并切片成多份,命名到数组中
        String[] split = builder.toString().replaceAll(",$", "").split("\\,");
        return Arrays.toString(split);//将数组转换成String类型并返回
    }

    @Test
    public void test() {
        String str1="abcwerthelloyuiodef12345";
        String str2="cvghellobnm12345";
        String maxSubString = maxSubString(str1, str2);
        System.out.println(maxSubString);
    }
}

2 JDK8 之前日期和时间的API测试

2.1 java.lang.System类

System类提供的public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差

2.2 java.util.Date类

①两个构造器的使用
->空参构造器:Date():创建一个对应当前时间的Date对象。Date d1 = new Date();
->参数为long型整数的构造器:Date(long date):创建指定毫秒数的Date对象,参数中的date是与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。Date d2 = new Date(1661156872226L); System.out.println(d2.toString());//输出是Mon Aug 22 16:27:52 CST 2022
②两个方法的使用
->toString():显式当前的年、月、日、星期几、时、分、秒。
->getTime():获取当前Date对象对应的毫秒数(时间戳),和java.lang.System.currentTimeMillis()功能一致。System.out.println(d1.getTime());

2.3 java.sql.Date类

java.sql.Date类是对应数据库中的日期类型的变量,只有在和数据库交互中才会使用这个(注:java.sql.Date是java.util.Date的子类)
->创建java.sql.Date对象。java.sql.Date d3 = new java.sql.Date(135646872313L);
java.sql.Date也可以调用toString()方法
->如何将java.util.Date对象转换为java.sql.Date对象。

java.util.Date d1 = new java.util.Date();
java.sql.Date d4 = new java.sql.Date(d1.getTime());

2.4 java.text.SimpleDateFormat类

SimpleDateFormat的使用:SimpleDateFormat是对日期Date类的格式化和解析的类
①当使用默认构造器进行SimpleDateFormat的实例化,按照默认的方式格式化和解析:SimpleDateFormat sdf = new SimpleDateFormat();
 两个操作:
 ->格式化:日期—>字符串

Date d1 = new Date();
String s2 = sdf.format(d1);
System.out.println(s2);//输出的是中文:2022/8/22 下午7:42

  ->解析:格式化的逆过程,字符串—>日期

String s3="2022/9/27 上午11:20";//字符串必须是这种格式,如果不是这种格式,会抛"ParseException"异常
Date d2=sdf.parse(s3);
System.out.println(d2);//此时输出的就又是Tue Sep 27 11:20:00 CST 2022

②当调用带参构造器进行SimpleDateFormat的实例化,按照指定的方式格式化和解析:SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
其中,yyyy代表4位数是年份,MM代表2位数的月份,dd代表2位数的日期,hh代表2位数的小时,mm代表2位数的分钟,ss代表2位数的秒
当然构造器的参数还有其他格式,如"yyyyy.MMMMM.dd GGG hh:mm:aaa"输出的格式是"02001.July.04 AD 12:08 PM"等等,具体可见java API
 两个操作:
 ->格式化:日期—>字符串

String s4 = sdf2.format(d1);//输出2022-08-22 07:55:07,
//这个格式和构造器中的参数类型是相同的

 ->解析:格式化的逆过程,字符串—>日期

Date d3 = sdf2.parse("2021-05-05 2:12:12");//要求字符串必须符合
//SimpleDateFormat的构造器的参数格式,否则会抛异常,
//输出为Wed May 05 02:12:12 CST 2021

2.5 java.util.Calendar类(日历类)

java.util.Calendar类是一个抽象类,主要用于完成日期字段之间相互操作的功能
①实例化
 方式一:创建其子类(GregorianCalendar)的对象
 方式二:调用其静态方法getInstance()

Calendar c1 = Calendar.getInstance();//因为Calendar是抽象类,
//所以getInstance得到的不是Calendar类,而是其子类GregorianCalendar,
//这是一个匿名子类的非匿名对象

②常用方法

  • int get(int field):获取想得到的时间信息;field可取YEAR,MONTH,DAY_OF_WEEK,DAY_OF_YEAR,HOUR_OF_DAY,MINUTE,SECOND,即获取年份、月份、这一周的第几天、这一年的第几天,这一天的第几个小时,分钟,秒。int days = c1.get(Calendar.DAY_OF_MONTH);//本月的第几天:此时为8月22日,所以是第22天
  • void set(int field, int value):修改日历中field为value,c1.set(Calendar.DAY_OF_MONTH,23);//修改本月的第几天为第23天
  • void add(int field, int amount):把日历中filed加上amount。c1.add(Calendar.DAY_OF_MONTH,3);//把本月的第几天加上3即23+3=26 c1.add(Calendar.DAY_OF_MONTH,-1);//把本月的第几天减去1天即25
  • final Date getTime():日历类转换成Date,Date d1 = c1.getTime();
  • final void setTime(Date date):Date转换成日历类,Date d2 = new Date(); c1.setTime(d2);//没有返回值,直接把d2的时间赋给c1

注意:Calendar有偏移量
即获取月份时:一月是0,二月是1…十二月是11。
获取星期时,周日是1,周一是2…周六是7

2.6 练习题:”三天打鱼两天晒网“

/**
 * @author JiaMing
 * @create 08-22 21:50
 * @description 练习二:从1990-01-01开始”三天打鱼两天晒网“,在2022年5月15日是打鱼还是晒网
 * 分析:可知五天一循环,则可以求这一天是五天中的第几天(总天数%5==1,2,3:打鱼,总天数%5==4,0:晒网),即求出2022-05-15与1990-01-01中间隔了多少天
 */
public class DaYu480 {
    @Test
    public void test() throws ParseException {
        String s1="1990-01-01";
        String s2="2022-05-15";

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date d1 = sdf.parse(s1);
        Date d2 = sdf.parse(s2);

        long time=d2.getTime()-d1.getTime();//两个时间段中间隔了多少毫秒

        long days=0;//两个时间段中间隔了多少天
        //一天有24*60*60*1000毫秒
        if(time%(24*60*60*1000)==0){
            //当全部除尽时,那么中间隔了天就是算出来的商
            days=time/(24*60*60*1000);
        }else {
            //当除不尽时就向上取整
            days=time/(24*60*60*1000)+1;
        }

        long doWhat=days%5;//五天循环中的第几天

        if(doWhat==1 || doWhat==2 || doWhat==3){
            System.out.println("打鱼");
        }else System.out.println("晒网");
    }
}

上述几个时间类之间的关系
在这里插入图片描述

3 JDK8 中新日期时间API

引出

由于JDK8之前的关于时间的包、类等具有可变性(如Calendar可以设置改变)、偏移性(如Date中的年份是从1900开始算的,月份是从0开始的,这和生活中不符)、格式化麻烦、线程不安全、不能处理闰秒等,因此JDK8之后有了更合适的关于时间操作的API:java.time,java.time.chrono,java.time.format,java.time.temporal,java.time.zone等

  • java.time:包含值对象的基础包
  • java.format:格式化和解析时间和日期
  • java.time.temporal:包含底层框架和扩展特性
  • java.time.zone:包含时区支持的类

3.1 java.time.LocalDateTime类

java.time使用的最频繁,包含本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)、持续时间(Duration)、时间线上的瞬时点(Instant)。其中LocalDateTime使用的频率更高,以下以LocalDateTime为例使用其方法,LocalDate、LocalTime类似

  • now():(静态方法)获取当前的日期+时间,即实例化
LocalDateTime ldt = LocalDateTime.now(); 
System.out.println(ldt);//2022-08-23T10:32:54.146038400
  • of():(静态方法)设置指定的年、月、日、时、分、秒;并且没有偏移量。也属于实例化
LocalDateTime ldt2 = LocalDateTime.of(2022, 8, 23, 10, 6, 23);
//也可以只设置时分秒,具体选择of()方法中的参数
  • getXxx():获取相关属性;并且没有偏移量.
System.out.println(ldt.getDayOfMonth());//获取本月的第几天:23
System.out.println(ldt.getMinute());//获取现在是这个小时的几分:11
System.out.println(ldt.getMonth());//获取月份:AUGUST
System.out.println(ldt.getMonthValue());//获取月份的的数字:8
System.out.println(ldt.getDayOfWeek());//获取星期几:TUESDAY
  • withXxx():设置相关属性;具有不可变性
LocalDateTime ldt3 = ldt.withDayOfMonth(30);
//此时ldt是今天的日期23,ldt3是返回修改过的日期30,因为ldt没有变,
//所以是不可变性
  • plusXxx(),minusXxx():加减相关属性,具有不可变性
LocalDateTime ldt5 = ldt.plusMonths(3);//ldt5是ldt月份往后推3个月的日期
LocalDateTime ldt6 = ldt.minusDays(6);//ldt6是ldt往前推6天的日期

3.2 Instant类

Instant:时间线上的一个瞬时点。Instant的使用类似于java.util.Date类

  • now():(静态方法)获取此时本初子午线的标准时间,属于实例化
    Instant i1 = Instant.now();System.out.println(i1);//2022-08-23T02:50:28.259934400Z----输出的是此时本初子午线那的时间
  • ofEpochMilli(long milli):(静态方法)通过给定的毫秒数,获取Instant实例,和Data(long milli)类似;属于实例化
    Instant i3 = Instant.ofEpochMilli(1661223459724L);
  • atOffset(ZoneOffset offset):结合时区的偏移量来创建一个 OffsetDateTime
OffsetDateTime i2 = i1.atOffset(ZoneOffset.ofHours(8));//我们这是东八区,所以参数是ZoneOffset.ofHours(8)
System.out.println(i2);//输出2022-08-23T10:53:49.070431400+08:00`
  • toEpochMilli():获取自1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳,和Date.getTime()类似。long l = i1.toEpochMilli();

由以上可知,一般实例化的方法都是静态的,其他的方法都是非静态的

3.3 java.time.format.DateTimeFormatter类

格式化或解析日期、时间的类,类似于SimpleDateFormat
该类提供了三种格式化方法:

  • 方式一:预定义的标准格式。如ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
    DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    ①格式化:日期—>String
    LocalDateTime ldt = LocalDateTime.now();String s1 = dtf.format(ldt);
    ②解析:String—>日期
    TemporalAccessor p1 = dtf.parse("2022-08-23T11:32:22.6186321");//标准格式实例化的解析只能是这种格式,否则会抛异常
  • 方式二:本地化相关的格式。如:ofLocalizedDateTime(参数),参数可选择:FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT。(类似可知ofLocalizedDate和ofLocalizedTime)
DateTimeFormatter dtf2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);//格式化之后输出2022/8/23 上午11:41
DateTimeFormatter dtf2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);//2022年8月23日 上午11:41:14
DateTimeFormatter dtf2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//2022年8月23日 上午11时41分14秒
格式化和解析的操作:
String s2 = dtf2.format(ldt);
TemporalAccessor p2 = dtf2.parse("2022/8/23 上午11:45");//实例化时参数是SHORT时的格式
  • 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”) (重点)
DateTimeFormatter dtf3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
①格式化
String s3 = dtf3.format(LocalDateTime.now());//输出2022-08-23 11:50:21
②解析
TemporalAccessor p3 = dtf3.parse("2022-08-23 11:50:21");

3.4 其他API

 ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris
 ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:
Asia/Shanghai等
 Clock:使用时区提供对当前即时、日期和时间的访问的时钟。
 持续时间:Duration,用于计算两个“时间”间隔
 日期间隔:Period,用于计算两个“日期”间隔
 TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整
到“下一个工作日”等操作。
 TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用
TemporalAdjuster 的实现。

3.5 与传统日期处理的转换

在这里插入图片描述

4 Java比较器

4.1 Comparable接口

一、说明:java中的对象,正常情况下,只能进行比较地址(==、!=),不能使用 > 或 < 。但是在开发中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。如何实现?使用两个接口中的任何一个:Comparable或Comparator
二、Comparable接口的使用(自然排序:强行对实现它的每个类的对象进行整体排序)

  • 1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式
  • 2.像String、包装类重写compareTo(obj)方法以后,进行了从小到大的排列
    String和Character:按照字符串/字符中字符的Unicode值进行比较
    Date、Time等:后面的日期时间比前面的日期时间大
    Boolean:true 对应的包装类实例大于 false 对应的包装类实例
  • 3.重写compareTo(obj)的规则:
    如果当前对象this大于形参obj,则返回正整数
    如果当前对象this小于形参obj,则返回负整数
    如果当前对象this等于形参obj,则返回零
  • 4.对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法,在compareTo(obj)方法中指明如何排序
  • 5.实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或 Arrays.sort 进行自动排序
public class CompareTest488 {
    @Test
    public void test1(){
        String[] arr=new String[]{"AA","MM","GG","DD","KK","CC"};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    @Test
    public void test2(){
        Goods[] arr=new Goods[5];
        arr[0]=new Goods("lenovoMouse",34);
        arr[1]=new Goods("dellMouse",43);
        arr[2]=new Goods("xiaomiMouse",12);
        arr[3]=new Goods("huaweiMouse",65);
        arr[4]=new Goods("microsoftMouse",43);

        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}


class Goods implements Comparable{
    private String name;
    private double price;

    public Goods(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        //指明按照什么方式进行排序:如按照价格从低到高排序,如果价格相等,则按照产品名称从低到高排序
        //方式1:自己写个方法进行排序
        if(o instanceof Goods){
            Goods goods = (Goods) o;
            if(this.price>goods.price) return 1;
            else if (this.price<goods.price) return -1;
            else{
                return this.name.compareTo(goods.name);//调用name(String类型)的compareTo()方法进行比较
                //return -this.name.compareTo(goods.name);//前面加一个"-"号,则是按照产品名称从高到低排序
            }

            //方式2:使用包装类中的比较方法compare
            //return Double.compare(this.price, goods.price);
        }
       throw new RuntimeException("传入的数据类型不一致");
    }
}

4.2 Comparator接口

三、Comparator接口的使用(定制排序)

  • 1.当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序
  • 2.重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2
  • 3.可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
public class CompareTest491 {
    @Test
    public void test1(){
        String[] arr=new String[]{"AA","MM","GG","DD","KK","CC"};
        //将上述字符串数组从大到小排
        //由于默认的Arrays.sort()是调用String的compareTo()方法的(String实现了Comparable接口),而String的compareTo()方法是从小到大的,
        //要想临时进行一次从大到小的排序,可以在参数里面写一个Comparator的匿名实现类的匿名对象,然后重写compare方法,进而设置从大到小排
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                    return -o1.compareTo(o2);
            }
        });
        System.out.println(Arrays.toString(arr));
    }

    @Test
    public void test2(){
        Goods[] arr=new Goods[5];
        arr[0]=new Goods("lenovoMouse",34);
        arr[1]=new Goods("dellMouse",43);
        arr[2]=new Goods("xiaomiMouse",12);
        arr[3]=new Goods("huaweiMouse",65);
        arr[4]=new Goods("microsoftMouse",43);

        //这时如果想按照名称从低到高排序,再按照价格从高到低排序
        //由于Goods类中的compareTo()方法的排序和想要的排序方式不一样,因此我们可以使用定制的排序
        //因此在Arrays.sort()参数中new一个Comparator并重写compare()方法,实现想要的排序方式
        Arrays.sort(arr, new Comparator<Goods>() {
            @Override
            public int compare(Goods o1, Goods o2) {
                if(o1.getName().equals(o2.getName())){
                    return -Double.compare(o1.getPrice(),o2.getPrice());//前面有个负号,表示从高到低排序
                    //一般情况下,String、包装类等重写的compareTo()或compare()方法都是从小到大排序的,所以想要从大到小排序的话需要在前面加"-"
                }else{
                    return o1.getName().compareTo(o2.getName());
                }
            }
        });

        System.out.println(Arrays.toString(arr));
    }
}

四、Comparable接口与Comparator接口使用的对比

  • 1.Comparable是需要对比的类去实现接口,一旦设置好之后,可以保证Comparable接口实现类的对象在任何位置都可以比较大小
    Comparator是临时设置的排序方式,什么时候需要比较,就临时创建一个Comparator的实现类
  • 2.调用Comparable中的compareTo()方法是用其实现类的对象(如Goods的对象goods)去调用的,参数是另一个需要对比的对象。name1.compareTo(name2);
    调用Comparator中的compare()方法是用其实现类(如Double)去调用的,参数是两个需要对比的对象。Double.compare(d1,d2);

5 System类

  • System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。
    该类位于java.lang包
  • 由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便的进行调用
  • 成员变量
    ->System类内部包含in、out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)
  • 成员方法
    ->native long currentTimeMillis():
    该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数
    ->void exit(int status):
    该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表
    异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等
    ->void gc():
    该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则
    取决于系统中垃圾回收算法的实现以及系统执行时的情况
    ->String getProperty(String key):
    该方法的作用是获得系统中属性名为key的属性对应的值。系统中常见
    的属性名以及属性的作用如下表所示:
    在这里插入图片描述
String javaVersion = System.getProperty("java.version");
System.out.println("java的version:" + javaVersion);

6 Math类

java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回
值类型一般为double型
abs------>绝对值
acos,asin,atan,cos,sin,tan------>三角函数
sqrt------>平方根
pow(double a,doble b)------>a的b次幂
log------>自然对数
exp------>e为底指数
max(double a,double b)
min(double a,double b)
random()------>返回0.0到1.0的随机数
long round(double a)------>double型数据a转换为long型(四舍五入)
toDegrees(double angrad)------>弧度转换为角度
toRadians(double angdeg)------>角度转换为弧度
向上取整------>ceil(单词意思:天花板)
向下取整------>floor(单词意思:地板)

7 BigInteger与BigDecimal

7.1 BigInteger类

Integer类作为int的包装类,能存储的最大整型值为231-1,Long类也是有限的,最大为263-1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
java.math包的BigInteger可以表示不可变的任意精度的整数。BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
构造器:BigInteger(String val):根据字符串构建BigInteger对象
 public BigInteger abs():返回此 BigInteger 的绝对值的 BigInteger。
 BigInteger add(BigInteger val) :返回其值为 (this + val) 的 BigInteger
 BigInteger subtract(BigInteger val) :返回其值为 (this - val) 的 BigInteger
 BigInteger multiply(BigInteger val) :返回其值为 (this * val) 的 BigInteger
 BigInteger divide(BigInteger val) :返回其值为 (this / val) 的 BigInteger。整数相除只保留整数部分。
 BigInteger remainder(BigInteger val) :返回其值为 (this % val) 的 BigInteger。
 BigInteger[] divideAndRemainder(BigInteger val):返回包含 (this / val) 后跟(this % val) 的两个 BigInteger 的数组。
 BigInteger pow(int exponent) :返回其值为 (thisexponent) 的 BigInteger。

7.2 BigDecimal类

一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。

构造器

public BigDecimal(double val)
public BigDecimal(String val)

常用方法

public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
public void testBigInteger() {
BigInteger bi = new BigInteger("12433241123");
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("11");
System.out.println(bi);
// System.out.println(bd.divide(bd2));
System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
}
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐