文章目录

  • 1. String 特性
  • 2. String的字面量创建 和 new 对象形式
  • 3. String 字符串 内存存储原理
  • 4. String 不同拼接对比 效果
  • 5. String 和 数组 常用的混合面试题
  • 6. JVM涉及字符串 内存结构
  • 7. String 常用方法
  • 8. 涉及到String 类与其他结构之间的转换
  • 8.1 常见的小错误
  • 8.2 String 和 int 之间的转换
  • 8.3 String 和 char[]字符组 之间的转换
  • 8.4 String字符串 和 byte[]字节数组 之间的转换
  • 9. String 拼接 小面试题
  • 10. StringBuffer 和 StringBuilder 介绍
  • 11. String ,StringBuffer,StringBuilder 源码分析
  • 12. StringBuffer 和 StringBuilder类常用的方法
  • 13. 对比String ,StringBuffer,StringBuilder的效率
  • 14. Java 时间日期 的相关API
  • 15. IDEA 的 debug调试
  • 16. JDK8之前日期时间API SimpleDateFormat类
  • 16.1 SimpleDateFormat默认无参数情况
  • 16.2 SimpleDateFormat有参数情况
  • 17. JDK8之前日期时间API Calendar(日历类)
  • 18. JDK8 新时间日期的 API (java.time)
  • 18.1 JDK8 的 java.time的介绍
  • 18.2 LocalDate , LocalTime , LocalDateTime的使用
  • 18.3 Instant 瞬时
  • 18.4 JDK8 新日期时间API java.time.format.DateTimeFormatter
  • 18.5 其他API
  • 19. Java比较器
  • 19. 为什么要用Java比较器?
  • 19.2 Comparable接口使用
  • 19.3 定制排序:java.util.Comparator
  • 19.4 Comparable接口 与 Comparator的使用的对比
  • 20. System类,Math类,BigInteger 与BigDecimal类
  • 20.1 System类
  • 20.2 Math类
  • 20.3 BigInteger 与BigDecimal类


1. String 特性

  • String声明为final的,不可被继承。
  • String实现Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小。
  • String内部定义了final char[] value 用于存储字符串数据。
  • String:代表不可变的字符序列。简称:不可变性。

java 笔记pdf java笔记完整版_java

java 笔记pdf java笔记完整版_java_02


(注意:上面的final,如果重新赋值,并且内容不同,就是重新获得新的地址,并不会在原来的地址上赋值!!!!)


面试题:== 和 equals的区别?

  • 比较s1和s2的地址是否相同。
  • 比较字符串内容值是否相同。
package com.holmes.java04;

import org.junit.Test;

public class StringTest {
    @Test
    public void test1(){
        String s1 = "abc";
        String s2 = "abc";

        System.out.println(s1 == s2);//比较s1和s2的地址是否相同。
        System.out.println(s1.equals(s2));//比较字符串内容值是否相同。
    }
}

String字符串,什么情况下,重新指定内存区域进行赋值:

无论,重复赋值,还是拼接字符串,还是修改指定替换字符串等,都是要重新指定内存区域进行赋值!!!

2. String的字面量创建 和 new 对象形式


String对象创建的四种方式:

java 笔记pdf java笔记完整版_后端_03

整体上,也就两种方式:一种字面量,一种new创建对象。

  • 通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
  • 通过 new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对象的值。
package com.holmes.java04;

import org.junit.Test;

public class StringTest {
    @Test
    public void test1(){
        //通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
        String s1 = "javaEE";
        String s2 = "javaEE";

        //通过 new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对象的值。
        String s3 = new String("javaEE");
        String s4 = new String("javaEE");

        System.out.println(s1 == s2);//true
        System.out.println(s1 == s3);//false
        System.out.println(s3 == s4);//false
    }
}

3. String 字符串 内存存储原理


字面形式和new + 对象的内存存储原理:

java 笔记pdf java笔记完整版_System_04


java 笔记pdf java笔记完整版_System_05

面试题:String s = new String(“abc”);方式创建对象,在内存中创建了几个对象?

两个,一个是堆空间中new的对象,另一个是char[]对应常量池中的数据:“abc”。

4. String 不同拼接对比 效果

下面的拼接效果必须牢记!!!!

java 笔记pdf java笔记完整版_java 笔记pdf_06

package com.holmes.java04;

import org.junit.Test;

public class StringTest {
    @Test
    public void test1(){
        String s1 = "javaEE";
        String s2 = "hadoop";

        String s3 = "javaEEhadoop";
        String s4 = "javaEE"+"hadoop";

        String s5 = s1 + "hadoop";
        String s6 = "javaEE" + s2;
        String s7 = s1 + s2;
        String s8 = (s1 + s2).intern();

        //没有变量相加,仅仅只是字符串,这样声明的s4的内存地址就仅仅在常量池中。
        System.out.println(s3 == s4); //true

        //只要有变量相加的,那么该创建方式就是new对象形式,也就是要存储到堆内存地址。
        System.out.println(s3 == s5); //false
        System.out.println(s3 == s6); //false
        System.out.println(s5 == s6); //false
        System.out.println(s3 == s7); //false
        System.out.println(s5 == s7); //false
        System.out.println(s6 == s7); //false

        //通过调用intern()方法,返回值就在常量池中!
        System.out.println(s3 == s8); //true
    }
}

