Java基本语法 ---- 常用类

一、字符串相关类

(一)String类常用方法

1. String类

  • String代表字符串常量,用 “ ” 表示,是一个final类,不可被继承
  • 实现Serializable接口表示字符串支持序列化,实现Comparable接口表示String可以比较大小
  • 内部定义了final char[] value 用于存储字符串数据
  • String代表不可变的字符序列
    • 对字符串重新赋值时,需要重新指定内存区域赋值,不能对原有value进行修改赋值
    • 对字符串进行连接操作时,需要重新指定内存区域赋值,不能对原有value进行修改赋值
    • 调用replace()修改字符/字符串时,需要重新指定内存区域赋值
  • 通过字面量方式(区别于new)给字符串赋值,此时字符串值声明在字符串常量池中
  • 字符串常量池中不会存储相同内容 (返使用equals()返回true)的字符串
    public static void main(String[] args) {
        String str = "abc";
        stringTest(str);
        System.out.println(str); // abc

        String str1 = new String("abc");
        stringTest(str1);
        System.out.println(str1); // abc
    }

    public static void stringTest(String str) {
        str = "stringTest";
    }
    public void test1() {
        String s1 = "abc"; // 字面量的定义方式
        String s2 = "abc";
        System.out.println(s1 == s2); // 地址值 ture

        s1 = "hello";
        System.out.println(s1 == s2); // 地址值 false

        String s3 = "abc";
        s3 += "def";
        System.out.println(s3); // abcdef
        System.out.println(s3 == s2); // false

        String s4 = "abcdef";
        System.out.println(s3 == s4); // false

        String s5 = "abc";
        String s6 = s5.replace('a', 'm');
        System.out.println(s5 == s6); // false
    }

2. String对象的创建

  • 通过字面量方式
  • 通过new对象的方式
    • String s = new String("abc"); 方式创建对象,在内存中创建了几个对象?
      • 2个:①堆空间new结构  ②char[]对应常量池中的数据 “abc”
    public void test2() {
        // 此时s1,s2中的数据声明在方法区中的常量池中
        String s1 = "JavaEE";
        String s2 = "JavaEE";
        // 此时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
    }

        Person p1 = new Person(new String("Tom"), 12);
        Person p2 = new Person(new String("Tom"), 12);
        System.out.println(p1.name.equals(p2.name)); // true
        System.out.println(p1.name == p2.name); // false

3. 字符串的拼接

  • 常量与常量的拼接结果在常量池,常量池中不会存在相同内容的常量
  • 只要拼接内容中有一个是变量,结果就在
  • 如果拼接结果调用intern(),返回值就在常量池中
    public void test3() {
        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;
        
        System.out.println(s3 == s4); // true
        System.out.println(s3 == s5); // false
        System.out.println(s5 == s6); // false
        System.out.println(s4 == s7); // false

        String s8 = s5.intern();
        System.out.println(s3 == s8); // true
    }
  • 面试小题:final修饰的为常量
        String s1 = "JavaEEHadoop";
        String s2 = "JavaEE";
        String s3 = s2 + "Hadoop"; 
        System.out.println(s1 == s3); // false

        final String s4 = "JavaEE"; // s4是常量
        String s5 = s4 + "Hadoop";
        System.out.println(s1 == s5); // true
 

4. 字符串的值传递问题 —— String不可变性

    String str = new String("good");
    char[] ch = {'t', 'e', 's', 't'};

    public void change(String str, char ch[]){
        str = "test ok";
        ch[0] = 'b';
    }

    public static void main(String[] args) {
        StringTest1 test = new StringTest1();
        test.change(test.str, test.ch);
        System.out.print(test.str + " and "); // good and
        System.out.println(test.ch); // best
    }

