Java常用类详解

本文详细介绍了Java中的包装类,包括Integer的装箱、拆箱、面试题以及特性;讲解了String的不可变性、效率问题以及常用方法;深入探讨了StringBuilder和StringBuffer的区别和使用场景;还涉及到了Math类的常用方法。此外,还介绍了日期类的发展历程,包括Date、Calendar以及新一代的日期时间API。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java常用类详解

1.包装类

1.1 包装类的分类

  1. 针对八种基本数据类型相应的引用类型—包装类

  2. 有了类的特点,就可以调用类中的方法。

  3. 如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1HT6P0AH-1681671609146)(E:\Java study\Markdown\本地图片\包装类1.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h3g2zTaF-1681671609149)(E:\Java study\Markdown\本地图片\包装类2.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xp6xNYGB-1681671609150)(E:\Java study\Markdown\本地图片\包装类3.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yrzSuWAn-1681671609151)(E:\Java study\Markdown\本地图片\包装类4.png)]

1.1.1 包装类和基本数据的转换
  1. jdk5以前是手动装箱和拆箱方式
    • 装箱:基本类型–>包装类型
    • 拆箱:包装类型–>基本类型
  2. jdk5以后(含jdk5)是自动装箱和拆箱方式
  3. 自动装箱底层调用的是valueOf方法,比如Integer.valueOf()
  4. 下面用int和Integer演示,其他包装类用法类似:
public static void main(String[] args) {
        //演示int <--> Integer 的装箱和拆箱
        //其他包装类的用法相似
        //jdk5前是手动装箱和拆箱
        int n1 = 100;
        Integer integer = new Integer(n1);
        Integer integer1=Integer.valueOf(n1);

        //手动拆箱
        //Integer --> int
        int i = integer.intValue();

        //jdk5以后,就可以自动装箱和自动拆箱
        //自动装箱
    	//底层使用的是 Integer.valueOf(n2)
        Integer integer2 = n1;
    
        //自动拆箱
    	//底层仍然使用的是 Integer.valueOf()方法
        int n2 = integer2;
    }
  1. 下面几道简单的代码判断

    • 下面的代码是否正确,为什么?
    Double d = 100d;//答:正确,自动装箱	Double.valueOf(100d);
    Float f = 1.5f;//答:正确,自动装箱	Double.valueOf(1.5f);
    
    • 下面两个代码输出结果相同吗?各是什么?
    //代码1:
    Object obj1 = true?new Integer(1):new Double(2.0);
    //三元运算符 [是一个整体]
    //所以输出的结果是  1.0
    System.out.println(obj1);
    
    //代码2:
    Object obj2;
    if (true)
        obj2 = new Integer(1);
    else
        obj2 = new Double(2.0);
    //输出的结果为    1
    System.out.println(obj2);
    
1.1.2 包装类型和String 类型的相互转换
  1. 这里以 Integer 和 String 转换为例,其它的类似:
public static void main(String[] args) {
        //包装类(Integer) -> String
        Integer i = 100;//自动装箱
        //方式一
        String str1 = i+"";
        //方式二
        String str2 = i.toString();
        //方式三
        String str3 = String.valueOf(i);
        
        //String -> 包装类(Integer)
        String str4 = "123";
        //方式一
        int i2 = Integer.parseInt(str4);
        //方式二
        Integer i3 = new Integer(str4);
    }
  1. Integer和Character有些常用的方法

    这里只是列举了一点点常用的方法,还有非常多的方法:

public static void main(String[] args) {
        System.out.println(Integer.MIN_VALUE); //返回最小值
        System.out.println(Integer.MAX_VALUE);//返回最大值

        System.out.println(Character.isDigit('a'));//判断是不是数字
        System.out.println(Character.isLetter('a'));//判断是不是字母
        System.out.println(Character.isUpperCase('a'));//判断是不是大写
        System.out.println(Character.isLowerCase('a'));//判断是不是小写

        System.out.println(Character.isWhitespace('a'));//判断是不是空格
        System.out.println(Character.toUpperCase('a'));//转成大写
        System.out.println(Character.toLowerCase('A'));//转成小写
    }
1.1.3 Integer 类面试题 1
  1. 看下面代码,输出什么结果?为什么?
public static void main(String[] args) {
        Integer i = new Integer(1);
        Integer j = new Integer(1);
        System.out.println(i == j);//false


        /*看源码:
        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
        源码解读:
        1. 如果 i 在 IntegerCache.low(-128)~IntegerCache.high(127),就直接从数组返回
        2. 如果不在 -128~127,就直接 new Integer(i)
        */
        //所以,这里主要是看范围 -128 ~ 127 就是直接返回
        Integer m = 1;//底层 Integer.valueOf(1)
        Integer n = 1;//底层 Integer.valueOf(1)
        System.out.println(m == n);//true

    	//128不在 -128~127,就直接 new Integer(i)
        Integer x = 128;//底层 Integer.valueOf(1)
        Integer y = 128;//底层 Integer.valueOf(1)
        System.out.println(x == y);//false
    }
1.1.4 Integer 类面试题总结
  1. 看看下面代码,输出什么结果.
public static void main(String[] args) {
        //实例一
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);//false

        //实例二
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);//false

        //实例三
        Integer i5 = 127;
        Integer i6 = 127;
        System.out.println(i5 == i6);//true

        //实例四
        Integer i7 = 128;
        Integer i8 = 128;
        System.out.println(i7 == i8);//false

        //实例五
        Integer i9 = 127; //Integer.valueOf(127)
        Integer i10 = new Integer(127);
        System.out.println(i9 == i10);//false

        //实例六
        Integer i11 = 127;//Integer.valueOf(127)
        int i12 = 127;
        //只要有基本数据类型,判断的是值是否相等
        System.out.println(i11 == i12);//true

        //实例七
        Integer i13 = 128;
        int i14 = 128;
        //只要有基本数据类型,判断的是值是否相等
        System.out.println(i13 == i14);//true
    }

2. String类

2.1 String类的理解和创建对象

2.1.1 String类的理解
  1. String对象是用保存字符串的,也就是一组字符串序列

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6tv9b2Fu-1681671609152)(E:\Java study\Markdown\本地图片\String.png)]

  2. 字符串常量对象是用双引号括起的字符序列。

    • 例如:“你好”、“hello”、"123"等
  3. 字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节

  4. String类有很多的构造器,实现了构造器的重载

    • 下面几个是较常用的构造器(看其他手册)
String s1 = new String();//
String s2 = new String(String original);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int starIndex,int count);
String s5 = new String(byte[] b)
  1. 代码
public static void main(String01[] args) {
        //1.String对象是用保存字符串的,也就是一组字符串序列
        //2."jack" 字符串常量,用双引号括起的字符序列
        //3.字符串的字符使用Unicode字符编码,一个字符(不区分字母还是汉字)占两个字节
        //4.String 类有很多构造器,实现了构造器的重载
        /*较常用的构造器
        1.String s1 = new String();//
        2.String s2 = new String(String original);
        3.String s3 = new String(char[] a);
        4.String s4 = new String(char[] a,int starIndex,int count);
        5.String s5 = new String(byte[] b)
         */
        //5.String类实现了接口 Serializable[String 可以串行化;可以在网络传输]
        //                     Comparable [String 对象可以比较大小]
        //6.String 是final类,不能被其它类继承
        //7.String 有属性 private final char value[];用于存放字符串内容
        // The value is used for character storage;
        //8.一定要注意: value 是 final类型,不可以修改(地址);
        //  即value不能指向新的地址,但是单个字符内容是可以变化的
        String name = "jack";
        name = "Lucy";

        final char[] value = {'a','b','c'};
        value[0] = '5';//单个字符可以变化

        char[] v2 = {'1','2','3'};
        //value = v2; 不可以修改value的地址
    }