5. String 和 数组 常用的混合面试题

package com.holmes.java04;

public class StringTest2 {

    //也算涉及到了String类型的不可变性。
    //这里与下面change函数中的str的内存地址不同!
    String str = new String("good");
    char[] ch = {'t','e','s','t'};

    public void change(String str,char ch[]){

        //这里的str与上面的str不同!!地址不同,这里是形参是参数!!!
        str = "test ok";
        ch[0] = 'b';

    }

    public static void main(String[] args) {

        StringTest2 ex = new StringTest2();
        ex.change(ex.str,ex.ch);

        //有人疑惑这里为什么不是test ok, 原因很简单,因为这里的ex.str是作为形参传入。
        System.out.println(ex.str); //good

        //至于数组没有不可变形,对应地址相同,只不过内容中的第一个值变化了而已。
        System.out.println(ex.ch); //best
    }
}

6. JVM涉及字符串 内存结构


JDK1.6版本,字符串常量池都在方法区中:

java 笔记pdf java笔记完整版_开发语言_07


JDK除了1.7版本,字符串常量池在堆中:

java 笔记pdf java笔记完整版_System_08


JDK1.8以及以后的版本,字符串常量池都在方法区中:

java 笔记pdf java笔记完整版_System_09

7. String 常用方法


java 笔记pdf java笔记完整版_java 笔记pdf_10


java 笔记pdf java笔记完整版_System_11

问题一:什么情况下,indexOf(str) 和 lastIndexOf(str)返回值相同?

答:情况一:存在唯一的一个str。情况二:不存在str时。
此外,indexOf 和 lastIndexOf方法如果未找到都是返回-1。


java 笔记pdf java笔记完整版_System_12

上面的replaceAll()函数方法,matches()函数方法,涉及到正则表达式内容,如下:

java 笔记pdf java笔记完整版_开发语言_13

8. 涉及到String 类与其他结构之间的转换

8.1 常见的小错误


首先,纠正一个经常犯下的错误:

String str = "123";
//错误的,强转的前提必须是子父类的前提下!!!
int num = (int)str;

8.2 String 和 int 之间的转换


String 转 int:(调用包装类的静态方法,Integer.parseXxx())

String str = "123";
//调用包装类的静态方法,才是正确的
int num = Integer.parseInt(str)

int 转 String:(调用包装类的静态方法,Integer.toString() 和 String.valueOf())

String s2;
String s3;
int num2 = 123;
//方式一:Integer.toString()方法
s2 = Integer.toString(num2);
//方式二:String.valueOf()方法
s3 = String.valueOf(num2);

System.out.println(s2.getClass()+ "," +s3.getClass());
//class java.lang.String , class java.lang.String

//方式三:就是通过加空字符串 "" 。
String s4 = 123 + "";

8.3 String 和 char[]字符组 之间的转换

java 笔记pdf java笔记完整版_开发语言_14

牢记toCharArray()函数方法:

package com.holmes.java04;

import org.junit.Test;

public class StringTest {
    @Test
    public void test1(){

        String str1 = "abc123";

        //调用String的toCharArray()拆分字符串 转为 字符数组。
        char[] charArray = str1.toCharArray();
        //遍历一下charArray
        for (int i=0;i<charArray.length;i++){
            System.out.println(charArray[i]);
        }

        char[] arr = new char[]{'h','e','l','l','o'};
        //直接将字符数组当作参数放入字符串对象,就直接形成了字符串
        String str2 = new String(arr);
        System.out.println(str2);


    }
}

8.4 String字符串 和 byte[]字节数组 之间的转换

这里就会出现一个编码和解码的一个效果:

java 笔记pdf java笔记完整版_后端_15


String 转为 byte[]:
(调用String的getBytes()方法)

package com.holmes.java04;

import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.Arrays;

public class StringTest {
    @Test
    public void test1() throws UnsupportedEncodingException {

        //调用String的getBytes()方法
        String str1 = "abc123中国";
        byte[] bytes = str1.getBytes(); //使用默认的字符集(utf-8),进行转换
        //Arrays.toString()方法显示字符串。
        System.out.println(Arrays.toString(bytes));
        //[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67],这里结果就是aciII码
        //此外,在utf-8当中一个汉字是占3个字节。

        //使用gbk编码,就要添加参数
        byte[] gbks = str1.getBytes("gbk");
        System.out.println(Arrays.toString(gbks));
        //[97, 98, 99, 49, 50, 51, -42, -48, -71, -6] 在gbk中一个汉字包含两个字节。


    }
}

byte[]字节数组 转 String字符串:
(new对象参数传入,来转换)

package com.holmes.java04;

import org.junit.Test;

import java.io.UnsupportedEncodingException;