5. JVM中涉及字符串的内存管理

  • 三种JVM: ① Sun公司的HotSpot (默认)  ② BEA公司的JRockit  ③ IBM公司的J9VM
  • 堆内存
    • 一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的
    • 类加载器读取类文件后把类、方法、常变量放到堆内存中,保存引用变量的真实信息
    • 堆内存的三部分
      • Young Generation Space 新生区类产生、应用、被GC回收的区域
        • Eden Space 伊甸园区所有类都在该区被new出来
        • Survivor Space 幸存者区
          • 1区 (Survivor 1 Space) 
          • 0区 (Survivor 0 Space) 
      • Tenure Generation Space 养老区
      • Permanent Space(Non-Heap)永久区、元空间 (方法区)
        • 存放JDK自身携带的 Claerfass Intce元数据,存储运行环境必须加载的类信息
        • 常驻内存区域,不会被GC回收,关闭JVM才会释放该区占用的内存
        • 别名 Non-Heap 将其区分于堆,永久区是方法区的一个实现
    • 涉及JDK的内存区域
      • JDK1.6:字符串常量池存储在方法区(永久区)
      • JDK1.7:字符串常量池存储在堆空间
      • JDK1.8:字符串常量池存储在方法区(元空间)
  • OOM (OutOfMemoryError) 异常
    • 产生java.lang.OutofMemoryError: Java heap space 的原因
      • ES区满需创建对象执行Minor GC, 剩余对象移动到0区 >> 1区 >> 养老区
      • 养老区满执行Major GC(Full GC),依然无法创建对象就会产生OOM
      • 代码中创建了大量对象并且长时间不能被GC收集 —— 内存溢出、内存泄漏
      • JVM堆内存设置不够,可通过参数-Xms、-Xmx调整
    • 产生java.lang.OutofMemoryError: PermGen space 的原因
      • eg. Tomcat下部署了太多应用、大量动态反射生成的类不断被加载等
      • Java虚拟机堆永久代Perm内存设置不够程序启动需加载大量第三方jar包

6. String类常用方法

  • int length()
  • char charAt(int index)
        String s1 = "HelloWorld!";
        System.out.println(s1.length()); // 11
//      System.out.println(s1.charAt(11)); // StringIndexOutOfBoundsException
        System.out.println(s1.charAt(10)); //!
  • boolean isEmpty():String是否为空,判断标准为lenth = 0
        String s2 = "";
        System.out.println(s2.isEmpty()); // true
  • String toLowerCase()
  • String toUpperCase()
        String s1 = "HelloWorld!"; 
        String s3 = s1.toLowerCase();
        String s4 = s1.toUpperCase();
        System.out.println(s1); // HelloWorld! s1不可变
        System.out.println(s3); // helloworld!
        System.out.println(s4); // HELLOWORLD!
  • String trim(): 忽略空格和空格,字符串中的空格不会删除
        String s5 = " Hello World! ";
        String s6 = s5.trim();
        System.out.println(s6); //Hello World! 只删除前后空格,中间空格不会删除
  • boolean equals(Object obj): 比较字符串内容
  • boolean equalsIgnareCase(String s): 忽略大小写比较内容
        String s1 = "HelloWorld!"; 
        String s3 = s1.toLowerCase();        
        System.out.println(s1.equals(s3)); // false
        System.out.println(s1.equalsIgnoreCase(s3)); // true
  • String concat(String str):字符串连接
       String s7 = s1.concat(" Java");
       System.out.println(s7); // HelloWorld! Java
  • int compareTo(String anotherString): 比较两个字符串大小; 负数当前对象小, 正数当前对象大
        String s1 = "abc";
        String s2 = "abe";
        System.out.println(s1.compareTo(s2)); // -2 >> (99-101 = -2)

        String s3 = "ac"; // a-97
        String s4 = "Ae"; // A-65
        System.out.println(s3.compareTo(s4)); // 32 (97 - 65 = 32)
  • String substring(int beginIndex): 返回一个新字符串,从beginIndex开始到最后一个字符
  • String substring(int biginIndex, int endIndex):返回新字符串,从begin到end,左闭右开
        String s8 = "abcdefg";
        String s9 = s8.substring(3);
        String s10 = s8.substring(3, 6);
        System.out.println(s9);// defg
        System.out.println(s10); // def >> 左闭右开
  • boolean endsWith(String suffix):判断字符串是否以suffix结束
  • boolean startsWith(String prefix):判断字符串是否以prefix开始
  • boolean startsWith(String prefix, int toffset): 判断字符串是否在toffset角标以字符串prefix开始
        String str = "HelloWorld!";
        boolean b1 = str.endsWith("world"); // false
        boolean b2 = str.startsWith("Hello"); // true
        boolean b3 = str.startsWith("hello"); // false
        boolean b4 = str.startsWith("loW", 3); // true
  • boolean contains(CharSequence s):判断字符串是否包含字符串s
        String str1 = "HelloWorld!";        
        String str2 = "World";
        boolean b5 = str1.contains(str2); // true
  • int indexOf(String str):从前往后返回首次出现str的首字母的角标未找到返回 -1
  • int indexOf(String str, int fromIndex):从指定索引开始从前往后找
  • int lastIndexOf(String str) / lastIndexOf(String str, int fromIndex):从后向前
  • ​​​​indexOf(str) 与 lastIndexOf(str) 返回值相同:① str只出现一次  ② str不存在
        String str = "HelloWorld!";
        System.out.println(str.indexOf("lo")); // 3
        System.out.println(str.indexOf("lol")); // -1
        System.out.println(str.indexOf("lo", 5)); // -1
        System.out.println(str.lastIndexOf("ll")); // 2
        System.out.println(str.lastIndexOf("l", 7)); // 3
  • String replace(char oldChar, char newChar): 替换所有字符
  • String replace(CharSequence target, CharSequence replacement):替换所有字符串
        String str1 = "HelloJava!";
        String str2 = str1.replace('a','o');
        String str3 = str1.replace("Java", "World");
        System.out.println(str1); // HelloJava!
        System.out.println(str2); // HelloJovo!
        System.out.println(str3); // HelloWorld!
  • String replaceAll(String regex, String replacement): 替换匹配正则表达式regex的所有字符串
  • String replaceFirst(String regex, String replacement): 替换匹配正则表达式的第一个字符串 
        String str = "12hello34world567java8910";
        String str4 = str.replaceAll("\\d+", "!").replaceAll("^!|!$", ""); // 将数字(\d+)替换为!, 把开头(^)和结尾($)的!删除
        String str5 = str.replaceFirst("\\d+", "!"); // 将数字替换为!
        System.out.println(str4); // hello!world!java
        System.out.println(str5); // !hello34world567java8910
  • boolean matches(String regex):匹配正则表达式
        String str = "12345";
        boolean matches = str.matches("\\d+"); // true 字符串是否匹配数字

        String tel = "0571-1234567";
        boolean result = tel.matches("0571-\\d{7,8}"); // true 由0571-开头,后匹配长度为7-8位的数字
  • String[] split(String regex)
  • String[] split(String regex, int limit) 切割字符串最多不超过limit个, 剩下放在最后一个字符串中 
        String str = "hello|world|java";
        String[] strs1 = str.split("\\|");
        for (int i = 0; i < strs1.length; i++) {
            System.out.print(strs1[i] + "\t"); //hello    world    java
        }

        String[] strs2 = str.split("\\|", 2);
        for (int i = 0; i < strs2.length; i++) {
            System.out.print(strs2[i] + "\t"); //hello    world|java
        }