2.1.2 创建String对象的两种方式
  1. 方式一:直接赋值 String S = “sys”;

  2. 方式二:调用构造器 String s = new String(“sys”);

  3. 区别:

    • 方式一:先从常量池查看是否有"sys"数据空间,如果有,直接指向;如果没有则重新创建,然后指向。S最终指向的是常量池的空间地址。
    • 方式二:先在堆中创建空间,里面维护了value属性,指向常量池的"sys"空间,如果常量池没有"sys",重新创建,如果有,直接通过value指向。最终指向的是堆中的空间地址。
  4. 测试题

      1. 判断下面代码输出结果
    public static void main(String[] args) {
            String a = "abc";
            String b = "abc";
            System.out.println(a.equals(b));//true
            System.out.println(a == b);//true
        }
    
      1. 判断下面代码输出结果
    public static void main(String[] args) {
            String a = new String("abc");
            String b = new String("abc");
            System.out.println(a.equals(b));//true
            System.out.println(a == b);//false
        }
    
      1. 判断下面代码输出结果
    public static void main(String[] args) {
            String a = "abc";//a指向常量池
            String b = new String("abc");//b指向堆中对象
            System.out.println(a.equals(b));//true
            System.out.println(a == b);//false
            System.out.println(a == b.intern());//true
            System.out.println(b == b.intern());//false
    
        /*
        当调用intern方法时,如果池里已经包含一个等于此String对象的字符串(用equals(Object)方法确定),
        则返回来自池的字符串。 否则,将此String对象添加到池中,并返回此String对象的引用。
        解读:(1)b.intern()方法最终返回的是常量池的地址(对象)。
         */
        }
    
      1. 判断下面代码输出结果
    public static void main(String[] args) {
            String s1 = "sys";
            String s2 = "java";
            String s4 = "java";
            String s3 = new String("java");
            System.out.println(s2 == s3);//false
            System.out.println(s2 == s4);//true
            System.out.println(s2.equals(s3));//true
            System.out.println(s1 == s2);//false
        }
    
      1. 判断下面代码输出结果
    public static void main(String[] args) {
            Person p1 = new Person();
            p1.name = "sys";
            Person p2 = new Person();
            p2.name = "sys";
    
            System.out.println(p1.name.equals(p2.name));//比较内容:true
            System.out.println(p1.name == p2.name);//true
            System.out.println(p1.name == "sys");//true
    
            String s1 = new String("abcd");
            String s2 = new String("abcd");
            System.out.println(s1 == s2);//false
        }
    

3. 字符串的特性

  1. 判断下面代码创建了几个对象

    • 练习1:
    public static void main(String[] args) {
            //1.String 是一个final类,代表不可变的字符序列
            //2.字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的
            //以下语句创建了几个对象?
            String s1 = "hello";//s1指向常量池里面的"hello"
    
            //此时常量池里面没有"haha",重新创建一个"haha"
            // 然后s1指向常量池里面的"haha"
            // 所以一共创建了两个对象
            s1 = "haha";
        }
    
    • 练习2:
    public static void main(String[] args) {
            //题1:下面代码创建了几个对象?
            String a = "hello"+"abc";
            //代码解读
            //原先代码: String a = "hello"+"abc";
            //编译器会做一个优化,判断创建的常量池对象,是否有引用指向
            //直接把代码优化为: String a = "helloabc";
            //所以只有一个对象
    
            //题2:下面代码创建了几个对象?
            String b = "hello";//创建了b对象
            String c = "abc";//创建了c对象
            String d = b+c;
            //关键是分析 String d = b+c;到底是怎么执行的
            
            //代码解读 String d = b+c;
            //1.底层先创建一个StringBuilder (Stringbuilder sb = StringBuilder)
            //2.然后执行sb.append("hello");
            //3.接着执行sb.append("abc");
            //  sb在堆中,并且append是在原来字符串的基础上追加的
            //4.String c = sb.toString();
            //最后其实是 c 指向堆中的对象(String)value[]-->池中"helloabc"
            //所以一共有三个对象
            
            //重要规则
            //String a = "hello"+"abc"; 常量相加,看的是池
            //String d = b+c; 变量相加,是在堆中;
        }
    
  2. 下面代码的运行结果是什么?

      1. 下面代码输出什么,请说明原因
    public static void main(String[] args) {
            //下面代码输出什么
            String s1 = "sys";//s1指向池中的"sys"
            String s2 = "java";//s2指向池中的"java"
            String s3 = "sysjava";//s3指向池中的"sysjava"
            String s4 = (s1+s2).intern();//s4指向池中的"sysjava"
            System.out.println(s3==s4);//true
            System.out.println(s3.equals(s4));//true
        }
    
      1. 下面程序运行的结果是什么?
    public static void main(String[] args) {
            Test1 ex = new Test1();
            ex.change(ex.str, ex.ch);
            System.out.println(ex.str+"and");//输出sysand
            System.out.println(ex.ch);//输出hava
        }
    class Test1{
        String str = new String("sys");
        final char[] ch = {'j','a','v','a'};
        public void change(String str,char ch[]){
            str = "java";
            ch[0] = 'h';
        }
    }
    

4. String类的常见方法

4.1 说明

  1. String类是保存字符串常量的。每次更新都需要重新开辟空间,效率极低,因此java设计者还提供了StringBuilder和StringBuffer来增强String的功能,并提高效率。[初步了解]
//例如这段代码
String s = new String("");
for(int i = 0,i <10000,i++){
    s+="hello";
}

4.2 String类的常见方法1[了解]

  1. equals //区分大小写,判断内容是否相等
  2. equalslgnoreCase //忽略大小写的判断内容是否相等
  3. length //获取字符的个数,字符串的长度
  4. indexOf //获取字符在字符串中第1次出现的索引 (索引从0开始。如果找不到,就返回-1)
  5. lastIndexOf //获取字符在字符串中最后1次出现的索引 (索引从0开始。如果找不到,就返回-1)
  6. substring //截取指定范围的子串
  7. trim //去前后空格
  8. charAt //获取某索引处的字符,注意不能使用 Str[index] 这种方式
public static void main(String[] args) {
    //1. equals //区分大小写,判断内容是否相等
        String str1 = "hello";
        String str2 = "Hello";
        System.out.println(str1.equals(str2));//false

    //2. equalslgnoreCase //忽略大小写的判断内容是否相等
        String str3 = "Jack";
        if ("jack".equalsIgnoreCase(str3)) {
            System.out.println("ok");
        } else {
            System.out.println("no");
        }//输出ok

    //3. length //获取字符的个数,字符串的长度
        String str4 = "sys";
        System.out.println(str4.length());//3

    //4. indexOf //获取字符在字符串中第1次出现的索引 (索引从0开始。如果找不到,就返回-1)
        String str5 = "sys@java@study";
        int index = str5.indexOf('@');
        System.out.println(index);//3
        System.out.println("sys="+str5.indexOf("sys"));//0

    //5. lastIndexOf //获取字符在字符串中最后1次出现的索引 (索引从0开始。如果找不到,就返回-1)
        int index2 = str5.lastIndexOf("@");
        System.out.println(index2);//8
        System.out.println("java="+str5.lastIndexOf("java"));//4

    //6. substring //截取指定范围的子串
        String name = "hello,jack";
        System.out.println(name.substring(6));//从索引6开始截取后面的所有内容
        System.out.println(name.substring(0,5));//表示从索引0开始,截取到索引 5-1 = 4的字符
    //7. trim //去前后空格
    //8. charAt //获取某索引处的字符,注意不能使用 Str[index] 这种方式
    }

4.3 String类的常见方法应用实例2[了解]

  1. toUpperCase //转换成大写
  2. toLowerCase //转换成小写
  3. concat //拼接字符
  4. replace //替换字符串中的字符
  5. split //分割字符串,对于某些分割字符,我们需要转义 比如 | \ \deng
  6. compareTo //比较两个字符串的大小
  7. toCharArray //转换成字符数组
  8. format //格式化字符串,%s 字符串, %c 字符, %d 整型, %.2f 浮点型,