public class StringTest {
    @Test
    public void test1() throws UnsupportedEncodingException {

        //调用String的getBytes()方法
        String str1 = "abc123中国";
        byte[] bytes = str1.getBytes(); //使用默认的字符集(utf-8),进行转换
        byte[] gbks = str1.getBytes("gbk");

        //同样这里也是用默认的字符集(utf-8)来进行解码
        String str2 = new String(bytes);
        System.out.println(str2);

        //因为这里是通过gbk编码的,但使用utf-8来解码就会乱码
        String str3 = new String(gbks);
        System.out.println(str3);

        //abc123中国
        //abc123�й�
    }
}

9. String 拼接 小面试题

因为一个final,就导致结果不同,牢记常量与常量拼接的结果是存储在常量池中,且常量池不会存在相同内容的常量。final声明后变量就变成了常量!

package com.holmes.java04;

import org.junit.Test;

public class StringTest {
    @Test
    public void test1(){
        String s1 = "javaEEhadoop";
        String s2 = "javaEE";
        String s3 = s2 + "hadoop";
        System.out.println(s1 == s3); //false

        //final声明后,s4就变成了常量,常量和常量的拼接结果就在常量池中,因此返回true。
        final String s4 = "javaEE";
        String s5 = s4 + "hadoop";
        System.out.println(s1 == s5); //true
    }
}

10. StringBuffer 和 StringBuilder 介绍

本质上字符串存储规则,其实就是个char[]数组,String不可变,StringBuffer和StringBuilder可变。


String , StringBuffer , StringBuilder三者的异同?

String:不可变的字符序列。
StringBuffer:可变的字符序列:线程安全的,效率偏低。
StringBuilder:可变的字符序列:jdk5.0新增,线程不安全的,效率高。

上面三者底层使用char[]存储。(StringBuffer和StringBuilder因为继承AbstractStringBuilder,因此也是char[] value存储。)


11. String ,StringBuffer,StringBuilder 源码分析


String源码分析:

String str = new String(); 
//执行实际源码为:char[] value = new char[0];

String str1 = new String("abc");
//执行实际源码为:char[] value = new char[]{'a','b','c'};

StringBuffer源码分析:(StringBuilder源码差不多,就是安不安全的问题)

java 笔记pdf java笔记完整版_开发语言_16

StringBuffer sb1 = new StringBuffer();
//执行实际源码为:char[] value = new char[16]; 底层创建了一个长度是16的数组。
sb1.append('a'); //value[0] = 'a';
sb1.append('b'); //value[1] = 'b';

StringBuffer sb2 = new StringBuffer("abc");
//执行实际源码为:char[] value = new char["abc".length() + 16]; 字符串的长度外加16个长度数组。

//问题1:System.out.println(sb2.length()); 输出为3呢,还是3+16呢?
//答案:其实和加不加16没关系,因为length返回的count,是数组中有多少数据。

//问题2:既然开始定义长度为16,一旦满了就会有一个扩容问题?
//如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
//append方法中,调用了ensureCapacityInternal(确保容量完整的)方法,进而满足扩容。
//默认情况下扩容为原来容量的2倍(向左进位1,就是乘于2)+2,同时将原有数组中的元素复制到新的数组中。

开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)。可以直接定义容量大小,区别就是安全不安全。

12. StringBuffer 和 StringBuilder类常用的方法

StringBuffer和StringBuilder的常用方法差不多,都是一样:

java 笔记pdf java笔记完整版_java 笔记pdf_17


java 笔记pdf java笔记完整版_开发语言_18


当append和insert时,如果原来value数组长度不够,可扩容。

java 笔记pdf java笔记完整版_java 笔记pdf_19

package com.holmes.java04;

import org.junit.Test;

public class StringBufferBuilderTest {
    @Test
    public void test1(){

        StringBuffer sb1 = new StringBuffer("abc");
        sb1.append(1);
        sb1.append('1');
        System.out.println(sb1);

        //注意:像delete这样的方法,删除的索引是左闭右开!!
        sb1.delete(2,4);
        System.out.println(sb1);

        sb1.replace(2,4,"hello");
        System.out.println(sb1);

        sb1.insert(2,"c");
        System.out.println(sb1);

        sb1.reverse();
        System.out.println(sb1);

        System.out.println( sb1.indexOf("c"));

        System.out.println(sb1.substring(2,4));

        System.out.println(sb1.charAt(5));

        sb1.setCharAt(0,'m');
        System.out.println(sb1);
    }
}

方法链是一个很重要的形式,方法链的原理:

java 笔记pdf java笔记完整版_java_20


13. 对比String ,StringBuffer,StringBuilder的效率

package com.holmes.java04;

import org.junit.Test;