String text = "a:b:c::";
String[] resultWithoutLimit = text.split(":");
String[] resultWithZeroLimit = text.split(":", 0);
String[] resultWithNegativeLimit = text.split(":", -1);

System.out.println("Without limit: " + java.util.Arrays.toString(resultWithoutLimit));
// 输出:[a, b, c]

System.out.println("With zero limit: " + java.util.Arrays.toString(resultWithZeroLimit));
// 输出:[a, b, c]

System.out.println("With negative limit: " + java.util.Arrays.toString(resultWithNegativeLimit));
// 输出:[a, b, c, , ]

7. String的类型转换

1)String、基本数据类型、包装类之间转换

  • String >> 基本数据类型:调用包装类的静态方法 parseXxx()
  • 基本数据类型 >> String: 调用String重载的方法valueOf(xxx) 基本数据类型 + “”
        String string = "123";
        int num = Integer.parseInt(string);
        String str1 = String.valueOf(num);
        String str2 = num + "";
        System.out.println(string == str2); // false

2)String与char[]之间转换 

  • String >> char[]:调用String的 toCharArray()
  • char[] >> String:调用String的构造器
        String string = "abc123";
        char[] charArray = string.toCharArray();
        String str = new String(charArray);

3)String与byte[]之间转换

  • 编码字符串 >> 字节:String >> byte[]:调用String的 toByteArray()
  • 解码字节 >> 字符串:byte[] >> String:调用String的构造器
  • 解码时使用的字符集必须与编码时使用的字符集相同,否则会出现乱码
        String string = "abc123中国"; // UTF-8编码1个汉字占3个字节, gbk中占2个字节
        byte[] byteArray = string.getBytes(); // 使用默认字符集编码,输出字符的对应ASkII码
        byte[] gbks = string.getBytes("gbk"); // 使用gbk进行编码

        String str = new String(byteArray); // 使用默认字符集解码
        String str1 = new String(gbks); // 出现乱码,原因:编码集和解码集不一致
        String str2 = new String(gbks, "gbk"); // 定义解码方式,编解码方式一致不会乱码

8.  几道算法题

1)模拟一个trim方法,去除字符串两端的空格

    public String trim(String str) {
        if (str != null) {
            int startIndex = 0, endIndex = str.length() - 1;
            while (startIndex < endIndex && str.charAt(startIndex) == ' ') {
                startIndex++;
            }
            while (endIndex > startIndex && str.charAt(endIndex) == ' ') {
                endIndex--;
            }
            if (str.charAt(startIndex) == ' ') return "";
            return str.substring(startIndex, endIndex + 1);
        }
        return null;
    }