public static void main(String[] args) {
        //1. toUpperCase //转换成大写
        String str1 = "jack";
        System.out.println(str1.toUpperCase());//JACK

        //2. toLowerCase //转换成小写
        String str2 = "JAVA";
        System.out.println(str2.toLowerCase());//java

        //3. concat //拼接字符
        String str3 = "sys";
        str3 = str3.concat("学").concat("学").concat("java");
        System.out.println(str3);//sys 学 学 java

        //4. replace //替换字符串中的字符
        //  str3.replace() 方法执行后,返回的结果才是替换过的
        //  注意:对 str3 没有任何影响
        String str4 = str3.replace("学","study");//将所有的 学 替换成 study
        System.out.println(str3);//sys 学 学 java
        System.out.println(str4);//sys study study java

        //5. split //分割字符串,对于某些分割字符,我们需要转义 比如 | \\ \deng
        String poem = "大家好,我是,sys,学,java";
        // 以 , 为标准对 poem进行分割,返回一个数组
        String[] poem1 = poem.split(",");
        for (int i = 0; i < poem1.length; i++) {
            System.out.println(poem1[i]);
        }

        poem = "D:\\aaa\\bbb\\ccc";
        // 在对字符串进行分割时,如有特殊字符,需要加入 转义符 \
        poem1 = poem.split("\\\\");
        for (int i = 0; i < poem1.length; i++) {
            System.out.println(poem1[i]);
        }

        //6. compareTo //比较两个字符串的大小
        //  如果前者大,则返回正数
        //  如果后者大,则返回负数
        //  如果两者相等,则返回0
        String a = "jack";
        String b = "jack";
        String c = "lucy";
        //如何比较
        //1.如果长度相等,并且每个字符也相同,就返回0
        //2.如果长度或字符不相等,在进行比较时,可以区分大小写
        //      if (c1 != c2) {
        //          return c1 - c2;
        //       }
        //3.如果长度不同,如果前面的部分都相同,就返回str1.length - str2.length
        System.out.println(a.compareTo(b));//0
        System.out.println(a.compareTo(c));//-2

        //7. toCharArray //转换成字符数组
        String s = "imformation";
        char[] ch = s.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            System.out.println(ch[i]);
        }

        //8. format //格式化字符串,%s 字符串, %c 字符, %d 整型, %.2f 浮点型,
        String name = "sys";
        int age = 28;
        double score = 88.8;
        char gender = '男';
        String info =
                "我的名字是"+name+"年龄是"+age+"成绩是"+score+"性别是"+gender+"很高兴认识大家";
        System.out.println(info);
        //%s , %c , %d , %.2f 称为占位符;
        //这些占位符由后面变量来替换
        //%s 表示后面用 字符串 来替换
        // %c 表示后面由 字符 来替换
        // %d 表示后面由 整数 来替换
        // %.2f 表示后面由 浮点数 来替换 2f表示保留2位小数[四舍五入]
        //写法1:
        String info2 = String.format("我的名字是%s 年龄是%d 成绩是%.2f 性别是%c 很高兴认识大							家",name,age,score,gender);
        System.out.println(info2);
        //写法2:
        String formatStr = "我的名字是%s 年龄是%d 成绩是%.2f 性别是%c 很高兴认识大家";
        String info3 = String.format(formatStr,name,age,score,gender);
        System.out.println(info3);
    }

5. StringBuffer 类

5.1 基本介绍

  1. java.lang.StringBuffer 代表可变的字符序列,可以对字符串进行增删;
  2. StringBuffer的很多方法和String相同,但StringBuffer是可变长度的;
  3. StringBuffer 的直接父类 是 AbstractStringBuilder;
  4. StringBuffer 实现了 Serializable, 即StringBuffer的对象可以串行化;
  5. 在父类中 AbstractStringBuilder 有属性 char[] value,不是final
    • 该 value 数组存放 字符串内容,引出存放在堆中的
  6. SringBuffer 是一个final类,不能被继承
  7. 因为StringBuffer字符内容是存在 char[] value,所以在变化(增加/删除) ,不用每次都更换地址(即创建新对象),所以效率高于String

5.2 String VS StringBuffer

  1. String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率极低。//private final char value[];
  2. StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率极高。//char[] value 放在堆中

5.3 StringBuffer的构造器

  1. StringBuffer()
    • 构造一个没有字符的字符串缓冲区,初始容量为16个字符。
  2. StringBuffer(CharSequence seq)
    • 构造一个包含与指定的相同字符的字符串缓冲区 CharSequence 。
  3. StringBuffer(int capacity)
    • 构造一个没有字符的字符串缓冲区和指定的初始容量。
  4. StringBuffer(String str)
    • 构造一个初始化为指定字符串内容的字符串缓冲区。
public static void main(String[] args) {
        //StringBuffer 构造器的使用:
        // 1.创建一个 大小为 16 的char[] ,用于存放字符内容
        StringBuffer stringBuffer = new StringBuffer();

        //2.构造一个包含与指定的相同字符的字符串缓冲区 CharSequence 。
        //StringBuffer(CharSequence seq)

        //3.通过构造器指定 char[] 大小
        StringBuffer stringBuffer1 = new StringBuffer(100);

        //4.通过 给一个String 创建StringBuffer , char[]大小就是 str.length()+16
        StringBuffer stringBuffer2 = new StringBuffer("hello");

    }

5.4 String和StringBuffer相互转换

  1. 在开发中,我们经常需要将String和StringBuffer进行转换
  2. 看如下代码
public static void main(String[] args) {
        //看 String --> StringBuffer
        String s = "hello";
        //方式 1 使用构造器
        //注意: 返回的才是 StringBuffer 对象,对 str 本身没有影响
        StringBuffer stringBuffer = new StringBuffer(s);
        //方式二:使用的是 append 方法
        StringBuffer stringBuffer1 = new StringBuffer();
        stringBuffer1 = stringBuffer1.append(s);

        //看 StringBuffer --> String
        StringBuffer stringBuffer2 = new StringBuffer("sys");
        //方式一:使用 StringBuffer 提供的 toString 方法
        String s2 = stringBuffer2.toString();
        //方式二:使用构造器来搞定
        String s3 = new String(stringBuffer2);
    }

5.5 StringBuffer类常见方法

  1. 增append
  2. 删delete(start,end)
  3. 改replace(start,end,string)
    • 将start—end间的内容换掉,不含end
  4. 查indexOf
    • 查找子串在字符串第一次出现的索引,如果找不到返回-1
  5. 插insert
  6. 获取长度length
  7. 代码操作:
public static void main(String[] args) {
        //增 append
        StringBuffer stringBuffer = new StringBuffer("sys");
        stringBuffer.append("学");//sys学
        stringBuffer.append("100");//sys学100
        stringBuffer.append("java");//sys学100java
        System.out.println(stringBuffer);

        //删 delete
        /*
        删除索引为>=start && < end处的字符
        解读:删除 4~7处的字符 [4,7)
         */
        stringBuffer.delete(4,7);//删除4-6位置的字符
        System.out.println(stringBuffer);//sys学java

        //改 replace
        //将start---end间的内容换掉,不含end
        //使用 study 替换掉 索引3-4的字符[3,4)
        stringBuffer.replace(3,4," study ");
        System.out.println(stringBuffer);//sys study java

        //查 indexOf
        //查找指定的子串在字符串第一次出现的索引,如果找不到就返回-1
        int index = stringBuffer.indexOf("study");
        System.out.println(index);//4

        //插入 inert
        //在索引9的位置插入100
        stringBuffer.insert(9,"100");
        System.out.println(stringBuffer);//sys study100 java

        //长度 length
        System.out.println(stringBuffer.length());//17
    }