public class StringBufferBuilderTest {
    @Test
    public void test1(){
        long startTime = 0;
        long endTime = 0;
        String text = "";
        StringBuffer buffer = new StringBuffer("");
        StringBuilder builder = new StringBuilder("");

        startTime = System.currentTimeMillis();
        for (int i = 0;i < 20000; i++){
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0;i < 20000; i++){
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder的执行时间:" + (endTime - startTime));

        startTime = System.currentTimeMillis();
        for (int i = 0;i < 20000; i++){
            text += i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String的执行时间:" + (endTime - startTime));

        //String的效率远远小于前两者
        //效率从高到低排列: StringBuilder > StringBuffer > String
        //考虑是否有线程安全问题是否要同步,就要使用StringBuffer. StringBuffer线程安全,StringBuilder线程不安全。
    }
}

14. Java 时间日期 的相关API


计算世界时间的主要标准有:

java 笔记pdf java笔记完整版_java 笔记pdf_21


方法一:
java.lang.System类的日期时间:(计算时间差)

  • System.currentTimeMillis()返回当前时间于1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
  • 此方法经常用来计算时间差。

方法二:
java.util.Date类表示特定的瞬间,精确到毫秒:

package com.holmes.java04;

    /*
        方式一:两个构造器使用
            构造器一:Date() :创建一个对应当前时间的Date对象。
            构造器二:创建指定毫秒数(时间戳)的Date对象。
        方式二:两个方法的使用
            调用toString()方法:显示当前的年,月,日,时,分,秒。
            getTime()方法:获取当前Date对象对应的毫秒数(时间戳)。

     */
import org.junit.Test;

import java.util.Date;

public class DateTimeTest {
    @Test
    public void test2(){

        //构造器一:Date() :创建一个对应当前时间的Date对象
        Date date1 = new Date();

        //调用toString()方法:显示当前的年,月,日,时,分,秒
        System.out.println(date1.toString());//Sat Nov 06 14:55:02 CST 2021

        //getTime()方法:获取当前Date对象对应的时间戳
        System.out.println(date1.getTime());//1636181996537

        //构造器二:创建指定毫秒数(时间戳)的Date对象
        Date date2 = new Date(1636181996537L);
        System.out.println(date2.toString());
        
    }

}

在sql也有一个,java.sql.Date类,对应着数据库中的日期类型的变量。

package com.holmes.java04;

    /*
        java.sql.Date类的Date对象:
            同样调用toString()方法和getTime()方法
     */
import org.junit.Test;

import java.sql.Date;

public class DateTimeTest {
    @Test
    public void test2(){

        //创建java.sql.Date的对象
        Date date1 = new Date(23453456342L);
        System.out.println(date1.toString()); //1970-09-29
        System.out.println(date1.getTime()); //23453456342

    }

}

怎么将sql.Date 转为 util.Date对象?

因为多态性,直接赋值就可。

package com.holmes.java04;

import org.junit.Test;

public class DateTimeTest {
    @Test
    public void test2(){

        //创建java.sql.Date的对象
        java.sql.Date date1 = new java.sql.Date(23453456342L);

        //创建java.util.Date的对象
        java.util.Date date2 = new java.util.Date();

        //sql.Date 转 util.Date 多态性直接赋值就可
        date2 = date1;
        System.out.println(date2);

    }

}

怎么将util.Date 转为 sql.Date对象?

因为参数都有毫秒(时间戳),所以我们可以通过getTime()的方式来解决这种问题!!

package com.holmes.java04;

import org.junit.Test;

public class DateTimeTest {
    @Test
    public void test2(){

        //创建java.sql.Date的对象
        java.sql.Date date1 = new java.sql.Date(23453456342L);

        //创建java.util.Date的对象
        //情况一:左边是util,右边是sql,多态性,这样就可以强转。
        java.util.Date date2 = new java.sql.Date(32453476342L);
        java.sql.Date date3 = (java.sql.Date)date2;
        System.out.println(date3); //1971-01-11

        //情况二:都是util直接强转会报错!!cannot be cast
        java.util.Date date4 = new java.util.Date(32453476342L);
        //java.sql.Date date5 = (java.sql.Date)date4; 错误的!
        //但是有一个方法getTime(),来获得毫秒数就可以直接当作参数传递过去,就完美解决了
        java.sql.Date date6 = new java.sql.Date(date4.getTime());
        System.out.println(date6); //2021-11-06

    }

}

15. IDEA 的 debug调试

java 笔记pdf java笔记完整版_java_22

16. JDK8之前日期时间API SimpleDateFormat类

16.1 SimpleDateFormat默认无参数情况


SimpleDateFormat是对日期Date类的格式化和解析。

  • 使用format()方法,格式化:日期 转为 字符串。
  • 使用parse()方法,解析:格式化的逆过程,字符串 转为 日期
package com.holmes.java05;

import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTimeTest {

    @Test
    public void testSimpleDateFormat() throws ParseException {
        //实例化SimpleDateFormat:使用默认的构造器
        SimpleDateFormat sdf = new SimpleDateFormat();

        //格式化:日期 转为 字符串
        Date date = new Date();
        String formatStr = sdf.format(date);
        System.out.println(formatStr);

        //解析:格式化的逆过程,字符串 转为 日期
        //需要注意的是字符串的格式也必须和date格式一样,不然就抛出异常了
        String str = "21-11-7 下午3:04";
        Date date1 = sdf.parse(str);
        System.out.println(date1);
    }

}

16.2 SimpleDateFormat有参数情况


SimpleDateFormat的参数,不同格式的参数对应不同返回的结果。可以查看java参考手册这对SimpleDateFormat有参数的构造器这一节。

jdk参考手册

java 笔记pdf java笔记完整版_java_23

package com.holmes.java05;

import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTimeTest {

    @Test
    public void testSimpleDateFormat() throws ParseException {

        Date date = new Date();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
        System.out.println(sdf.format(date));

        //常用格式如下:
        //年:小写y,月:大写M,时分秒:小写hms。
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //格式化format:日期 转为 字符串
        System.out.println(sdf1.format(date));

        //解析,同样这里parse解析的格式也必须和参数定义的格式一样!!否则抛出异常
        System.out.println(sdf1.parse("1999-11-07 04:07:55"));;

        //2021.11.07 公元 at 16:09:21 CST
        //2021-11-07 04:09:21
        //Sun Nov 07 04:07:55 CST 1999
    }

}

很多页面传字符串"2020-09-08" 转为java.sql.Date(以方便存储数据库中)。

package com.holmes.java05;

import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class DateTimeTest {

    @Test
    public void testExer() throws ParseException {
        String str = "2020-09-08";

        //参数格式有一种为:"yyyy-MM-dd hh:mm:ss"
        //要对应前端传过来的数据,像后面的hh:mm:ss,忽略就行。
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        //util下的date
        java.util.Date dateUtil = sdf.parse(str);
        java.sql.Date dateSql = new java.sql.Date(dateUtil.getTime());
        System.out.println(dateSql);

    }
}

总天数差的一些计算,可以用到方法类和getTime类方法。

java 笔记pdf java笔记完整版_后端_24


17. JDK8之前日期时间API Calendar(日历类)

首先,Calendar是一个抽象类,抽象类不能声明对象。

Calendar因为有set()方法可以随意改变日期,便有了可变性,一旦set()设置了指定日期,calendar就会设定。

虽然他不能声明对象,但它有个子类GregorianCalendar,该子类可以创建构造器。


Calendar(日历类)实例化方式:

  • 方式一:创建其子类(GregorianCalendar)的对象。
  • 方式二:调用其静态方法getInstance()来创建对象。
package com.holmes.java05;

import org.junit.Test;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class DateTimeTest {

    // Calendar日历类的使用
    @Test
    public void testExer(){

        //1.实例化
        //方式一:创建其子类(GregorianCalendar)的对象
        GregorianCalendar gregorianCalendar = new GregorianCalendar();


        //方式二:调用其静态方法getIntance()
        Calendar calendar = Calendar.getInstance();
        //其实调用getInstance()方法,还是用的子类GregorianCalendar。
        System.out.println(calendar.getClass());//class java.util.GregorianCalendar

    }
}

Calendar类的常用方法:

package com.holmes.java05;

import org.junit.Test;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class DateTimeTest {

    // Calendar日历类的使用
    @Test
    public void testExer(){

        //方式二:调用其静态方法getIntance()
        Calendar calendar = Calendar.getInstance();

        //常用方法

        //1. get()方法操作:(获取当前日期)
        //查看这个月的第几天:calendar.get(Calendar.DAY_OF_MONTH)
        int days = calendar.get(Calendar.DAY_OF_MONTH);
        System.out.println("查看这个月的第几天:" + days);
        //查看今年的第几天:calendar.get(Calendar.DAY_OF_YEAR)
        System.out.println("查看今年的第几天:" + calendar.get(Calendar.DAY_OF_YEAR));

        //2. set()方法操作:(重新设置当前日期)
        calendar.set(Calendar.DAY_OF_MONTH,22);
        System.out.println("重新设置本月天数:"+ calendar.get(Calendar.DAY_OF_MONTH));

        //3. add()方法操作:(在当前的日期基础上,增加)
        calendar.add(Calendar.DAY_OF_MONTH,3);
        System.out.println("在当前的日期基础上,增加相应日期:"+ calendar.get(Calendar.DAY_OF_MONTH));

        //4. getTime()方法操作:(通过日历类的getTime方法,获得了一个Date对象。)
        Date date = calendar.getTime();
        System.out.println(date);

        //5. setTime()方法操作:(将Date对象)
        Date date1 = new Date();
        calendar.setTime(date1);
        //注意在获取一月是0,星期时周日是1,周六是7.
        //因此,月份要加1 ; 星期要减1
        System.out.println(calendar.get(Calendar.YEAR)+ "年" + (calendar.get(Calendar.MONTH) + 1) + "月" + calendar.get(Calendar.DAY_OF_MONTH) + "号");
        System.out.println("星期:" + (calendar.get(Calendar.DAY_OF_WEEK) - 1));
        System.out.println("今年的第几个周:" + calendar.get(Calendar.WEEK_OF_YEAR));
    }
}

注意获取月份和星期时很重要!!

java 笔记pdf java笔记完整版_后端_25


日期偏移量的问题:

package com.holmes.java05;

import org.junit.Test;

import java.util.Date;

public class JDKDateTimeTest {
    @Test
    public void testDate(){

        //日期偏移量的问题:
        //年要减1900,月要减1,才是我们想要得到的内容
        Date date1 = new Date(2020 - 1900,9 - 1,8);
        System.out.println(date1);

    }
}

java 笔记pdf java笔记完整版_后端_26

18. JDK8 新时间日期的 API (java.time)

18.1 JDK8 的 java.time的介绍


JDK8中的新的java.time中包含了所有关于本地日期(LocalDate),本地时间(LocalTime),本地日期时间(LocalDateTime),时区(ZonedDateTime)和持续时间(Duration)的类。

java 笔记pdf java笔记完整版_System_27


java 笔记pdf java笔记完整版_开发语言_28

18.2 LocalDate , LocalTime , LocalDateTime的使用

  • now()方法:用来创建对,获取当前的日期,时间。使用频率最高的是LocalDateTime。
  • of()方法:设置指定的年,月,日,时,分,秒。该方法设置没有偏移量的!!

创建了对象,那必须有方法对应,见下:

package com.holmes.java05;

import org.junit.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class JDKDateTimeTest {
    @Test
    public void testDate(){

        //now()方法:用来创建对,获取当前的日期,时间。使用频率最高的是LocalDateTime
        LocalDate localDate = LocalDate.now();//Date日期
        LocalTime localTime = LocalTime.now();//Time时间
        LocalDateTime localDateTime = LocalDateTime.now();//DateTime日期加时间

        System.out.println(localDate);//2021-11-09
        System.out.println(localTime);//16:32:46.154
        System.out.println(localDateTime);//2021-11-09T16:32:46.154

        //of()方法:设置指定的年,月,日,时,分,秒。该方法设置没有偏移量的!!
        LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 13);
        System.out.println(localDateTime1);

        //getXxx()方法:获取相关属性
        System.out.println("获取当月的第几天" + localDateTime.getDayOfMonth());//获取当月的第几天
        System.out.println("获取这周的第几天" + localDateTime.getDayOfWeek());//获取这周的第几天
        System.out.println("获取英文的当前月份" + localDateTime.getMonth());//获取英文的当前月份
        System.out.println("获取数字的当前月份" + localDateTime.getMonthValue());//获取数字的当前月份
        System.out.println("获取当前分钟:" + localDateTime.getMinute());//需要注意前提是必须有分钟!!

        //withXxx()方法:设置相关属性:(注意它是有返回值的!!!)

        //与Calendar类不同,这里体现了不可变性
        //因为他有返回值,localDateTime2就是localDateTime.withDayOfMonth(22)的返回值对象。
        //localDateTime 和 localDateTime2 之间不会相应。
        LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(22);//设置当前月份的天数
        System.out.println(localDateTime);
        System.out.println(localDateTime2);

        LocalDateTime localDateTime3 = localDateTime.withHour(4);//设置当前小时
        System.out.println(localDateTime);
        System.out.println(localDateTime3);

        //plusXxx()方法:是添加属性数量
        LocalDateTime localDateTime4 = localDateTime.plusMonths(3);
        System.out.println(localDateTime);
        System.out.println(localDateTime4);

        //minuxXxx()方法:上面是加法,那么这里就是做减法了
        LocalDateTime localDateTime5 = localDateTime.minusDays(4);
        System.out.println(localDateTime);
        System.out.println(localDateTime5);
    }
}

18.3 Instant 瞬时


java.time.Instant也是基于1970年1月1日0时0分0秒(UTC)开始。

首先,要确定一个时区问题,UTC是按照本初子午线来开始的。

java 笔记pdf java笔记完整版_开发语言_29


两种创建Instant实例方式:

  • now()方法:获取本初子午线对应的标准时间(UTC)
  • ofEpochMilli()方法:也是实例化的方式,它可以接受long型的参数,从而获取时间。

instant实例化对应的方法:

  • atOffset()方法:定义时区偏移量的。
  • toEpochMilli()方法:获取从1970年1月1日0时0分0秒(UTC)开始到现在对应的毫秒数
package com.holmes.java05;

import org.junit.Test;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class InstantTest {
    @Test
    public void test(){

        //now()方法:获取本初子午线对应的标准时间(UTC)
        Instant instant = Instant.now();

        //这里算出的是本初子午线的时间,也就是伦敦的位置时区
        System.out.println(instant);//2021-11-11T09:02:36.799Z

        //atOffset()方法:我们北京位处东八区,因此要加8个小时。offsetDateTime就是用来定义时区偏移量的
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);//2021-11-11T17:02:36.799+08:00

        //toEpochMilli()方法:获取从1970年1月1日0时0分0秒(UTC)开始到现在对应的毫秒数
        long l = instant.toEpochMilli();
        System.out.println(l);//1636621675611

        //ofEpochMilli()方法:也是实例化的方式,它可以接受long型的参数,从而获取时间。
        Instant instant1 = Instant.ofEpochMilli(1636621675611L);
        System.out.println(instant1);

    }
}