2)将一个字符串进行反转。将字符串中指定部分进行反转

    // 方式1
    public String reverse1(String str, int startIndex, int endIndex) {
        if (str != null && str.length() != 0) {
            char[] arr = str.toCharArray();
            for (int x = startIndex, y = endIndex; x < y; x++, y--) {
                char temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
            return new String(arr);
        }
        return str;
    }
    // 方式2 使用String拼接操作
    public String reverse2(String str, int startIndex, int endIndex) {
        if (str != null && str.length() != 0) {
            String reverseStr = str.substring(0, startIndex);
            for (int i = endIndex; i >= startIndex; i--) {
                reverseStr += str.charAt(i);
            }
            reverseStr += str.substring(endIndex + 1);
            return reverseStr;
        }
        return str;
    }
    // 方式3 使用StringBuffer/StringBuilder替换String
    public String reverse3(String str, int startIndex, int endIndex) {
        if (str != null && str.length() != 0) {
            StringBuilder sBuilder = new StringBuilder();
            sBuilder.append(str.substring(0, startIndex));
            for (int i = endIndex; i > startIndex; i--) {
                sBuilder.append(str.charAt(i));
            }
            sBuilder.append(str.substring(endIndex - 1));
            return sBuilder.toString();
        }
        return str;
    }

3)获取一个字符串在另一个字符串中出现的次数

    public int count(String mainStr, String subStr) {
        int mainLength = mainStr.length();
        int subLength = subStr.length();
        int count = 0;
        int index = 0;
        if (mainLength >= subLength) {
            // 方式1
            while ((index = mainStr.indexOf(subStr)) != -1) {
                count++;
                mainStr = mainStr.substring(index + subLength);
            }

            // 方式2
            while ((index = mainStr.indexOf(subStr, index)) != -1) {
                count++;
                index += subLength;
            }
        }
        return count;
    }

4)获取两个字符串中最大的相同子串

    public String[] subString2(String str1, String str2) {
        if (str1 != null && str2 != null) {
            StringBuffer sBuffer = new StringBuffer();
            String longStr = str1.length() > str2.length() ? str1 : str2;
            String shortStr = str1.length() >= str2.length() ? str2 : str1; // 长度相同情况
            for (int length = shortStr.length(); length > 0; length--) {
                for (int startIndex = 0, endIndex = startIndex + length - 1; 
                     endIndex < shortStr.length(); startIndex++, endIndex++) {
                    String subStr = shortStr.substring(startIndex, endIndex + 1);
                    if (longStr.contains(subStr)) {
                        sBuffer.append(subStr + ",");
                    }
                }
                if (sBuffer.length() != 0) {
                    return sBuffer.toString().replaceAll(",$", "").split("\\,");
                }
            }
        }
        return null;
    }

5)对字符串中的字符进行自然顺序排序

    public String sort(String str) {
        char[] chars = str.toCharArray();
        for (int i = 0; i < str.length() - 1; i++) {
            for (int j = 0; j < str.length() - i - 1; j++) {
                if (chars[i] < chars[j]) {
                    char temp = chars[i];
                    chars[i] = chars[j];
                    chars[j] = temp;
                }
            }
        }
        return new String(chars);
    }

(二)StringBuffer、StringBuilder

1. String、StringBuffer、StringBuilder三者异同

  • 相同点:都是字符串相关类,底层使用char[]存储
  • 不同点
    • String不可变字符序列
    • StringBuffer可变字符序列;线程安全,效率低;
    • StringBuilder可变字符序列;jdk5.0新增,线程不安全,效率高; 
  • 底层存储:char[]数组
  • 数组长度: 输出字符串内容长度
  • 扩容问题: 底层数组长度不够扩容, 默认情况原长度2倍+2, 同时将原数组元素赋值到新数组中
        String str = new String(); // char[] value = new char[0];
        String str1 = new String("abc"); // char value = new char[]{'a', 'b', 'c'};

        StringBuffer sb1 = new StringBuffer(); // char value = new char[16]; 相当与底层创建了长度为16的char[]\
        System.out.println(sb1.length()); // 0
        sb1.append('a'); // value[0] = 'a';
        sb1.append('b'); // value[1] = 'b';

        StringBuffer sb2 = new StringBuffer("abc"); // char value = new char["abc".length + 16];
        System.out.println(sb2.length()); // 3