5.6 StringBuffer 练习题

  1. 看下面代码输出什么?为什么
public static void main(String[] args) {
        String str = null;
        StringBuffer sb = new StringBuffer();
        sb.append(str);//需要看源码
        //底层调用的是AbstractStringBuilder的 appendNull()
        //直接把空转为一个字符串{'n','u','l','l'}
        System.out.println(sb.length());//字符串的长度为4

        System.out.println(sb);//null
        
        //看底层源码
        StringBuffer sb1 = new StringBuffer(str);
        /*
        public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
         */
        //这里会变成 null.length() + 16 
        //这里构造器会直接抛出空指针异常
        // NullPointerException
        System.out.println(sb1);
    }
  1. 按照要求编写代码:
public static void main(String[] args) {
        //输入商品名称和价格,要求打印效果示例,
        // 使用前面学习的方法完成:
        /*
        商品名     商品价格
        手机      123,561,531,564.59
         */
        //要求:价格的小数点前面每三位用小数点隔开
        String a = "商品名";
        String price = "123561531564.59";
        StringBuffer sb = new StringBuffer(a);
        StringBuffer sb2 = new StringBuffer(price);
        //增加"商品价格"  补齐抬头
        sb = sb.append("\t商品价格");
        //先完成一个最简单的实现123564.59
        //找到小数点的索引 ,然后再该位置的前3位插入 , 即可
        /*初始操作
        int index = sb2.indexOf(".");
        sb2.insert(index-3,",");
         */
        //万一数字不止那么多,上面两步只插入了一个 ,
        // 上面两步需要做一个循环处理
        //循环方法1:
        /*
        int index = sb2.indexOf(".");
        for (int i = index; i >3; i-=3) {
            sb2 = sb2.insert(index-3,",");
            index-=3;
        }

         */
        //循环方法2:把代码合并为一个代码
        for (int i = sb2.indexOf(".")-3; i > 0 ; i-=3) {
            sb2 = sb2.insert(i,",");
        }
        //前面插入 "手机"
        sb2.insert(0,"手机\t");

        System.out.println(sb);
        System.out.println(sb2);
    }

6.StringBuilder类

6.1 基本介绍

  1. StringBuilder 是一个可变的字符序列。
  2. 此类提供一个与StringBuffer 兼容的API,但不保证同步。(StringBuilder 不是线程安全的)
  3. 该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。
  4. 如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer要快。
  5. 在 StringBuilder 上的主要操作是 append 和 insert 方法,可重载这些方法,以接收任意类型的数据。

6.2 结构剖析

  1. StringBuilder 继承了 AbstractStringBuilder 类;
  2. 实现了 Serializable ,说明StringBuilder对象是可以串行化(对象可以网络传输,可以保存到文件);
  3. StringBuilder 是final类,不能被继承;
  4. StringBuilder 对象字符序列仍然是存放在其父类AbstractStringBuilder的char[] value中,因此,字符序列是在堆中;
  5. StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字,因此在单线程的情况下使用StringBuilder;

6.3 String、StringBuffer和StringBuilder的比较

  1. StringBuilder 和StringBuffer 非常相似,均可代表可变的字符序列,而且方法也一样;
  2. String:不可改变字符序列,效率低,但是复用率高;
  3. StringBuffer:可改变字符序列、效率较高(增删)、线程安全(看源码,方法都有synchronized关键字);
  4. StringBuilder:可改变字符序列,效率最高、线程不安全;
  5. String使用注意说明:
    • String s = “a”;//创建了一个字符串
    • s += “b”;//实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+“b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符对象留在内存中,降低效率。如果这样的操作放在循环中,会极大影响程序的性能;
    • 结论:如果我们对String做大量修改,不要使用String;

6.4 String、StringBuffer和StringBuilder的效率测试

  1. 测试代码如下:
public static void main(String[] args) {
        //设置初始时间和结束时间清零
        long startTime = 0L;
        long endTime = 0L;
        //StringBuffer
        StringBuffer buffer = new StringBuffer("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 200000; i++) {
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间为" + (endTime - startTime));//32ms
        //StringBuilder
        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 200000; i++) {
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder的运行时间为" + (endTime - startTime));//15ms
        //String
        String test = "";
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 200000; i++) {
            test = test + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String的运行时间为" + (endTime - startTime));//17614ms
    }
  1. 由上面的代码测试可得效率:
    • StringBuilder > StringBuffer > String

6.5 String、StringBuffer和StringBuilder的选择

使用的原则,结论:
  1. 如果字符串存在大量的修改操作,一般使用StringBuffer或StringBuilder
  2. 如果字符串存在大量的修改操作,并在单线程的情况下,使用StringBuilder
  3. 如果字符串存在大量的修改操作,并在多线程的情况下,使用StringBuffer
  4. 如果我们字符串很少修改,被多个对象引用,使用String。
    • 比如配置信息等
  5. StringBuilder和StingBuffer的方法一样。

7. Math类

7.1. 基本介绍

  1. Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

7.2. Math方法一览(均为静态方法)

  1. abs 绝对值
  2. pow 求幂
  3. ceil 向上取整,返回 >= 该参数的最小整数
  4. floor 向下取整,返回 <= 该参数的最大整数
  5. round 四舍五入 相当于Math.floor(该参数+0.5)
  6. sqrt 求开方
  7. random 求随机数
  8. max min 最大值和最小值
  9. 下面进行简单的代码操作:
public static void main(String[] args) {
        //Math的静态方法
        //1.abs 绝对值
        int abs = Math.abs(-3);
        System.out.println(abs);//3
        //2.pow 求幂
        double pow = Math.pow(2, 3);//2的3次方
        System.out.println(pow);//8.0
        //3.ceil 向上取整,返回 >= 该参数的最小整数
        double ceil = Math.ceil(5.2);
        System.out.println(ceil);//6.0
        //4.floor 向下取整,返回 <= 该参数的最大整数
        double floor = Math.floor(2.9);
        System.out.println(floor);//2.0
        //5.round 四舍五入 相当于Math.floor(该参数+0.5)
        double round = Math.round(5.49);
        System.out.println(round);//5.0
        //6.sqrt 求开方
        double sqrt = Math.sqrt(9);
        System.out.println(sqrt);//3.0
        //7.random 求随机数
        //思考:请写出获取 a-b 之间的一个随机整数,
        //      a,b均为正数     2-7
        //解题思路:
        //(1) random 返回的是 0 <= x <1 之间的一个随机小数
        //(2) Math.random()*(b-a) 返回的是 0 <= x <(b-a)的随机小数
        //(3) (int)(a+Math.random()*(b-a+1)) 返回的就是 a <= x <b-a+1的随机整数
        //      现在要取2-7之间的整数,那么就是(int)(2+Math.random()*(7-2+1))
        //      Math.random()*6 返回的是 0 <= x < 6
        //      2+Math.random()*6 返回的是 2 <= x < 8
        //      那么(int)(2+Math.random()*6) 返回的就是2-7之间的随机整数
        //(4) 公式就是(int)(a+Math.random()*(b-a+1))
        int random = (int) (2 + Math.random() * 6);
        for (int i = 0; i < 10; i++) {
            System.out.println(random);//输出2-7之间的随机整数
        }

        //8.max min 最大值和最小值
        int min = Math.min(21, 66);
        int max = Math.max(21, 66);
        System.out.println(min);//21
        System.out.println(max);//66
    }

8.Arrays类

8.1 Arrays类常见方法应用案例

  1. Arrays里面包含了一系列静态方法,用于管理或操作数组(比如排序和搜索)。

    • ① toString 返回数组的字符串形式 Arrays.toString(arr)
    public static void main(String[] args) {
            Integer[] integers = {1, 2, 5, 15};
            /*
            //以前遍历数组
            for (int i = 0; i < integers.length; i++) {
                System.out.println(integers[i]);
            }
             */
            //toString 返回数组的字符串形式
            System.out.println(Arrays.toString(integers));//[1, 2, 5, 15]
        }
    
    • ② sort 排序(自然排序和定制排序) Integer arr[] = {-5, 1, -10, 7, 0, 18, 9};
    public static void main(String[] args) {
            //sort 排序(自然排序和定制排序)
    
            //1. 可以直接使用冒泡排序 , 也可以直接使用 Arrays 提供的 sort 方法排序
            //2. 因为数组是引用类型,所以通过 sort 排序后,会直接影响到 实参 arr
            //3. sort 重载的,也可以通过传入一个接口 Comparator 实现定制排序
            //4. 调用 定制排序 时,传入两个参数
            /*
            (1) 排序的数组 arr
            (2) 实现了 Comparator 接口的匿名内部类 , 要求实现	compare 方法
             */
            //5.这里体现了接口编程的方式 , 看看源码,就明白
            //	源码分析
            //(1) Arrays.sort(arr, new Comparator()
            //(2) 最终到 TimSort 类的
            // private static <T> void binarySort(T[] a, int lo, int hi, int start,Comparator<? super T> c)()
            //(3) 执行到 binarySort 方法的代码, 会根据动态绑定机制 c.compare()
            //    执行我们传入的匿名内部类的 compare ()
            /*
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (c.compare(pivot, a[mid]) < 0)
                right = mid;
                else
                left = mid + 1;
            }
             */
            /*(4)
            new Comparator() {
                 @Override
                 public int compare(Object o1, Object o2) {
                 Integer i1 = (Integer) o1;
                 Integer i2 = (Integer) o2;
                 return i2 - i1;
                 }
            }
             */
            //(5) public int compare(Object o1, Object o2) 返回的值>0 还是 <0
            //	会影响整个排序结果, 这就充分体现了 接口编程+动态绑定+匿名内部类的综合使用
            //	底层框架和源码的使用方式,会非常常见
    
            Integer arr[] = {-5, 1, -10, 7, 0, 18, 9};
    
            //自然排序
            //Arrays.sort(arr); // 默认排序方法
            /*
            Arrays.sort(arr);//[-10, -5, 0, 1, 7, 9, 18]
             */
    
            //定制排序
            Arrays.sort(arr, new Comparator() {
                @Override
                public int compare(Object o1, Object o2) {
                    Integer i1 = (Integer) o1;
                    Integer i2 = (Integer) o2;
                    return i2 - i1;// [18, 9, 7, 1, 0, -5, -10]
                    //return i1-i2;// [-10, -5, 0, 1, 7, 9, 18]
                }
            });
            System.out.println(Arrays.toString(arr));
        }
    
    • 上面提到的sort定制排序,我们可以自己通过原理冒泡排序去编一个定制排序的代码,能更好的理解
    public static void main(String[] args) {
            int[] arr = {1,-1,8,2};
            //bubble(arr);//冒泡排序
            bubble02(arr, new Comparator() {
                @Override
                public int compare(Object o1,Object o2) {
                    int i1 = (Integer)o1;
                    int i2 = (Integer)o2;
                    //return i1 - i2;// [-1, 1, 2, 8]
                    return i2 - i1;// [8, 2, 1, -1]
                }
            });
            System.out.println(Arrays.toString(arr));
        }
        //冒泡排序
        public static void bubble(int[] arr){
            int temp = 0;
            for (int i = 0; i < arr.length-1; i++) {
                for (int j = 0; j < arr.length-1-i; j++) {
                    if (arr[j]>arr[j+1]){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
        }
    
        //定制排序
        public static void bubble02(int[] arr,Comparator c){
            int temp = 0;
            for (int i = 0; i < arr.length-1; i++) {
                for (int j = 0; j < arr.length-1-i; j++) {
                    //数组排序由 c.compareTo(arr[j],arr[j+1]) 返回的值决定
                    if (c.compare(arr[j],arr[j+1])>0){
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
        }
    
    • ③ binarySearch 通过二分搜索法进行查找,要求必须排好序 int index = Arrays.binarySearch(arr,3);
    public static void main(String[] args) {
            //binarySearch 通过二分搜索法进行查找,要求必须排好序
            Integer[] arr = {1,3,5,8,12,25};
    
            //1.使用binarySearch 二叉查找
            //2.要求该数组是有序的,如果该数组无序,那么不能使用binarySearch
            //3.如果该数组不存在该元素,那么返回 return -(low + 1);  // key not found.
            //  low 代表数组在的位置
            int index = Arrays.binarySearch(arr,5);
            System.out.println("index = "+index);//输出2
            //找不到的情况下
            //如果 9 存在的话应该在8后面,那么下标应该为 4
            //现在不存在 9,所以index = -(4+1) = -5
            int index2 = Arrays.binarySearch(arr,9);
            System.out.println("index2 = "+index2);//输出-5
        }
    
    • ④ copyOf 数组元素的复制 Integer[] newArr = Arrays.copyOf(arr,arr.length);
    public static void main(String[] args) {
            Integer[] arr = {1, 3, 5, 8, 25};
            //copyOf 数组元素的复制  Integer[] newArr = Arrays.copyOf(arr,arr.length);
            //1.从 arr 数组中,拷贝 arr.length 个元素到新数组 newArr 中
            //2.如果拷贝的长度 > arr.length 就在新数组后面加一个 null
            //3.如果拷贝长度 < arr.length 就从数组 arr 最后面往前删除数组元素
            //     当拷贝长度 < 0时,就会抛出异常 NegativeArraySizeException
            //4.该方法使用的底层源码是 System.arraycopy()
    
            //完全拷贝
            //1.从 arr 数组中,拷贝 arr.length 个元素到新数组 newArr 中
            Integer[] newArr = Arrays.copyOf(arr, arr.length);
            System.out.println("===拷贝执行完后===");
            System.out.println(Arrays.toString(newArr));//[1, 3, 5, 8, 25]
    
            //增加拷贝数组长度
            //2.如果拷贝的长度 > arr.length 就在新数组后面加一个 null
            Integer[] newArr2 = Arrays.copyOf(arr, arr.length + 1);
            System.out.println(Arrays.toString(newArr2));//[1, 3, 5, 8, 25, null]
    
            //减少拷贝数组长度
            //3.如果拷贝长度 < arr.length 就从数组 arr 最后面往前删除数组元素
            //     当拷贝长度 < 0时,就会抛出异常 NegativeArraySizeException
            Integer[] newArr3 = Arrays.copyOf(arr, arr.length - 1);
            System.out.println(Arrays.toString(newArr3));//[1, 3, 5, 8]
            //当拷贝长度 < 0时
            Integer[] newArr4 = Arrays.copyOf(arr, arr.length - 6);
            //抛出异常 NegativeArraySizeException
            System.out.println(Arrays.toString(newArr4));
        }
    
    • ⑤ fill 数组元素的填充
    • ⑥ equals 比较两个数组元素内容是否完全一致
    • ⑦ asList 将一组值,转换成 list
    • 代码剖析:
    public static void main(String[] args) {
            Integer[] arr = {1, 3, 5};
            //fill 数组元素的填充
            //使用 6 去填充 arr 数组,可以理解为6替换原数组中所有的元素
            Arrays.fill(arr, 6);
            System.out.println(Arrays.toString(arr));//[6, 6, 6]
    
            //equals 比较两个数组元素内容是否完全一致
            //1.如果两个数组中的元素完全一样,则返回true
            //2.如果两个数组中的元素不是完全一样,则返回false
            Integer[] arr2 = {1, 3, 5};
            Integer[] arr3 = {1, 3, 5, 7};
            boolean equals = Arrays.equals(arr, arr2);
            boolean equals2 = Arrays.equals(arr, arr3);
            System.out.println("equals = " + equals);//true
            System.out.println("quals2 = " + equals2);//false
    
            // asList 将一组值,转换成 list
            //1.asList 方法,会将(1,3,5,7)的数据转成一个List集合
            //2.返回的是 asList 编译类型 List(接口)
            //3.asList 运行类型 java.util.Arrays$ArrayList
            //  是Arrays里面的静态内部类
            //  private static class ArrayList<E> extends AbstractList<E>
            //        implements RandomAccess, java.io.Serializable
            List asList = Arrays.asList(1, 3, 5, 7);
            System.out.println("asList = " + asList);
            System.out.println("asList的运行类型" + asList.getClass());
        }
    

8.2 Arrays类小练习

  1. 案例:自定义 Book 类,里面包含 name 和 price,按 price 排序(从大到小)。

  2. 要求:

    • 使用两种方式排序 , 有一个 Book[] books = 4 本书对象.
    • 使用前面学习过的传递 实现 Comparator 接口匿名内部类,也称为定制排序。
    • 可以按照 price (1)从大到小 (2)从小到大 (3) 按照书名长度从大到小
    • 代码如下:
    public static void main(String[] args) {
            //1. 案例:自定义 Book 类,里面包含 name 和 price,按 price 排序(从大到小)。
            //2. 要求:
            //   使用两种方式排序 , 有一个 Book[] books = 4 本书对象.
            //   使用前面学习过的传递 实现 Comparator 接口匿名内部类,也称为定制排序。
            //   可以按照 price (1)从大到小 (2)从小到大 (3) 按照书名长度从大到小
            Book[] books = new Book[4];
            books[0] = new Book("西游记", 66);
            books[1] = new Book("三国演义", 68);
            books[2] = new Book("金瓶梅新版", 88);
            books[3] = new Book("新少林寺传奇", 99);
            /*
            //(1) 从大到小
            Arrays.sort(books, new Comparator() {
                //这里是对Book数组排序,因此o1 和o2就是Book对象
                @Override
                public int compare(Object o1, Object o2) {
                    Book books1 = (Book)o1;
                    Book books2 = (Book)o2;
                    int priceVal = books1.getPrice()-books2.getPrice();
                    //进行转换
                    if (priceVal>0){
                        return -1;
                    } else if (priceVal<0) {
                        return 1;
                    }else {
                        return 0;
                    }
                }
            });
             */
            
            /*
            //(2) 从小到大
            Arrays.sort(books, new Comparator() {
                //这里是对Book数组排序,因此o1 和o2就是Book对象
                @Override
                public int compare(Object o1, Object o2) {
                    Book books1 = (Book)o1;
                    Book books2 = (Book)o2;
                    int priceVal = books1.getPrice()-books2.getPrice();
                    //进行转换
                    if (priceVal>0){
                        return 1;
                    } else if (priceVal<0) {
                        return -1;
                    }else {
                        return 0;
                    }
                }
            });
            */
    
            //(3) 按照书名长度从大到小
            Arrays.sort(books, new Comparator() {
                //这里是对Book数组排序,因此o1 和o2就是Book对象
                @Override
                public int compare(Object o1, Object o2) {
                    Book books1 = (Book) o1;
                    Book books2 = (Book) o2;
                    return books2.getName().length() - books1.getName().length();
                }
            });
            System.out.println(Arrays.toString(books));
        }
    }
    //创建 Book 类,里面包含 name 和 price
    class Book {
        private String name;
        private int price;
    	//构造器
        public Book(String name, int price) {
            this.name = name;
            this.price = price;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getPrice() {
            return price;
        }
    
        public void setPrice(int price) {
            this.price = price;
        }
    	//子类重写toString方法
        @Override
        public String toString() {
            return "books{" +
                    "name='" + name + '\'' +
                    ", price=" + price +
                    '}';
        }
    }
    

9. System类

9.1 System类常见的方法和案例

  1. exit 退出当前程序
  2. arraycopy:复制数组元素,比较适合底层调用,一般使用 Arrays.copyOf 完成复制数组
  3. currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
  4. gc:运行垃圾回收机制 System.gc();
  5. 代码剖析:
public static void main(String[] args) {
        /*
        //1. exit 退出当前程序
        System.out.println("s1");//输出s1
        //1. exit(0) 表示程序退出
        //2. 0表示一个状态,正常的状态
        System.exit(0);
        System.out.println("s2");//输出不了s2
         */

        /*
        //2. arraycopy:复制数组元素,比较适合底层调用,
        //  一般使用 Arrays.copyOf 完成复制数组
        int[] src = {1,2,3};
        int[] dest = new int[3];
        // src: 源数组
        // src – the source array.
        // srcPos: 从源数组的哪个索引位置开始
        // srcPos – starting position in the source array.
        // dest: 目标数组,即把源数组的数组拷贝到哪个数组
        // dest – the destination array.
        // destPos: 把源数组的数据拷贝到 目标数组的哪个索引
        // destPos – starting position in the destination data.
        // length: 从源数组拷贝多少个数据到目标数组
        // length – the number of array elements to be copied.

        //从源数组 src 索引为0的位置开始 拷贝到目标数组 dest 索引为0的位置,拷贝3个数据
        System.arraycopy(src,0,dest,0,3);
        System.out.println(Arrays.toString(dest));//[1, 2, 3]

        //从源数组 src 索引为1的位置开始 拷贝到目标数组 dest 索引为1的位置,拷贝2个数据
        System.arraycopy(src,1,dest,1,2);
        System.out.println("dest="+Arrays.toString(dest));//[0,2,3]
         */

        //currentTimeMillens:返回当前时间距离1970-1-1的毫秒数
        System.out.println(System.currentTimeMillis());
    }

10. BigInteger和BigDecimal类

10.1 BigInteger和BigDecimal介绍

应用场景:
  1. BigInteger适合保存比较大的整型(整数)
public static void main(String[] args) {
        //当我们编程中,需要处理很大的整数,long不够用
        //可以使用BigInteger的类来搞定
        /*
        long l = 14156534156144649999999999L;
        System.out.println(l);
        //java: 过大的整数: 14156534156144649999999999
         */
        BigInteger bigInteger = new BigInteger("14156534156144649999999999");
        BigInteger bigInteger2 = new BigInteger("100");
        System.out.println(bigInteger);//输出14156534156144649999999999

        //我们对 BigInteger 进行加减乘除的时候,需要使用相应的方法,不能直接进行 + - * /
        //可以创建一个 要操作的 BigInteger 来进行相应的操作
        BigInteger add = bigInteger.add(bigInteger2);//加
        System.out.println(add);//输出14156534156144650000000099
        BigInteger subtract = bigInteger.subtract(bigInteger2);//减
        System.out.println(subtract);//输出14156534156144649999999899
        BigInteger multiply = bigInteger.multiply(bigInteger2);//乘
        System.out.println(multiply);//输出1415653415614464999999999900
        BigInteger divide = bigInteger.divide(bigInteger2);//除
        System.out.println(divide);//输出141565341561446499999999
    }
  1. BigDecimal适合保存精度更高的浮点型(小数)
public static void main(String[] args) {
        //当我们需要保存一个精度很高的数时,double不够用
        //这时候我们可以使用 BigDecimal
        /*
        double d = 168.99999991111111999222299d;
        System.out.println(d);//输出169.0
         */
        BigDecimal bigDecimal = new BigDecimal("168.99999991111111999222299");
        System.out.println(bigDecimal);//输出168.99999991111111999222299

        //我们对 BigDecimal 进行加减乘除的时候,需要使用相应的方法,不能直接进行 + - * /
        //可以创建一个 要操作的 BigDecimal 来进行相应的操作
        BigDecimal bigDecimal2 = new BigDecimal("1.1");
        BigDecimal add = bigDecimal.add(bigDecimal2);//加
        System.out.println(add);//输出170.09999991111111999222299
        BigDecimal subtract = bigDecimal.subtract(bigDecimal2);//减
        System.out.println(subtract);//输出167.89999991111111999222299
        BigDecimal multiply = bigDecimal.multiply(bigDecimal2);//乘
        System.out.println(multiply);//输出185.899999902222231991445289
        //因为除法可能会除不尽,所以可能抛出异常 ArithmeticException
        //BigDecimal divide = bigDecimal.divide(bigDecimal2);//除
        //处理方法:在调用 divide 方法时,指定精度即可
        //bigDecimal2 后面加 BigDecimal.ROUND_CEILING
        //如果有无限循环小数,就会保留 分子 的精度
        BigDecimal divide = bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING);//除
        System.out.println(divide);//输出153.63636355555556362929363
    }

11. 日期类(知道怎么查,怎么用即可,不用每个方法都背)

11.1 第一代日期类

  1. Date:精确到毫秒,代表特定的瞬间

  2. SimpleDateFormat:格式和解析日期的类

  3. SimpleDateFormat:格式化和解析日期的具体类。他允许进行格式化(日期 -> 文本)、解析(文本 -> 日期)和规范化。

    • SimpleDateFormat转换日期的格式如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mrwq71Ex-1681671609154)(E:\Java study\Markdown\本地图片\SimpleDateFormat转换格式.png)]

  4. 应用实例

public static void main(String[] args) throws ParseException {
    	//第一代日期
    
        //第1种:
        // 1.获取当前的时间
        // 2.这里的 Date 类是在 java.util 包
        // 3.默认输出的日期格式是国外的方式,因此通常需要对格式进行转换
        Date d1 = new Date();
        System.out.println("当前的时间为 " + d1);

        //第2种:
        // 通过毫秒数获得一个时间
        Date d2 = new Date(999999999);
        System.out.println("d2的时间为 " + d2);

        //格式转换
        // 1.创建 SimpleDateFormat 对象,可以指定相应的格式
        // 2.这里的格式使用的字母是规定好的,不能乱写
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
        String format = sdf.format(d1);
        System.out.println("转换格式后的当前时间为 " + format);

        //第3种:
        // 1.可以把一个格式化的字符串 转成对应的Date
        // 2.得到的 Date 仍然按照国外的格式输出,
        // 3.如果希望指定格式输出,需要转换
        // 4.在把 String -> Date,使用的 sdf 格式需要和你所写的 Sting 的格式相同
        //   否则会抛出转换异常  ParseException
        String s = "2012年12月12日 12:12:12 星期三";
        Date parse = sdf.parse(s);
        System.out.println("parse= " + sdf.format(parse));
    }

11.2 第二代日期类

  1. 第二代日期类,主要就是 Calendar类(日历)
  2. Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段 (例如获得下星期的日期) 提供了一些方法。
  3. 应用实例
public static void main(String[] args) {
    	//第二代日期
    
        //Calendar 解读
        //1.Calendar是一个抽象类,并且构造器是protected
        //2.可以通过 getInstance() 来获取实例
        //3.提供大量的方法和字段提供给程序员

        //1.创建日历类对象
        //会出现一大堆字段
        Calendar calendar = Calendar.getInstance();
        System.out.println(calendar);

        //2.获取日历对象的某个日历字段
        System.out.println("年" + calendar.get(Calendar.YEAR));
        //因为 Calendar 返回月的时候,是按照 0 开始编号,所以这里要+1
        System.out.println("月" + (calendar.get(Calendar.MONTH) + 1));
        System.out.println("日" + calendar.get(Calendar.DAY_OF_MONTH));
        System.out.println("时" + calendar.get(Calendar.HOUR));
        System.out.println("分" + calendar.get(Calendar.MINUTE));
        System.out.println("秒" + calendar.get(Calendar.SECOND));

        //Calendar 没有专门的格式化方法,所以需要程序员自己来组合显示
        System.out.println(calendar.get(Calendar.YEAR) + "年" + (calendar.get(Calendar.MONTH) + 1) + "月" +
                calendar.get(Calendar.DAY_OF_MONTH) + "日" + calendar.get(Calendar.HOUR) + "时" +
                calendar.get(Calendar.MINUTE) + "分" + calendar.get(Calendar.SECOND) + "秒");
    }

11.3 第三代日期类

11.3.1前面两代日期类的不足分析

  1. JDK 1.0 包含了一个 java.util.Date 类,但是他的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而 Calendar 也存在以下问题:
    • 可变性:像日期和时间这样的类应该是不可变的
    • 偏移性:Date中的年份是从1900开始的,而月份都是从0开始
    • 格式化:格式化只对Date有用,Calendar不可以格式化
    • 此外,他们也不是线程安全的;不能处理闰秒等(每隔两天,多出1s)
  2. 第三类日期常见方法:JDK8时加入
    • ① LocalDate(日期):只包含日期,可以获取日期字段
    • ② LocalTime(时间):只包含时间,可以获取时间字段
    • ③ LocalDateTime(日期时间):包含日期+时间,可以获取日期和时间字段
    • 使用 DateTimeFormatter 对象来进行格式化
  3. 案例演示:
public static void main(String[] args) {
        //第三代日期

        //1.使用 now 返回当前日期时间的 对象
        LocalDateTime ldt = LocalDateTime.now();
        //LocalDate.now 只获取日期
        //LocalTime.now 只获取时间
        System.out.println(ldt);

        //2.使用 DateTimeFormatter 对象来进行格式化
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        String format = dtf.format(ldt);
        System.out.println("格式化的日期= "+format);
        /*
        //单独获得字段的方法
        ldt.getYear();
        ldt.getMonthValue();
        ldt.getDayOfMonth();
        ldt.getHour();
        ldt.getMinute();
        ldt.getSecond();
         */
        System.out.println("年= "+ldt.getYear());//年
        System.out.println("月="+ldt.getMonth());//月
        System.out.println("月= "+ldt.getMonthValue());//月
        System.out.println("日= "+ldt.getDayOfMonth());//日
        System.out.println("时= "+ldt.getHour());//时
        System.out.println("分= "+ldt.getMinute());//分
        System.out.println("秒= "+ldt.getSecond());//秒

    }
  1. Instant 时间戳:

    • 类似于 Date
    • 提供了一系列和Date类转换的方式
    public static void main(String[] args) {
            //1.通过静态方法 now() 获取当前时间戳的对象
            Instant now = Instant.now();
            System.out.println(now);
            //2.通过 form 可以把 Instant 转成 Date
            Date date = Date.from(now);
            //3.通过 date的 toInstant() 可以把 date 转成 Instant 对象
            Instant instant = date.toInstant();
        }
    
  2. 第三代日期类有很多的方法

    • LocalDateTime类
    • MonthDay类:检查重复时间
    • 检查是否是润年
    • 增加日期的某个部分
    • 使用plus方法测试增加时间的某个部分
    • 使用minus方法测试查看一年前和一年后的日期
    //提供了 plus 和 minus 方法可以对当前的时间进行 加 或者 减
            //看678天后是什么时间 把 年月日-时分秒 输出
            LocalDateTime ldt2 = ldt.plusDays(678);
            System.out.println("678天后的时间= " + dtf.format(ldt2));
            //看789分钟前是什么时间
            LocalDateTime ldt3 = ldt.minusMinutes(789);
            System.out.println("789分钟前的时间= " + dtf.format(ldt3));
    
    • 还有很多其他的方法,使用的时候自己查看API使用

12. 本章练习

练习一:

  1. 将字符串中指定的部分进行反转。比如将"abcdef" 反转为 “aedcbf”*
  2. 编写方法 public static String reverse(String str,int start,int end) 搞定
  3. 编码如下:
public class Homework01 {
    public static void main(String[] args) {
        String str = "abcdef";
        System.out.println("最初的str =" + str);//最初的str =abcdef
        try {
            str = reverse(str, 1, 4);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return;//如果上面参数不正确,直接不进行下面的步骤
        }
        System.out.println("反转的str =" + str);//反转的str =aedcbf
    }

    /**
     * 要求
     * (1) 将字符串中指定的部分进行反转。比如将"abcdef" 反转为 "aedcbf"
     * (2) 编写方法 public static String reverse(String str,int start,int end) 搞定
     * 解题思路
     * (1) 先确定好方法
     * (2) 把 String 转成 char[] ,因为 char[] 的元素是可以交换的
     * (3) 防止输出的时候超出实际范围,对输入的参数做一个验证
     * (4) 对于参数的验证分享一个重要的编程技巧
     * (1) 写出正确的情况
     * (2) 然后进行取反就行
     */
    public static String reverse(String str, int start, int end) {
        //对输入的参数做一个验证
        //重要的编程技巧分享
        //(1) 写出正确的情况
        //(2) 然后进行取反就行
        if (!(str != null && start >= 0 && end > start && end < str.length())) {
            throw new RuntimeException("参数不正确");
        }
        char[] chars = str.toCharArray();
        char temp = ' ';
        for (int i = start, j = end; i < j; i++, j--) {
            temp = chars[i];
            chars[i] = chars[j];
            chars[j] = temp;
        }
        //使用 chars 重新构建一个 String 即可
        return new String(chars);
    }
}

练习二:

  1. 输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象;
  2. 要求:
    • (1) 用户名长度为2、3或4
    • (2) 密码长度为6,要求全是数字
    • (3) 邮箱中包含 @ 和 . 并且 @ 在 . 的前面 isDigital
  3. 编码如下:
public class Homework02a {
    public static void main(String[] args) {
        String name = "sun";
        String pwd = "123456";
        String email = "1241955497@qq.com";
        
        try {
            userRegister(name, pwd, email);
            System.out.println("恭喜你,注册成功");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    /**
     * 1. 输入用户名、密码、邮箱,如果信息录入正确,则提示注册成功,否则生成异常对象;
     * 2. 要求:
     * - (1) 用户名长度为2、3或4
     * - (2) 密码长度为6,要求全是数字 isDigital
     * - (3) 邮箱中包含 @ 和 . 并且 @ 在 . 的前面
     */
    //1.先编写一个方法 userRegister
    //2.针对输入的内容进行校验,如果发现问题,就抛出异常,给出提示
    //3.单独写一个方法,判断密码是否全部是数字 boolean
    public static void userRegister(String name, String pwd, String email) {
        //再加入一些校验
        if (!(name != null && pwd != null && email != null)) {
            throw new RuntimeException("参数不能为空");
        }
        //1.对用户名进行核验
        //  用户名长度为2、3或4
        int userLength = name.length();
        if (!(userLength >= 2 && userLength <= 4)) {
            throw new RuntimeException("用户名长度为2、3或4");
        }

        //2.对密码进行校验
        //  密码长度为6,要求全是数字 isDigital
        if (!(pwd.length() == 6 && isDigital(pwd))) {
            throw new RuntimeException("密码长度为6,要求全是数字 isDigital");
        }

        //3.对邮箱进行校验
        //  邮箱中包含 @ 和 . 并且 @ 在 . 的前面
        int i = email.indexOf("@");
        int j = email.indexOf(".");
        if (!(i > 0 && i > j)) {
            throw new RuntimeException("邮箱中包含 @ 和 . 并且 @ 在 . 的前面");
        }

    }

    //单独写一个方法,判断密码是否全部是数字 boolean
    public static boolean isDigital(String str) {
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] < '0' || chars[i] > '9') {
                return false;
            }
        }
        return true;
    }
}

练习三:

  1. 编写一个java程序,输入形式为:Sun Yu Song 的人名,以 Song,Sun .Y 的形式打印出来;
    • 其中 .Y是中间单词的首字母
    • 例如输入 Jack Lucy John,输出形式为 John,Jack.L
  2. 编码如下:
public class Homework03 {
    public static void main(String[] args) {
        String name = "Sun Yu Song";
        printName(name);//Song,Sun,S

    }
    /*
    编写一个java程序,输入形式为:Sun Yu Song 的人名,以 Song,Sun .Y 的形式打印出来;
    - 其中 .Y是中间单词的首字母
    - 例如输入 Jack Lucy John,输出形式为 John,Jack.L
     */
    //思路分析
    //1.对输入的字符串进行分割,split
    //2.对得到的String[] 进行格式化String.format
    //3.对输入的字符串进行校验即可

    public static void printName(String str) {
        if (str == null) {
            System.out.println("str 不能为空");
            return;
        }
        //把输入的名字进行分割
        String[] names = str.split(" ");
        if (names.length != 3) {
            System.out.println("输入的字符串格式不对");
        }

        //格式化字符串,%s 字符串, %c 字符, %d 整型, %.2f 浮点型,
        String format = String.format("%s,%s,%s", names[2], names[0], names[0].toUpperCase().charAt(0));
        System.out.println(format);
    }
}

联系四:

  1. 输入字符串,判断里面有多少个大写字母,有多少个小写字母,多少个数字
  2. 编码如下:
public class Homework04 {
    public static void main(String[] args) {
        String str = "shaNJNdasji 1266d";//随便写一串字符
        count(str);//调用count方法输出
        //数字有4个
        //小写字母有9个
        //大写字母有3个
        //其他字符有1个
    }

    //输入字符串,判断里面有多少个大写字母,有多少个小写字母,多少个数字
    //思路分析
    // 1.遍历字符串,如果char在 '0~9' ,就是一个数字
    // 2.如果char在 'a~z' ,就是小写字母
    // 3.如果char在 'A~Z' ,就是小写字母
    // 4.使用三个变量来记录,统计结果
    public static void count(String str) {
        if (str == null) {
            System.out.println("输入不能为空");
        }

        int strLen = str.length();
        int numCount = 0;
        int lowerCount = 0;
        int upperCount = 0;
        int otherCount = 0;
        for (int i = 0; i < strLen; i++) {
            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                numCount++;
            } else if (str.charAt(i) >= 'a' && str.charAt(i) <= 'z') {
                lowerCount++;
            } else if (str.charAt(i) >= 'A' && str.charAt(i) <= 'Z') {
                upperCount++;
            } else {
                otherCount++;
            }

        }
        System.out.println("数字有" + numCount + "个");
        System.out.println("小写字母有" + lowerCount + "个");
        System.out.println("大写字母有" + upperCount + "个");
        System.out.println("其他字符有" + otherCount + "个");
    }
}
世界地图矢量数据可以通过多种网站进行下载。以下是一些提供免费下载世界地图矢量数据的网站: 1. Open Street Map (https://www.openstreetmap.org/): 这个网站可以根据输入的经纬度或手动选定范围来导出目标区域的矢量图。导出的数据格式为osm格式,但只支持矩形范围的地图下载。 2. Geofabrik (http://download.geofabrik.de/): Geofabrik提供按洲际和国家快速下载全国范围的地图数据数据格式支持shape文件格式,包含多个独立图层,如道路、建筑、水域、交通、土地利用分类、自然景观等。数据每天更新一次。 3. bbbike (https://download.bbbike.org/osm/): bbbike提供全球主要的200多个城市的地图数据下载,也可以按照bbox进行下载。该网站还提供全球数据数据格式种类齐全,包括geojson、shp等。 4. GADM (https://gadm.org/index.html): GADM提供按国家或全球下载地图数据的服务。该网站提供多种格式的数据下载。 5. L7 AntV (https://l7.antv.antgroup.com/custom/tools/worldmap): L7 AntV是一个提供标准世界地图矢量数据免费下载的网站。支持多种数据格式下载,包括GeoJSON、KML、JSON、TopJSON、CSV和高清SVG格式等。可以下载中国省、市、县的矢量边界和世界各个国家的矢量边界数据。 以上这些网站都提供了世界地图矢量数据免费下载服务,你可以根据自己的需求选择合适的网站进行下载
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dominator945

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值