总结:
本质上,Date类和Instant类差不多,功能和方法都差不多。

18.4 JDK8 新日期时间API java.time.format.DateTimeFormatter

这里DateTimeFormatter就与上面的SimpleDateFormat差不多。


方式一:预定义的标准格式,ISO_LOCAL_DATE_TIME,ISO_LOCAL_DATE,ISO_LOCAL_TIME

  • format()方法格式化:日期 --》 字符串。
  • parse()方法解析:字符串 --》 日期
package com.holmes.java05;

import org.junit.Test;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;

public class DateTimeFormatterTest {
    @Test
    public void test(){

        //方式一:预定义的标准格式,ISO_LOCAL_DATE_TIME,ISO_LOCAL_DATE,ISO_LOCAL_TIME
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

        //format()方法格式化:日期 --》 字符串
        LocalDateTime localDateTime = LocalDateTime.now();
        String str1 = formatter.format(localDateTime);
        System.out.println(str1);//2021-11-11T17:45:51.145

        //parse()方法解析:字符串 --》 日期
        TemporalAccessor parse = formatter.parse("2021-11-11T17:45:51.145");
        System.out.println(parse);


    }
}

方式二:本地化相关的格式

  • 1.ofLocalizedDateTime()方法:(ofLocalizeDateTime对应的就是DateTime的格式类)
    参数:FormatStyle.SHORT, FormatStyle.MEDIUM, FormatStyle.LONG
  • 2.ofLocalizedDate()方法:(ofLocalizeDate对应的就是Date的格式类)
    参数:相比较上面多了一个FormatStyle.FULL,FormatStyle.SHORT, FormatStyle.MEDIUM, FormatStyle.LONG