2. 常用方法

  • StringBuffer append(xxx) 字符串拼接。可扩容,支持方法链
        StringBuffer sb = new StringBuffer();
        sb.append('a');
        sb.append("bcdef");
  • StringBuffer delete(int start, int end) 删除指定位置的内容 左闭右开
        StringBuffer sb = new StringBuffer("abcd");
        sb.delete(2, 4);
        System.out.println(sb); // ab
  • StringBuffer replace(int start, int end, String str) 把(start,end)位置内容换为str
        StringBuffer sb = new StringBuffer("abcdef");
        sb.replace(2, 4, "hello");
        System.out.println(sb); // abhelloef
  • StringBuffer insert(int offset, xxx) 在指定位置插入xxx。可扩容,支持方法链
        StringBuffer sb = new StringBuffer("abCdef");
        sb.insert(2, false); // abfalseCedf
  • StringBuffer reverse()  字符串序列逆转
        StringBuffer sb = new StringBuffer("abc");
        sb.reverse(); // cba
  • int indexOf(String str)
        StringBuffer sb = new StringBuffer("hello");
        int index = sb.indexOf("l"); // 2
  • String substring(int start, int end) 返回从索引start到end 左闭右开区间内的新子字符串
        StringBuffer sb = new StringBuffer("hello");
        String string = sb.substring(1, 4);
        System.out.println(string); // ell
  • int length()
  • char charAt(int n)
  • void setCharAt(int n, char ch) 将指定索引位置字符改为新字符

3. 三者效率对比:StringBuffer > StringBuilder > String

    @Test   
    public void test() {
        // 初始设置
        long startTime = 0L;
        long endTime = 0L;
        String text = "";
        StringBuffer sBuffer = new StringBuffer("");
        StringBuilder sBuilder = new StringBuilder("");
        // 开始对比
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 20000; i++) {
            sBuffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间:" + (endTime - startTime)); // 5

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

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

4. String、StringBuffer、StringBuilder之间转换

  • String >> StringBuffer、StringBuilder
    • 调用StringBuffer、StringBuilder的构造器
  • StringBuffer、StringBuilder >> String
    • 调用String的构造器
    • 调用StringBuffer、StringBuilder的toString()
        String str = "abc";
        StringBuffer sBuffer = new StringBuffer(str);
        StringBuilder sBuilder = new StringBuilder(str);

        String str1 = new String(sBuffer);
        String str2 = new String(sBuilder);
        
        String str3 = sBuffer.toString();
        String str4 = sBuilder.toString();

5. 一道面试题 

        String str = null;
        StringBuffer sBuffer = new StringBuffer();
        sBuffer.append(str);
        System.out.println(sBuffer.length()); // 4  // appendNull(): value[] = {'n', 'u', 'l', 'l'}
        System.out.println(sBuffer); // "null"

        StringBuffer sBuffer1 = new StringBuffer(str);
        System.out.println(sBuffer1); // NullPointerException

二、日期时间API

  • 第一代:JDK1.0 Date类
  • 第二代:JDK1.1 Calander类
  • 第三代:JDK1.8 提出一套新API

(一)JDK8前

1. System类静态方法 

  • public static long currentTimeMillis()
  • 返回当前时间与1/1/1970 00:00:00 GMT的时间差,也称为时间戳,单位为毫秒
  • 国际标准时间
    • UTC (Coordinated Universal Time)
    • GMT (Greenwich Mean Time)
    • CST (Central Standard Time)
        long time = System.currentTimeMillis();
        System.out.println(time); // 单位毫秒,代表1970年1月1日到现在的时间差,称为时间戳

2. Date类

1)java.util.Date类

  • 两个构造器的使用
    • Date(): 创建一个当前时间的Date对象
    • Date(long型时间): 创建一个指定时间戳的Date对象
  • 两个方法的使用
    • toString(): 显示当前的年、月、日、时、分、秒
    • getTime(): 获取当前Date对象对应的时间戳
        Date date1 = new Date();
        System.out.println(date1.toString()); // Mon Oct 03 15:50:06 CDT 2022
        System.out.println(date1.getTime()); // 1664830206571
        
        // @Deprecated: 过时了,也能用
        Date date2 = new Date(1664830206571L);
        System.out.println(date2.toString()); // Mon Oct 03 15:50:06 CDT 2022

2)java.sql.Date类

  • 实例化问题
  • java.util.Date对象 >> java.sql.Date对象
        java.sql.Date date3 = new java.sql.Date(1664830206571L);
        System.out.println(date3); // 2022-10-03

        Date date4 = new java.sql.Date(1664830206571L);
        java.sql.Date date5 = (java.sql.Date) date4;

        Date date6 = new Date();
//      java.sql.Date date7 = (java.sql.Date) date6; // java.lang.ClassCastException
        java.sql.Date date7 = new java.sql.Date(date6.getTime());

3. SimpleDateFormat类

  • 对日期Date类的格式化和解析

1)格式化:日期 >> 字符串 

        SimpleDateFormat sdf = new SimpleDateFormat(); // 默认空参构造器
        Date date = new Date(); // Thu Oct 06 19:23:53 CDT 2022
        String format = sdf.format(date); // 2022/10/6 下午7:23

2)解析:字符串 >> 日期

        SimpleDateFormat sdf = new SimpleDateFormat();
        String str = "2022/10/6 下午7:23";
        Date date = sdf.parse(str); // Thu Oct 06 19:23:00 CDT 2022
        String str1 = "2022/10/6 7:23";
        Date date4 = sdf.parse(str1); // 报错 Unparseable date: "2022/10/6 7:23"

3) 带有日期格式的实例化

  • 字符串必须符合SDF识别的格式(构造器参数格式),否则会报错Unparseable date
        // SimpleDateFormat实例化(指定日期格式参数)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        //格式化日期
        String format = sdf.format(new Date()); // 2022-10-07 01:45:06

        // 解析日期
        String str = "2022-10-07 01:45:06";
        Date date = sdf.parse(str);// Fri Oct 07 01:45:06 CDT 2022
  • 练习一:将字符串”2022-10-07“转换为java.sql.Date类型
        String str = "2022-10-07";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = sdf.parse(str);
        java.sql.Date date = new java.sql.Date(parse.getTime());
  •  练习二:三天打鱼两天晒网
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date1 = sdf.parse("1990-01-01");
        Date date2 = sdf.parse("2020-10-10");
        long time = date2.getTime() - date1.getTime();
        long day = time / (1000 * 60 * 60 * 24) + 1;
        String result = (day % 5 >= 1 && day % 5 <= 3) ? "打鱼" : "晒网";

4. Calender类

  • Calendar是一个抽象类,完成日期字段之间相互操作的功能

1)实例化

  • 方式1:创建子类GregorianCalendar对象
  • 方式2:调用静态方法getInstance()
        Calendar calendar = Calendar.getInstance();
        System.out.println(calendar.getClass()); // GregorianCalendar

2)常用方法

  • Calender是可变的
  • 注意
    • 获取月份时(MONTH):一月是0,二月是1 ... 十二月是11
    • 获取星期时(DAY_OF_WEEK):周日是1,周一是2 ... 周六是7
        // get()
        int day = calendar.get(Calendar.DAY_OF_MONTH); // 7 返回当前日期是当月的第几天

        // set()
        calendar.set(Calendar.DAY_OF_MONTH, 22);
        day = calendar.get(Calendar.DAY_OF_MONTH); // 22

        // add()
        calendar.add(Calendar.DAY_OF_MONTH, 3); // 25
        calendar.add(Calendar.DAY_OF_MONTH, -3); // 22

        // getTime()
        Date date = calendar.getTime(); // 修改后的calendar日期 Sat Oct 22 19:45:58 CDT 2022

        // setTime()
        calendar.setTime(date); // 修改calendar为date日期

(二)JDK8 

  • Calendar与Date类存在的问题
    • 可变性:日期和时间这样得类应该是不可变的
    • 偏移性:Date中的年份是从1900年开始的,月份是从0开始的
    • 格式化:格式化只对Date有用,Calendar则不行
    • 线程不安全,不能处理闰秒
Date date = new Date(2020 - 1900, 1 -1, 1); // 偏移性
  • 新日期时间API
    • java.time: 值对象的基础包
    • java.time.chrono: 提供对不同的日历系统的访问
    • java.time.format: 格式化和解析时间和日期
    • java.time.temporal: 包括底层框架和延展特性
    • java.time.zone: 包含时区支持的类

1. LocalDate、LocalTime、LocalDateTime类

  • 实例是不可变的对象
  • 表示使用ISO-8601日历系统的日期、时间、日期和时间, 不包含当前时间信息、时区相关信息

1)实例化相关

  • now(): 获取当前日期/时间/日期时间
  • of(): 设置指定年月日时分秒,无偏移量
    LocalDate localDate = LocalDate.now(); // 2022-10-08
    LocalTime localTime = LocalTime.now(); // 13:22:12.199293300
    LocalDateTime localDateTime = LocalDateTime.now(); // 2022-10-08T13:22:12.200296100

    LocalDateTime ofLocalDateTime = LocalDateTime.of(2022, 10, 9, 13, 33, 33);

2)getXxx()获取相关属性:起始为1

        int dayOfMonth = localDateTime.getDayOfMonth(); // 8  获取该月第几天
        int monthValue = localDateTime.getMonthValue(); // 10 

3)withXxx()设置相关属性:体现不可变性

        LocalDate localDate1 = localDate.withDayOfMonth(22);
        System.out.println(localDate1); // 2022-10-22
        System.out.println(localDate); // 2022-10-08