package com.holmes.java05;

import org.junit.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
import java.util.Date;

public class DateTimeFormatterTest {

    @Test
    public void test2(){

        //方式二:本地化相关的格式

        //1.ofLocalizedDateTime()方法:(ofLocalizeDateTime对应的就是DateTime的格式类)
        //参数:FormatStyle.SHORT, FormatStyle.MEDIUM, FormatStyle.LONG
        DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
        LocalDateTime localDateTime = LocalDateTime.now();

        //不同的参数,获得的格式也不同。
        String str = formatter.format(localDateTime);
        System.out.println(str);//21-11-11 下午6:20

        TemporalAccessor parse = formatter.parse("21-11-11 下午6:20");
        System.out.println(parse);//{},ISO resolved to 2021-11-11T18:20

        //2.ofLocalizedDate()方法:(ofLocalizeDate对应的就是Date的格式类)
        //参数:相比较上面多了一个FormatStyle.FULL,FormatStyle.SHORT, FormatStyle.MEDIUM, FormatStyle.LONG
        //同样不同的参数,也是获得不同的格式
        DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
        String str2 = formatter1.format(LocalDate.now());
        System.out.println(str2);//2021年11月11日 星期四


    }
}

方式三:自定义的格式,这种方式是重点!!

  • ofPattern()方法:来自定义
    ofPattern(“yyyy-MM-dd hh:mm:ss”)。
package com.holmes.java05;

import org.junit.Test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
import java.util.Date;

public class DateTimeFormatterTest {
  
    @Test
    public void test3(){

        //方式三:自定义的格式,如:ofPattern("yyyy-MM-dd hh:mm:ss")
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh");
        //格式化
        String str = formatter.format(LocalDateTime.now());//2021-11-11 06
        System.out.println(str);//2021-11-11 06
        //解析
        TemporalAccessor parse = formatter.parse("2021-11-11 06");
        System.out.println(parse);//{HourOfAmPm=6},ISO resolved to 2021-11-11
    }
}

18.5 其他API

java 笔记pdf java笔记完整版_开发语言_30

19. Java比较器

19. 为什么要用Java比较器?


Java中的对象(引用数据类型),正常情况下,只能进行比较使用 == ,=!来比较地址值,像 >,< ,>= ,<=等没办法对引用数据类型对象进行比较的。

但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。

这就用到了Comparable 或 Comparator接口了。

19.2 Comparable接口使用


像实现Comparable接口调用sort方法也叫做自然排序。

Comparable接口的使用举例:

  • 像String,包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。
  • 重写compareTo(obj)的规则:
    如果当前对象this大于形参对象obj,则返回正整数;
    如果当前对象this小于形参对象obj,则返回负数;
    如果当前对象this等于形参对象obj,则返回零。

像String这种系统类排序处理:

实现Comparable接口的对象列表(和数组)可以通过 Collection.sort(针对集合排序) 或 Arrays.sort(针对数组排序) 进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无序指定比较器。

package com.holmes.java05;

import org.junit.Test;

import java.util.Arrays;