4)plus/ minus 操作:体现不可变性 

        LocalDate localDate2 = localDate.plusMonths(3);
        LocalDate localDate3 = localDate.minusMonths(10);
        System.out.println(localDate2); // 2023-01-08
        System.out.println(localDate3); // 2021-12-08
        System.out.println(localDate); // 2022-10-08

2. Instant类

  • 本初子午线时间瞬时点,起始点1970年1月1日,单位为毫秒,其他时区需加偏移量
        // now(): 获取本初子午线时间
        Instant instant = Instant.now(); // 本初子午线时间

        // atOffSet(): 添加时间偏移量
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8)); //获取东八区时间

        // toEpochMilli(): 获取举例1970年1月1日0时0分0秒到现在的瞬时毫秒数
        long milli = instant.toEpochMilli();

        // ofEpochMilli(Long long): 通过给定毫秒数创建instant实例
        Instant instant1 = Instant.ofEpochMilli(1665251928772L);

3. DateTimeFormatter类

  • 格式化或解析日期/时间,类似于SimpleDateFormat

1)三种实例化方式

  • 预定义的标准模式: (ISO预定义) ISO_LOCAL_DATE, ISO_OFFSET_DATE, ISO_DATE...
    DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
    // 格式化: 日期 >> 字符串
    String strFormat = formatter.format(LocalDateTime.now()); // 2022-10-08T14:19:51.2200785
    // 解析: 字符串 >> 日期
    TemporalAccessor parse = formatter.parse("2022-10-08T14:18:43.2536188"); // {},ISO resolved to 2022-10-08T14:18:43.253618800
  • 本地化相关的格式
    // 1. ofLocalizedDateTime(): FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT
    // 注:FormatStyle.LONG: JDK 8.0可运行,8.0以上需要添加.withZone(ZoneId.systemDefault()
    DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
    String format1 = formatter1.format(LocalDateTime.now()); // 2022/10/8 下午3:24
    DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withZone(ZoneId.systemDefault());
    String format2 = formatter2.format(LocalDateTime.now()); // 2022年10月8日 CDT 下午3:24:16
    // 2. ofLocalizedDate(): FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT
    DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
    String format3 = formatter3.format(LocalDateTime.now()); // 2022年10月8日星期六
  • 自定义格式: ofPattern("自定义日期时间pattern")
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
    // 格式化
    String format = dateTimeFormatter.format(LocalDateTime.now()); // 2022-10-08 03:37:43
    // 解析
    TemporalAccessor parse1 = dateTimeFormatter.parse("2022-10-08 03:37:43");

 2)常用方法总结

  • ofParttern(String pattern): 自定义格式,返回一个指定字符串格式的DateTimeFormatter
  • format(TemporalAccessor t): 格式化,日期 >> 字符串
  • parse(charSequence text0): 解析,字符串 >> 日期

4. 其他API

1)时区相关

  • ZoneId.of(): 获取指定时区的时间
    LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
  • ZonedDateTime: 含时区的日期时间 
    • now(): 获取本时区
    • now(zoneId id): 获取指定时区的ZonedDateTime对象
    ZonedDateTime zonedDateTime = ZonedDateTime.now();
    ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

2)间隔相关

  • Duration: 计算两个”时间“间隔,以秒和纳秒为基准
    • between(): 静态方法,返回Duration对象,表示两个时间的间隔
    • end时间在start时间前,结果为负数
    LocalTime localTime1 = LocalTime.now();
    LocalTime localTime2 = LocalTime.of(15, 23, 23);
    Duration duration = Duration.between(localTime1, localTime2);
    System.out.println(duration.getSeconds());
    System.out.println(duration.getNano());

    LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 10, 22, 22, 22);
    LocalDateTime localDateTime2 = LocalDateTime.of(2022, 10, 10, 22, 22, 22);
    Duration duration1 = Duration.between(localDateTime1, localDateTime2);
    System.out.println(duration1.toDays());
  • Period: 用于计算两个”日期“间隔,以年、月、日衡量
    LocalDate date1 = LocalDate.now();
    LocalDate date2 = LocalDate.of(2020, 10, 10);
    Period period = Period.between(date2, date1);
    System.out.println(period); // P1Y11M28D
    System.out.println(period.getYears()); // 1
    System.out.println(period.getMonths()); // 11
    System.out.println(period.getDays()); // 28

    Period period1 = period.withYears(2); // 不可变性
    System.out.println(period1); // P2Y11M28D

3)时间矫正

  • TemporalAdjuster: 时间矫正量
    // 获取当前日期的下一个周日
    TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
    LocalDateTime nextSunday = LocalDateTime.now().with(temporalAdjuster);
    System.out.println(nextSunday); // 2022-10-09T17:55:53.506655300

    // 获取下一个工作日
    LocalDate nextWorkDay = LocalDate.now().with(new TemporalAdjuster() {
        @Override
        public Temporal adjustInto(Temporal temporal) {
            LocalDate date = (LocalDate) temporal;
            if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
                return date.plusDays(3);
            } else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                return date.plusDays(2);
            } else return date.plusDays(1);
        }
    });
    System.out.println(nextWorkDay);// 2022-10-10

三、Java比较器

  • Java中的对象正常只能进行比较:== , != (判断引用指向对象实体是否相同), 不能使用 >, <

1. Comparable接口 (自然排序)

  • String/包装类等实现了Comparable接口, 重写compareTo()方法提供比较两个对象大小的方式
  • 重写compareTo()规则
    • 当前对象this形参对象obj相比,大于返回正整数,小于返回负整数,相等返回0
    • 结果默认从小到大排列
  • 自定义类需要排序,需实现Comparable接口,重写CompareTo()指明如何排序
        String[] str = new String[]{"FF", "AA", "DD", "CC", "BB"};
        Arrays.sort(str);
    @Test public void test() {
        Goods[] arr = new Goods[5];
        arr[0] = new Goods("lianxiang", 34);
        arr[1] = new Goods("Huawei", 50);
        arr[2] = new Goods("dell", 45);
        arr[3] = new Goods("yiaomi", 12);
        arr[4] = new Goods("xiaomi", 12);
        Arrays.sort(arr); // 如果没有实现Comparable接口会报ClassCastException
        System.out.println(Arrays.toString(arr));
    }

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

    // 构造器, getter, setter, toString省略

    @Override
    public int compareTo(Object o) { // 指明商品比较大小的方式
        if (o instanceof Goods) {
            Goods goods = (Goods) o;
            // 方式1
            if (this.price > goods.price) {
                return 1;
            } else if (this.price < goods.price) {
                return -1;
            } else {
                // 价格相同 按名称从大到小排
                return -this.name.compareTo(goods.name);
            }

            // 方式2
            return Double.compare(this.price, goods.price);
        }
        throw new RuntimeException("传入数据类型不一致");
    }
}

2. Comparator接口 (定制排序)

  • 当元素类型没有实现Comparable接口又不方便修改代码,或接口规则无法满足需求
  • 重写Compare(Object o1, Object o2)规则
    • o1与o2相比,大于返回正整数,小于返回负整数,相等返回0
  • Comparable接口与Comparator接口对比
    • Comparable接口方式一旦指定,可保证实现类的对象在任何位置都可以比较大小
    • Comparator接口属于临时性的比较
    @Test public void test2() {
        Goods[] arr = new Goods[5];
        arr[0] = new Goods("lianxiang", 34);
        arr[1] = new Goods("Huawei", 50);
        arr[2] = new Goods("dell", 45);
        arr[3] = new Goods("xiaomi", 20);
        arr[4] = new Goods("xiaomi", 12);
        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(Arrays.toString(arr));
    }

四、System类

  • System类包含系统级的多种属性和控制方法,位于java.lang包
  • 构造器是private的,无法创建该类的对象
  • 内部的成员变量和成员方法是static的,方便调用
  •  成员变量
    • PrintStream err:标准错误输出流
    • InputStream in:标准输入流
    • PrintStream out:标准输出流
  • 成员方法
    • native long currenTimeMillis(): 
    • void exit(int status): 退出程序,status 为0代表正常退出,非零代表异常退出
    • void gc(): 请求系统进行垃圾回收,系统是否回收取决于回收算法实现以及系统执行情况
    • String getProperty(String key): 获得系统中属性名为key的属性对应的值
属性名属性说明

java.version

Java执行时环境版本
java.homeJava安装目录
os.name操作系统的名称
os.version操作系统的版本
user.name用户的账户名称
user.home用户的主目录
user.dir用户的当前工作目录

五、Math类

  • 提供一些列静态方法用于科学计算,参数和返回值一般为double类型
  • 常用方法
    • abs() 绝对值
    • acos, asin, atan, cos, sin, tan: 三角函数
    • sqrt: 平方根
    • pow(double a, double b): a的b次幂
    • 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): 角度 >> 弧度

六、BigInteger与BigDecimal

1. BigInteger

  • Integer存储最大整型值2^{31}-1,Long存储最大值为2^{63}-1
  • BigInteger表示不可变的任意精度的整数

2. BigDecimal

  • BigDecimal支持不可变的、任意精度的有符号十进制定点数
    BigInteger b1 = new BigInteger("12433241123");
    BigDecimal bd = new BigDecimal("12435.531");
    BigDecimal bd2 = new BigDecimal("11");
    System.out.println(b1);
    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)); // 四舍五入保留15位小数
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值