public class CompareTest {
    @Test
    public void test(){
        //像String,包装类等实现了Comparable接口,重写了compareTo()方法,给出了比较两个对象大小的方式
        String[] arr = new String[]{"AA","CC","MM","BB","OO","FF"};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

对于自定义类来说:

如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。

在compareTo(obj)方法中指明如何排序。

同时,可能排序遇到相同的会存在二级排序的情况。


自定义类实例:

goods类:

package com.holmes.java05;

public class Goods implements Comparable{

    private String name;
    private double price;

    public Goods() {
    }

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

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

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

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

    //指明商品比较大小的方式:按照价格从低到高排序
    @Override
    public int compareTo(Object o) {

        if (o instanceof Goods){

            //方式一:if语句比较价格
            Goods goods = (Goods)o;
            if(this.price > goods.price){
                return 1;
            }else if (this.price < goods.price){
                return -1;
            }else {
                //return 0;
                //二级排序,就是前面排序相同就会在第二种属性进行排序
                //需要时就这么做,不需要就返回0就行。
                return this.name.compareTo(goods.name);
            }


            //方式二:
//            return Double.compare(this.price,goods.price);
        }
        throw new ClassCastException("传入的数据类型不匹配");
    }
}

测试类:通过sort()方法来调用实现Comparable的compareTo()方法

package com.holmes.java05;

import org.junit.Test;

import java.util.Arrays;

public class CompareTest {

    @Test
    public void test2(){

        Goods[] arr = new Goods[4];
        arr[0] = new Goods("lenovoMouse",34);
        arr[1] = new Goods("dellMouse",56);
        arr[2] = new Goods("xiaomiMouse",12);
        arr[3] = new Goods("huaweiMouse",99);

        Arrays.sort(arr);
        System.out.println(arr[0].getPrice());
        System.out.println(arr[1].getPrice());
        System.out.println(arr[2].getPrice());
        System.out.println(arr[3].getPrice());
    }

}

19.3 定制排序:java.util.Comparator


什么时候用定制排序:java.util.Comparator?

java 笔记pdf java笔记完整版_java 笔记pdf_31


从写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。

Arrays.sort()方法中,除了可以添加数组进行比较,还可以添加Comparator对象来定义如何比较。

java 笔记pdf java笔记完整版_开发语言_32


如定制排序String从大到小排序的sort()方法:

package com.holmes.java05;

import org.junit.Test;

import java.util.Arrays;
import java.util.Comparator;

public class CompareTest {

    @Test
    public void test(){
        String[] arr = new String[]{"AA","CC","MM","BB","OO","FF"};
        Arrays.sort(arr, new Comparator<String>() {

            //按照字符串从大到小排序
            @Override
            public int compare(String o1, String o2) {
                if (o1 instanceof String && o2 instanceof String){
                    String s1 = (String) o1;
                    String s2 = (String) o2;
                    return -s1.compareTo(s2);
                }
                throw new RuntimeException("输出的数据类型不一致");
            }

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

}

接着上面的自定义类Goods,使用定制排序Comparator和sort方法进行修改:

package com.holmes.java05;

import org.junit.Test;

import java.util.Arrays;
import java.util.Comparator;

public class CompareTest {

    @Test
    public void test3(){
        Goods[] arr = new Goods[4];
        arr[0] = new Goods("lenovoMouse",34);
        arr[1] = new Goods("dellMouse",56);
        arr[2] = new Goods("xiaomiMouse",12);
        arr[3] = new Goods("huaweiMouse",99);

        Arrays.sort(arr, new Comparator() {

            //按照名字进行排序,二级排序按照价格
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof Goods && o2 instanceof Goods){
                    Goods g1 = (Goods) o1;
                    Goods g2 = (Goods) o2;
                    if (g1.getName().equals(g2.getName())){
                        return Double.compare(g1.getPrice(),g2.getPrice());
                    }else {
                        return g1.getName().compareTo(g2.getName());
                    }
                }
                throw new RuntimeException("输入的数据类型不匹配");
            }

        });
        System.out.println(arr[0].getName());
        System.out.println(arr[1].getName());
        System.out.println(arr[2].getName());
        System.out.println(arr[3].getName());
    }

}

19.4 Comparable接口 与 Comparator的使用的对比

java 笔记pdf java笔记完整版_后端_33

20. System类,Math类,BigInteger 与BigDecimal类

20.1 System类

java 笔记pdf java笔记完整版_System_34


java 笔记pdf java笔记完整版_System_35


System.getProperty()方法的使用:

package com.holmes.java05;

import org.junit.Test;

public class OtherClassTest {

    @Test
    public void test1(){

        String javaVersion = System.getProperty("java.version");
        System.out.println("java的版本:" + javaVersion);

        String javaHome = System.getProperty("java.home");
        System.out.println("java的home:" + javaHome);

        String osName = System.getProperty("os.name");
        System.out.println("os的name:" + osName);

        String osVersion = System.getProperty("os.version");
        System.out.println("os的version:" + osVersion);

        String userName = System.getProperty("user.name");
        System.out.println("user的name:" + userName);

        String userHome = System.getProperty("user.home");
        System.out.println("user的home:" + userHome);

        String userDir = System.getProperty("user.dir");
        System.out.println("user的dir:" + userDir);

        //java的版本:1.8.0_144
        //java的home:E:\Computerrelated\javashixun\jdk-8u144-windows-x64\jre
        //os的name:Windows 10
        //os的version:10.0
        //user的name:Administrator
        //user的home:C:\Users\Administrator
        //user的dir:E:\Intellij_IDEA\workspace\java    }

}

20.2 Math类

java 笔记pdf java笔记完整版_后端_36

20.3 BigInteger 与BigDecimal类


了解Integer:

java 笔记pdf java笔记完整版_java_37


BigInteger类介绍:

java 笔记pdf java笔记完整版_java_38


BigDecimal类:

java 笔记pdf java笔记完整版_java 笔记pdf_39

package com.holmes.java05;

import org.junit.Test;

import java.math.BigDecimal;
import java.math.BigInteger;

public class OtherClassTest {

    @Test
    public void test2(){
        BigInteger bi = new BigInteger("124332411231231231231231231");
        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));//scale保留几位小数

        //124332411231231231231231231
        //1130.486
        //1130.486454545454545
    }
}