• Java进阶笔记(面向对象后, 持续更新)


    常用API

    游戏打包成exe

    考虑的因素

    1. 要有图形化界面
    2. 代码要打包起来
    3. 游戏用到的图片也要打包
    4. JDK也要打包

    核心步骤

    1. 把所有代码打包成一个压缩包, jar后缀的压缩包
    2. 把jar包转换成exe安装包
    3. 把第二部的exe, 图片, JDK整合在一起, 变成最终的exe安装包

    1. Math

    • 是一个帮助我们用于进行数学计算的工具类
    • 私有化构造方法, 所有方法都是静态的
    常用方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    看一下Math源码:

    public final class Math {
    
        /**
         * Don't let anyone instantiate this class.
         */
        private Math() {}
    
        /**
         * The {@code double} value that is closer than any other to
         * e, the base of the natural logarithms.
         */
        public static final double E = 2.718281828459045;
    
        /**
         * The {@code double} value that is closer than any other to
         * pi (π), the ratio of the circumference of a circle to
         * its diameter.
         */
        public static final double PI = 3.141592653589793;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    扩展:

    Math.sqrt() 开平方

    Math.cbrt() 开立方

    2. System

    工具类, 提供了一些与系统相关的方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    计算机中的时间原点: 19070-1-1 00:00:00 (C语言的生日)

    1秒 = 1 000毫秒 = 1 000 000微秒 = 1 000 000 000 纳秒

    代码演示:

    package APIDemo1;
    
    public class SystemDemo {
        public static void main(String[] args) {
            // 0-当前虚拟机正常停止
            // 非0- 异常停止
            //System.exit(0);
    
    //        long l = System.currentTimeMillis();
    //        System.out.println(l);
            //test01();
            test02();
        }
    
        public static void test01(){
            // 判断1-10000之间有多少质数
            int count = 0;
            long time1 = System.currentTimeMillis();
            for (int i = 1; i <= 100000; i++) {
                if(isPrime1(i)) ++count;
            }
            long time2 = System.currentTimeMillis();
            System.out.println(count);
            long time3 = time2 - time1;
            System.out.println("算法1花费: " + time3);
    
            System.out.println("--------------------------------");
    
            count = 0;
    
            long time4 = System.currentTimeMillis();
            for (int i = 1; i <= 100000; i++) {
                if(isPrime2(i)) ++count;
            }
            long time5 = System.currentTimeMillis();
            System.out.println(count);
            long time6 = time5 - time4;
            System.out.println("算法2花费: " + time6);
        }
    
        public static boolean isPrime1(int number){
            for(int i = 2; i < number; ++i){
                if(number % i == 0){
                    return false;
                }
            }
            return true;
        }
    
        public static boolean isPrime2(int number){
            for(int i = 2; i <= Math.sqrt(number); ++i){
                if(number % i == 0){
                    return false;
                }
            }
            return true;
        }
    
        public static void test02(){
            int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
            int[] arr2 = new int[10];
            // 把arr1拷贝到arr2中
            // 参数一: 数据源
            // 参数二: 拷贝起始索引
            // 参数三: 目标数组
            // 参数四: 目的地数组的索引
            // 参数五: 拷贝的个数
    
            // 现在想要 0 0 7 8 9 0 0 0 0 0
            System.arraycopy(arr1, 6, arr2, 2, 3);
            for (int i = 0; i < arr2.length; i++) {
                System.out.print(arr2[i] + " ");
            }
            System.out.println();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    扩展

    1. 如果数据源数组和目的地数组都是基本数据类型, 那么两者的类型必须保持一致
      比如arr1是int数组, arr2是double数组的话就不能拷贝
    2. 拷贝的时候要考虑数组长度, 超出范围也会报错
    3. 如果数据源数组和目的地数组都是引用数据类型
      那么子类数据类型可以赋值给父类类型 arr1里面的类型是子类, arr2是父类 就可以

    3. Runtime

    Runtime表示当前虚拟机的运行环境

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package APIDemo1;
    
    import java.io.IOException;
    
    public class RuntimeDemo {
        public static void main(String[] args) throws IOException {
            // 1. 获取Runtime对象
            // 这个类只能获取一个对象, 所以多次调用得到的对象也是一致的
            Runtime r1 = Runtime.getRuntime();
            Runtime r2 = Runtime.getRuntime();
    
            //System.out.println(r1 == r2); // true
    
            // 2. exit
            //Runtime.getRuntime().exit(0); // System.exit(0) 就是这么调用的
            //System.out.println("看看我执行了吗");
    
            // 3. CPU线程数
            System.out.println(r1.availableProcessors()); // 12
    
            // 4. 总内存大小 byte
            System.out.println(r1.maxMemory() / 1024 / 1024); // 单位是M
    
            // 5. 已经获取的总内存大小
            System.out.println(r1.totalMemory() / 1024 / 1024);
    
            // 6. 剩余内存大小
            System.out.println(r1.freeMemory() / 1024 / 1024);
    
            // 7. 运行cmd命令
            Runtime.getRuntime().exec("notepad"); // 运行记事本
            // shutdown: 关机
            // 加上参数才能执行
            // -s : 默认在1分钟后关机
            // -s -t 指定时间: t单位是秒
            // -a: 取消关机操作
            // -r: 关机并重启
            Runtime.getRuntime().exec("shutdown -a");
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    4. Object 和 Objects

    object

    • Object是Java的顶级父类. 所有的累都直接或间接继承于Object类
    • Object类中的方法可以被所有子类访问, 所以我们要学习Object类和其中的方法
    构造方法

    只有空参构造

    成员方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    toString
    package ObjectDemo1;
    
    public class ObjectDemo1 {
        public static void main(String[] args) {
            Object obj = new Object();
            String str = obj.toString();
    
            System.out.println(str); //java.lang.Object@b4c966a
            // System是类名
            // out: 静态变量
            // System.out: 获取打印的对象
            // println(): 方法
            // 参数: 表示打印的内容
            // 核心逻辑:
            // 当打印一个对象的时候, 看底层会调用对象的toString方法
            // 把对象变成字符串
            // 然后再打印在控制台, 打印完毕换行处理
            System.out.println(obj); //java.lang.Object@b4c966a
    
            Student s = new Student("ljq", 24);
            System.out.println(s);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    默认情况下, 打印一个对象打印的就是地址值, 如果想打印对象里面的属性, 可以重写toString方法( ptg to JavaBean )

    在重写的方法中, 把要返回的字符串拼接好返回即可

    equals

    比较两个对象是否相等

    返回布尔类型

    默认比较地址值, 所以两个空的新建的对象是不相等的

    解决方法: 重写父类的equals方法

    重写toString 和 equals方法
    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true; // 比较地址值是否相等, 相等的话直接返回true
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        // 比较每个成员属性
        return age == student.age && Objects.equals(name, student.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    小练习
    package ObjectDemo1;
    
    public class ObjectDemo2 {
        public static void main(String[] args) {
            String s = "abc";
            StringBuilder sb = new StringBuilder("abc");
    
            System.out.println(s.equals(sb)); // false
            System.out.println(sb.equals(s)); // false
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    解释:

    1. System.out.println(s.equals(sb)); // false

    因为equals方法是s调用的, s是字符串, 所以equals要看String类中的方法

    源码如下:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        return (anObject instanceof String aString)
                && (!COMPACT_STRINGS || this.coder == aString.coder)
                && StringLatin1.equals(value, aString.value);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该方法会先判断参数是否为字符串, 如果是字符串, 在比较内部的属性, 如果不是, 直接返回false

    该题sb是StringBuilder对象, 不是String对象, 所以返回false.

    1. System.out.println(sb.equals(s)); // false

    这里的equals方法是sb调用的, 所以要看StringBuilder方法里的equals方法.

    但是StringBuilder里没有该方法, 所以用的是Object父类的equals方法, 即直接比较两个对象的地址值, 直接返回false.

    clone

    对象克隆

    把A对象里面的属性值完全拷贝给B对象, 也叫对象拷贝, 对象赋值

    代码:

    User的JavaBean

    package ObjectDemo1;
    
    import java.util.StringJoiner;
    
    public class User implements Cloneable{
        private String name;
        private int age;
        private int[] data;
    
        public User() {
        }
    
        public User(String name, int age, int[] data) {
            this.name = name;
            this.age = age;
            this.data = data;
        }
    
        /**
         * 获取
         * @return name
         */
        public String getName() {
            return name;
        }
    
        /**
         * 设置
         * @param name
         */
        public void setName(String name) {
            this.name = name;
        }
    
        /**
         * 获取
         * @return age
         */
        public int getAge() {
            return age;
        }
    
        /**
         * 设置
         * @param age
         */
        public void setAge(int age) {
            this.age = age;
        }
    
        /**
         * 获取
         * @return data
         */
        public int[] getData() {
            return data;
        }
    
        /**
         * 设置
         * @param data
         */
        public void setData(int[] data) {
            this.data = data;
        }
    
        public String toString() {
            return "User{name = " + name + ", age = " + age + ", data = " + arrToString(data) + "}";
        }
    
        private String arrToString(int[] data){
            StringJoiner sj = new StringJoiner(",", "[", "]");
            for (int i = 0; i < data.length; i++) {
                sj.add(data[i] + "");
            }
            return sj.toString();
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            // 调用父类中的clone方法
            return super.clone();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    Test代码

    package ObjectDemo1;
    
    public class TestUser {
        public static void main(String[] args) throws CloneNotSupportedException {
            int[] data = {1,2,3,4,5};
    
            User u1 = new User("ljq", 12, data);
            User u2 = (User) u1.clone();
    
            System.out.println(u1);
            System.out.println(u2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    细节:

    方法在底层会给我们创建一个对象, 并把原对象中的数据拷贝过去

    User类需要实现一个没有抽象方法的接口

    解释:

    如果一个接口里面没有抽象方法, 表示当前的接口是一个标记性接口

    现在Cloneable表示一旦实现了, 那么当前类就可以被克隆

    如果没有实现, 当前类的对象就不能克隆

    书写细节:

    1. 重写Object中的clone方法
    2. 让Javabean类实现cloneable接口
    3. 创建原对象并调用clone就可以了

    两种克隆方式

    浅克隆, 浅拷贝

    不管对象内部的属性是基本数据类型还是引用数据类型, 都完全拷贝过来

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    深克隆, 深拷贝

    基本数据类型拷贝过来

    字符串复用串池里的数据

    引用数据类型会创建新的

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    Object里的clone方法是浅克隆

    验证:

    int[] arr = u1.getData();
    arr[0] = 100;
    
    System.out.println(u1);
    System.out.println(u2);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    两个对象里的data数据都改变了.

    怎么实现深克隆?

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 调用父类中的clone方法
        // 相当于让Java帮我们克隆一个对象, 并把克隆之后的对象返回出去
    
        // 先把被克隆对象中的数组获取出来
        int[] data = this.data;
        // 创建新的数组
        int[] newData = new int[data.length];
        // 拷贝数组中的数据
        for (int i = 0; i < data.length; i++) {
            newData[i] = data[i];
        }
        // 调用父类中的方法克隆
        User u = (User)super.clone();
        // 因为父类中的克隆方法是浅克隆, 替换克隆出来对象中的数组地址值
        u.data = newData;
    
        return u;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    扩展:

    第三方工具类 自带深克隆方法

    Gson

    Objects

    工具类

    Object的equals方法, 需要先判断对象是否为null, 因为空对象无法调用成员函数

    构造方法

    Objects 类的构造方法是私有的,因此无法直接通过实例化对象的方式来调用构造方法。

    成员方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    成员方法代码演示
    package Objects;
    
    import java.util.Objects;
    
    public class ObjectsDemo1 {
        public static void main(String[] args) {
            Student s1 = new Student("zhangsan", 23);
            Student s2 = null;
            //System.out.println(s1.equals(s2));
    
            // s2.equals(s1); // 会报错
    
            boolean res1 = Objects.equals(s1, s2);
            System.out.println(res1); // false
    
            System.out.println(Objects.isNull(s1)); // false
            System.out.println(Objects.isNull(s2)); // true
    
            System.out.println(Objects.nonNull(s1)); // true
            System.out.println(Objects.nonNull(s2)); // false
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    equals方法细节:

    1. 方法的底层会判断s2是否为null, 如果是null, 直接返回false
    2. 如果s2不是null, 那么就利用s2再次调用equals方法
    3. 此时s2是student类型, 所以最终还是会调用Student中的equals方法

    如果equals方法没有被重写的话, 就比较地址值, 重写了就比较属性值.

    5. BigInteger 和 BigDecimal

    BigInteger

    java中整数的四种类型及所占用的字节数

    byte 1 , short 2 , int 4 , long 8

    构造方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    对象一旦创建, 内部的值就不能发生改变(只要进行计算, 就会产生一个新的BigInteger对象)

    package BigInteger;
    
    import java.math.BigInteger;
    import java.util.Random;
    
    public class BigIntegerDemo {
        public static void main(String[] args) {
            // 获取一个随机的大整数
            BigInteger bd1 = new BigInteger(4, new Random());
            System.out.println(bd1);
    
            // 获取指定的大整数
            // 字符串里面必须是整数, 不能有小数或字母
            BigInteger bd2 = new BigInteger("99999999999999999999999999");
            System.out.println(bd2);
    
            // 获取指定进制的大整数
            // 字符串的数字必须为整数
            // 且必须与进制吻合
            BigInteger bd3 = new BigInteger("1001", 2);
            System.out.println(bd3);
    
            // 静态方法获取大整数
            BigInteger bd4 = BigInteger.valueOf(16);
            BigInteger bd5 = BigInteger.valueOf(16);
            System.out.println(bd4 == bd5); // true
    
            // 获取最大Long类型的值
            System.out.println(Long.MAX_VALUE);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    常用的方法是2 和 4

    方法4 与 2相比:

    1. 能表示的范围在long之内, 比方法2小
    2. 在内部常用的数字: -16 ~ +16 进行了优化
    3. 提前把这个范围内的数字创建好BigInteger的对象, 如果多次获取不会创建新的对象
    成员方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    代码:

    package BigInteger;
    
    import java.math.BigInteger;
    
    public class BigIntegerDemo2 {
        public static void main(String[] args) {
            // 1.创建两个对象
            BigInteger bd1 = BigInteger.valueOf(10);
            BigInteger bd2 = BigInteger.valueOf(2);
    
            // 2.加法
            BigInteger bd3 = bd1.add(bd2);
            System.out.println(bd3);
    
            // 3.除法 获取商和余数
            BigInteger[] arr1 = bd1.divideAndRemainder(bd2);
            System.out.println(arr1.length); // 2
            System.out.println(arr1[0]); // 5
            System.out.println(arr1[1]); // 0
    
    
            // 4.比较是否相同
            // 结果
            // true 当且仅当指定的Object是BigInteger时,
            // 其值在数字上等于此BigInteger
            System.out.println(bd1.equals(bd2));
    
            // 5.次幂
            BigInteger bd4 = bd1.pow(2);
            System.out.println(bd4);
    
            // 6.max
            BigInteger bd5 = bd1.max(bd2);
            System.out.println(bd5.equals(bd1)); // true
            System.out.println(bd5.equals(bd2)); // false
    
            // 7.转换为int类型整数
            // 超出范围会出现错误
            BigInteger bd6 = BigInteger.valueOf(1000);
            int i = bd6.intValue();
            System.out.println(i);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    底层存储方式
    1. 对于计算机而言, 是没有数据类型的概念的, 都是010101
    2. 数据类型是编程语言自己规定的

    源码:

    public class BigInteger extends Number implements Comparable<BigInteger> {
        /**
         * The signum of this BigInteger: -1 for negative, 0 for zero, or
         * 1 for positive.  Note that the BigInteger zero must have
         * a signum of 0.  This is necessary to ensures that there is exactly one
         * representation for each BigInteger value.
         */
        final int signum;
    
        /**
         * The magnitude of this BigInteger, in big-endian order: the
         * zeroth element of this array is the most-significant int of the
         * magnitude.  The magnitude must be "minimal" in that the most-significant
         * int ({@code mag[0]}) must be non-zero.  This is necessary to
         * ensure that there is exactly one representation for each BigInteger
         * value.  Note that this implies that the BigInteger zero has a
         * zero-length mag array.
         */
        final int[] mag;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    signum表示正负

    mag是一个多段的数组

    先变成补码, 然后以32位为一组, 分成n组, 再转成10进制放到数组mag中

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    存储上限:

    存储方式为: [1, -2147483648, 0]

    数组中最大长度是int的最大值: 2147483647

    数组中每一位能表示的数字: -2147483648 ~ 2147483647

    也就是说数组中最多21亿个元素, 每个元素能表示的数字位42亿多

    所以BigInteger能表示的最大数字为: 42亿的21亿次方

    实际计算机不可能有这么大内存

    BigDecimal

    计算机中的小数

    0.875 转为二进制 111

    0.9 - 45位二进制

    底层:

    类型占用字节数总bit位数小数部分bit位数
    float4个字节32bit23bit
    double8个字节64bit52bit

    所以有些小数在计算的时候会很不精确

    BigDecima
    构造
    1. 通过传递double类型的小数来创建对象, 这种方式有可能不精确, 不建议使用
    2. 通过传递字符串表示的小数来创建对象, 就会很精确
    3. 通过静态方法获取对象valueof

    推荐使用方法2和方法3

    package BigDecimalDemo;
    
    import java.math.BigDecimal;
    
    public class BigDecimalTest {
        public static void main(String[] args) {
            // 构造方法
            BigDecimal bd1 = new BigDecimal(0.01);
            BigDecimal bd2 = new BigDecimal(0.09);
            System.out.println(bd1);
            System.out.println(bd2);
            // 都不精确
    
            // 字符串传递
            BigDecimal bd3 = new BigDecimal("0.01");
            BigDecimal bd4 = new BigDecimal("0.09");
            System.out.println(bd3);
            System.out.println(bd4); // 精确
            BigDecimal bd5 = bd3.add(bd4);
            System.out.println(bd5); // 精确
    
            // 静态方法构造
            BigDecimal bd6 = BigDecimal.valueOf(0.1);
            System.out.println(bd6); //精确
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    细节:

    1. 如果要表示的数字不大, 没有超出double的取值范围, 建议使用静态方法
    2. 如果要表示的书自己表达, 超出了double的取值范围,建议使用构造方法
    3. 如果传递的是0-10之间的整数, 包含0 包含10, 那么方法会返回已经创建好的对象, 不会重新new

    验证代码:

    BigDecimal bd6 = BigDecimal.valueOf(10);
    BigDecimal bd7 = BigDecimal.valueOf(10);
    System.out.println(bd6 == bd7); // true
    
    BigDecimal bd8 = BigDecimal.valueOf(10.0);
    BigDecimal bd9 = BigDecimal.valueOf(10.0);
    System.out.println(bd8 == bd9); // false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    解释: 只有当传递1-10之间的整数时, 是同一个对象, 但如果是小数, 都是new出来的

    成员方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package BigDecimalDemo;
    
    import java.math.BigDecimal;
    import java.math.RoundingMode;
    
    public class BigDecimalTest2 {
        public static void main(String[] args) {
            // 创建对象
            BigDecimal bd1 = BigDecimal.valueOf(10.0);
            BigDecimal bd2 = BigDecimal.valueOf(2.0);
            // 加法
            BigDecimal bd3 = bd1.add(bd2);
            System.out.println(bd3);
            // 减法
            BigDecimal bd4 = bd1.subtract(bd2);
            System.out.println(bd4);
            // 乘法
            BigDecimal bd5 = bd1.multiply(bd2);
            System.out.println(bd5);
            // 除法
            BigDecimal bd6 = bd1.divide(bd2);
            System.out.println(bd6);
            // 以上结果为: 12.0 8.0 20.00 5
    
            // 除法精确几位小数
            BigDecimal bd7 = bd1.divide(bd2, 5, RoundingMode.HALF_UP);
            // half_Up就是四舍五入
            System.out.println(bd7); //5.00000
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    舍入模式:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    UP: 远离0的方向舍入

    DOWN: 向0的方向舍入

    HALF_EVEN:

    例子:with HALF_EVEN rounding 5.5 6, 2.5 2, 1.6 2, 1.1 1, 1.0 1, -1.0 -1, -1.1 -1, -1.6 -2, -2.5 -2, -5.5 -6,

    BigDecimal底层存储模式

    首先不管是静态方法还是字符串传入, 都是new出来的

    首先会对字符串进行遍历, 然后把每个字符对应的ASCII码存入到数组中

    debug调试:

    package BigDecimalDemo;
    
    import java.math.BigDecimal;
    
    public class BigDecimalTest3 {
        public static void main(String[] args) {
            BigDecimal bd1 = BigDecimal.valueOf(0.226);
            BigDecimal bd2 = BigDecimal.valueOf(123.226);
            BigDecimal bd3 = BigDecimal.valueOf(-1.5);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    上限: 小数总长度不超过数组长度也就是INT_MAX

    小结:

    1. BigDecimal作用: 表示较大的小数和纪珏小数精度失真问题
    2. BigDecimal的对象如何获取? 传入字符串, 静态方法valueof
    3. 常见操作: 加减乘除 (四舍五入: RoundingMode.HALF_UP)

    6.正则表达式

    一种校验字符串的规则

    校验用户名, 密码等是否满足规则可以用到

    作用:
    1. 校验字符串是否满足规则
    2. 在一段文本中查找满足要求的内容

    使用规则

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    细节: 如果要求两个范围的交集, 写两个&&才行, 写成一个的话就会当成是判断是否是&符号

    转义字符: \ 改变后面那个字符原本的含义

    代码示例:

    // 只能是a b c
    System.out.println(“-----------1-------------”);
    System.out.println(“a”.matches(“[abc]”)); // true
    System.out.println(“z”.matches(“[abc]”)); // false

        // 不能出现a b c
        System.out.println("-----------2-------------");
        System.out.println("a".matches("[^abc]")); // false
        System.out.println("z".matches("[^abc]")); // true
        System.out.println("zz".matches("[^abc]")); //false
        System.out.println("zz".matches("[^abc][^abc]")); //true
    
        // a到zA到Z(包括头尾的范围)
        System.out.println("-----------3-------------");
        System.out.println("a".matches("[a-zA-z]")); // true
        System.out.println("z".matches("[a-zA-z]")); // true
        System.out.println("aa".matches("[a-zA-z]"));//false
        System.out.println("zz".matches("[a-zA-Z]")); //false
        System.out.println("zz".matches("[a-zA-Z][a-zA-Z]")); //true
        System.out.println("0".matches("[a-zA-Z]"));//false
        System.out.println("0".matches("[a-zA-Z0-9]"));//true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
        // [a-d[m-p]] a到d,或m到p
        System.out.println("-----------4-------------");
        System.out.println("a".matches("[a-d[m-p]]"));//true
        System.out.println("d".matches("[a-d[m-p]]")); //true
        System.out.println("m".matches("[a-d[m-p]]")); //true
        System.out.println("p".matches("[a-d[m-p]]")); //true
        System.out.println("e".matches("[a-d[m-p]]")); //false
        System.out.println("0".matches("[a-d[m-p]]")); //false
    
        // [a-z&&[def]] a-z和def的交集。为:d,e,f
        System.out.println("----------5------------");
        System.out.println("a".matches("[a-z&[def]]")); //false
        System.out.println("d".matches("[a-z&&[def]]")); //true
        System.out.println("0".matches("[a-z&&[def]]")); //false
    
        // [a-z&&[^bc]] a-z和非bc的交集。(等同于[ad-z])
        System.out.println("-----------6------------_");
        System.out.println("a".matches("[a-z&&[^bc]]"));//true
        System.out.println("b".matches("[a-z&&[^bc]]")); //false
        System.out.println("0".matches("[a-z&&[^bc]]")); //false
    
        // [a-z&&[^m-p]] a到z和除了m到p的交集。(等同于[a-1q-z])
        System.out.println("-----------7-------------");
        System.out.println("a".matches("[a-z&&[^m-p]]")); //true
        System.out.println("m".matches("[a-z&&[^m-p]]")); //false
        System.out.println("0".matches("[a-z&&[^m-p]]")); //false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    // \ 转义字符 改变后面那个字符原本的含义
    //练习:以字符串的形式打印一个双引号
    //"在Java中表示字符串的开头或者结尾

        //此时\表示转义字符,改变了后面那个双引号原本的含义
        //把他变成了一个普普通通的双引号而已。
        System.out.println("\"");
    
        // \表示转义字符
        //两个\的理解方式:前面的\是一个转义字符,改变了后面\原本的含义,把他变成一个普普通通的\而已。
        System.out.println("c:Users\\moon\\IdeaProjects\\basic-code\\myapi\\src\\com\\itheima\\a08regexdemo\\RegexDemo1.java");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
        //.表示任意一个字符
        System.out.println("你".matches("..")); //false
        System.out.println("你".matches(".")); //true
        System.out.println("你a".matches(".."));//true
    
        // \\d 表示任意的一个数字
        // \\d只能是任意的一位数字
        // 简单来记:两个\表示一个\
        System.out.println("a".matches("\\d")); // false
        System.out.println("3".matches("\\d")); // true
        System.out.println("333".matches("\\d")); // false
    
        //\\w只能是一位单词字符[a-zA-Z_0-9]
        System.out.println("z".matches("\\w")); // true
        System.out.println("2".matches("\\w")); // true
        System.out.println("21".matches("\\w")); // false
        System.out.println("你".matches("\\w"));//false
    
        // 非单词字符
        System.out.println("你".matches("\\W")); // true
        System.out.println("---------------------------------------------");
        // 以上正则匹配只能校验单个字符。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    代码示例:

        // 必须是数字 字母 下划线 至少 6位
        System.out.println("2442fsfsf".matches("\\w{6,}"));//true
        System.out.println("244f".matches("\\w{6,}"));//false
    
        // 必须是数字和字符 必须是4位
        System.out.println("23dF".matches("[a-zA-Z0-9]{4}"));//true
        System.out.println("23 F".matches("[a-zA-Z0-9]{4}"));//false
        System.out.println("23dF".matches("[\\w&&[^_]]{4}"));//true
        System.out.println("23_F".matches("[\\w&&[^_]]{4}"));//false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    练习

    验证手机号:

    分成三部分:

    1. 1 表示手机号码只能以1开头
    2. [3-9] 表示第二位数字必须是3-9之间的
    3. \\d{9} 表示任意数字可以出现9次, 也只能出现9次
    package RegexDemo;
    
    public class RegexDemo2 {
        public static void main(String[] args) {
            // 验证手机号码
            String regex1 = "1[3-9]\\d{9}";
            System.out.println("13112345678".matches(regex1));
            System.out.println("131123_5678".matches(regex1));
            System.out.println("1311a345678".matches(regex1));
            System.out.println("131152345678".matches(regex1));
            System.out.println("03112345678".matches(regex1));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    座机号码三部分
    1. 区号 0\\d{2,3}
    2. -? 表示0次或1次
    3. 号码的第一位也不能以0开头, 总长度5-10
    验证邮箱
    //         验证邮箱
    //         1. @ 左边 任意字母数字下划线至少一次
    //         2. @有且仅有一次
    //         3. @ 右边
    //         3.1  . 的左边  任意字母加数字2-6次, 且不能有下划线
    //         3.2  \\.
    //         3.3 大写小写字母都可 2-3次
    //         3.4 3.3部分可以出现1-2次
    
            String regex3 = "\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2}";
            System.out.println("474328774@qq.com".matches(regex3));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    扩展:

    平时几乎不用自己写, 下载插件any-rule, 在双引号中间右键, 然后点击any-rule可以查到很多模板

    我们需要先看懂, 再根据自己的要求进行修改

    验证身份证
    package RegexDemo;
    
    public class RegexDemo3 {
        public static void main(String[] args) {
    //        请编写正则表达式验证用户名是否满足要求。
    //        要求:大小写字母,数字,下划线一共4-16位
            String regex1 = "\\w{4,16}";
    
    //        请编写正则表达式验证身份证号码是否满足要求。
    //        简单要求:18位,前17位任意数字,最后一位可以是数字可以是大写或小写的X
    //        复杂要求:按照身份证号码的格式严格要求
            String regex2 = "[0-9]{17}(0-9|X|x)";
            String regex3 = "[0-9]{17}[\\dXx]";
            String regex7 = "[0-9]{17}(\\d|(?i)x";
            // regex2 和regex3 和 regex7等价
    
            System.out.println("76104310000564371x".matches(regex2));
    
            // 忽略大小写的书写方式
            // 在匹配的时候忽略abc的大小写
            String regex4 = "(?i)abc";
            // 之忽略bc的大小写
            String regex5 = "a(?i)bc";
    //      只忽略b的大小写
            String regex6 = "a((?i)b)c";
            System.out.println("abc".matches(regex6));
            System.out.println("aBc".matches(regex6));
    
    
            // 复杂
            String IDCardRegex = "[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|10|11|12)(0[1-9]|[1-2]\\d|30|31)\\d{3}[\\dXx]";
            
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    小结:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    作用2 在一段文本中查找满足作用的内容

    爬虫

    Pattern: 表示正则表达式

    Matcher: 文本匹配器, 作用: 按照正则表达式的规则去读取字串, 从头开始读取

    package RegexDemo1;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegexTest {
        public static void main(String[] args) {
            // 要求找出里面所有的JAVAXX
            String str = "Java自从95年问世以来, 经历了很多版本, 目前企业中用的最多的是Java8" + 
                    "和Java11, 因为这两个是长期支持版本, 下一个长期支持版本是Java17, 相信在未来不久Java17也会登上历史舞台";
            
            // 获取正则表达式的对象
            Pattern p = Pattern.compile("Java\\d{0,2}");
            // 获取文本匹配器的对象
            // m: 文本匹配器的对象
            // str: 大串
            // p: 规则
            // 理解为: m要在str中找符合p规则的小串
            Matcher m = p.matcher(str);
            
            // 拿着文本匹配器从头开始读取, 寻找是否有满足规则的子串
            // 如果没有, 方法返回false
            // 如果有, 返回true, 在底层记录字串的起始索引和结束索引+1
            // 0, 4
    
            boolean b = m.find();
            System.out.println(b); // true
            // 方法底层会根据find方法记录的索引进行字符串的截取
            // subString(start, end) 包头不包围
            // (0, 4) 但是不包括4索引
            // 会把街区的小串进行返回
            String s1 = m.group();
            System.out.println(s1);
    
            // 第二次调用find的时候, 会继续读取后面的内容
            // 重复返回
            while(m.find()){
                s1 = m.group();
                System.out.println(s1);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    练习:

    package RegexDemo1;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegexTest2 {
        public static void main(String[] args) {
            String str = "来黑马程序员学习Java" +
                    "电话: 18512516758,18512508907" +
                    "或者联系邮箱: boniu@itcast.cn," +
                    "座机电话:01036517895,010-98951256"+
                    "邮箱: bozai@itcast.cn" +
                    "热线电话: 400-618-9090,400-618-4000,4006184000,4006189090";
    
            // 把电话, 邮箱, 手机号, 热线都爬取出来
            String phone = "1[3-9]\\d{9}";
            String mail = "\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2}";
            String zuoJi = "0\\d{2,3}-?[1-9]\\d{4,9}";
            String reXian = "400-?[1-9]\\d{2}-?[1-9]\\d{3}";
    
            String regex = "(1[3-9]\\d{9})|" +
                    "(\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2})|" +
                    "(0\\d{2,3}-?[1-9]\\d{4,9})|" +
                    "(400-?[1-9]\\d{2}-?[1-9]\\d{3})";
    
            // 获取正则表达式对象
            Pattern p = Pattern.compile(regex);
            // 获取文本匹配器的对象
            Matcher m = p.matcher(str);
            while (m.find()){
                String s = m.group();
                System.out.println(s);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    有条件的数据爬取

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    需求1:

    package RegexDemo1;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegexTest3 {
        public static void main(String[] args) {
            String str = "Java自从95年问世以来, 经历了很多版本, 目前企业中用的最多的是Java8" +
                    "和Java11, 因为这两个是长期支持版本, 下一个长期支持版本是Java17, " +
                    "相信在未来不久Java17也会登上历史舞台";
            // 1.定义正则表达式
            // ?理解为前面的数据Java
            // =表示在Java后面要跟随的数据
            // 但是在获取的时候, 只获取前半部分
            String regex = "Java(?=8|11|17)";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(str);
            while (m.find()){
                String s = m.group();
                System.out.println(s);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    需求2:

    // 需求2
    String regex2 = "Java(8|11|17)";
    String regex3 = "Java(?:8|11|17)"; // 都可以
    
    Pattern p = Pattern.compile(regex3);
    Matcher m = p.matcher(str);
    while (m.find()){
        String s = m.group();
        System.out.println(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    需求3:

    // 需求3
    String regex4 = "Java(?!8|11|17)";
    Pattern p = Pattern.compile(regex4);
    Matcher m = p.matcher(str);
    while (m.find()){
        String s = m.group();
        System.out.println(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    小结:

    带有选择性的数据爬取

    String regex1 = "Java(?=8|11|17)";
    
    • 1

    获取的时候只获取前半部分

    String regex3 = "Java(?:8|11|17)";
    
    • 1

    全都获取

    String regex4 = "Java(?!8|11|17)";
    
    • 1

    只要Java, 不爬取Java8, 11, 17

    贪婪爬取和非贪婪爬取

    贪婪爬取: 在爬取数据的时候, 尽可能的多获取 abbbbbbbbbbbbbbb

    非贪婪爬取: 尽可能少获取 ab

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    Java默认贪婪爬取

    如果我们在数量词 + * 的后面加上问号, 就是非贪婪爬取

    package RegexDemo1;
    
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    public class RegexTest4 {
        public static void main(String[] args) {
            String s = "Java自从95年问世以来," +
                    "abbbbbbbbbbbbaaaaaaaaaaaaaaaaaa经历了很多版本," +
                    "目前企业中用的最多的是Java8和Java11," +
                    "因为这两个是长期支持版本," +
                    "下一个长期支持版本是Java17," +
                    "相信在未来不久Java17也会逐渐登上历史舞台";
    
            String regex1 = "ab+";
            Pattern p = Pattern.compile(regex1);
    
            Matcher m = p.matcher(s);
            while (m.find()){
                String str = m.group();
                System.out.println(str); // abbbbbbbbbbb
            }
    
            String regex2 = "ab+?";
            p = Pattern.compile(regex2);
            m = p.matcher(s);
            while (m.find()){
                String str = m.group();
                System.out.println(str); // ab
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    正则表达式在字符串方法中的使用

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    replaceAll 细节:

    方法在底层跟之前一样也会创建文本解析器的对象

    然后从头开始去读取字符串中的内容, 只要有满足的, 那么就用第二个参数去替换

    package RegexDemo;
    
    public class RegexDemo4 {
        public static void main(String[] args) {
            // replacaAll 和 split 应用
            String s = "消失时bfdcjhsbj456小蛋蛋fbgdsyue458小灰灰";
    
            // 把三个名字之间的字母替换为vs
            String res = s.replaceAll("[\\w&&[^_]]+", "vs");
            System.out.println(res); // 消失时vs小蛋蛋vs小灰灰
    
            // 把字符串中的三个姓名切割出来
            String[] arr = s.split("[\\w&&[^_]]+");
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
    //        消失时
    //        小蛋蛋
    //        小灰灰
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    想知道字符串哪些识别正则表达式, 可以看这个方法的参数是否有regex, 有regex的方法就可以识别正则表达式

    分组

    概述

    分组就是个小括号

    每组是有组号的, 也就是序号

    规则1: 从1开始, 连续不间断

    规则2: 以左括号为基准, 最左边的是第一组, 其次为第二组, 以此类推

    练习: 捕获分组

    捕获分组就是把这一组的数据捕获出来,再用一次

    需求1:判断一个字符串的开始字符和结束字符是否一致?

    只考虑一个字符

    举例: a123a b456b 17891 &abc&

    需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符

    举例:abc123abc b456b 123789123 &!@abc&!@

    需求3:判断一个字符串的开始部分和结束部分是否一致? 开始部分内部每个字符也需要一致

    举例:bbb456bbb 111789111 &&abc&& aaa123aaa

    package RegexDemo;
    
    public class RegexDemo5 {
        public static void main(String[] args) {
            // 需求1: 判断开头结尾是否一致, 只考虑一个字符
            //   \\组号: 表示把第X组的内容拿出来在用一次
            String regex1 = "(.).+\\1";
            System.out.println("a123a".matches(regex1));
            System.out.println("b456b".matches(regex1));
            System.out.println("17891".matches(regex1));
            System.out.println("&abc&".matches(regex1));
            System.out.println("&745*".matches(regex1)); // false
    
            // 需求2: 判断开头结尾是否一致, 可以有多个字符
            String regex2 = "(.+).+\\1";
            System.out.println("abc123abc".matches(regex2));
    
            // 需求3: 开始部分内部每个字符要一致
            // (.) 把首字母看作一组
            // \\2 把首字母拿出来再次使用
            //  * 作用于\\2, 表示后面重复的内容出现0次或多次
            String regex3 = "((.)\\2*).+\\1";
            System.out.println("bbb456bbb".matches(regex3));
            System.out.println("111789111".matches(regex3));
            System.out.println("aaa123aaa".matches(regex3));
            System.out.println("aaa123aab".matches(regex3));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    捕获分组

    正则内部使用: \\组号

    正则外部使用: $组号


    需求: 将字符串: 我要学学编编编编编编程程程程程程

    替换为: 我要学编程

    package RegexDemo;
    
    public class RegexDemo6 {
        public static void main(String[] args) {
    //        需求: 将字符串: 我要学学编编编编编编程程程程程程
    //        替换为: 我要学编程
            String s = "我要学学编编编编编编程程程程程程";
    
            // (.) 把重复内容的第一个字符 看作一组
            // \\1 表示第一个字符再次出现
            //  + 至少一次
            // $1 表示正则表达式中第一组的内容
            String res1 = s.replaceAll("(.)\\1+", "$1");
            System.out.println(res1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    非捕获分组

    分组之后不需要再用本组数据, 仅仅是把数据括起来

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    不占用组号, 再写\\1就会报错

    更多使用第一个

    ?: 可以不写, 但是一般都用, 要能看懂

    7.时间相关类

    7.1 JDK7前的时间相关类

    Date 时间

    SimpleDateFormat 格式化时间

    Calendar 日历

    时间相关知识

    全世界的时间有一个统一的标准

    格林尼治时间(Greenwich Mean Time) 简称GMT

    计算核心: 地球自转一天是24小时, 太阳直射时为正午12点

    但是这种方法误差太大(最大16分钟)

    2012年后使用原子钟

    原理: 利用铯原子的振动频率计算出来的时间, 作为世界标准时间(UTC). 每秒震动91亿次

    1s = 1000ms = 1 000 000 微秒 = 1 000 000 000 纳秒

    Date类

    Date类是一个JDK写好的JavaBean类, 用来描述时间, 精确到毫秒

    利用空参构造创建的对象, 默认表示系统当前时间

    利用有参构造创建的对象, 表示指定的时间

    修改事件对象的毫秒值

    setTime(毫秒值)

    获取时间对象中的毫秒值

    getTime();

    package DateDemo;
    
    import java.util.Date;
    
    public class DateDemo1 {
        public static void main(String[] args) {
            // 1. 创建对象表示一个时间
            Date d1 = new Date();
            System.out.println(d1);
    
            // 2. 创建对象, 表示指定时间
            Date d2 = new Date(0L);
            System.out.println(d2);
    
            // 3. setTime 修改时间
            d2.setTime(1000L);
            System.out.println(d2);
    
            // 4. getTime 获取当前时间的毫秒值
            long time = d2.getTime();
            System.out.println(time);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    练习:

    package DateDemo;
    
    import java.util.Date;
    import java.util.Random;
    
    public class DateDemo2 {
        public static void main(String[] args) {
            // 需求1: 打印时间原点开始一年之后的时间
            // 需求2: 定义两个Date对象,比较一下那个时间在前, 那个在后
    
            //extracted();
    
            // 2
            Random r = new Random();
            Date d1 = new Date(Math.abs(r.nextInt()));
            Date d2 = new Date(Math.abs(r.nextInt()));
            System.out.println(d1);
            System.out.println(d2);
            long time1 = d1.getTime();
            long time2 = d2.getTime();
            if(time1 > time2){
                System.out.println("d1在后");
            } else if (time1 < time2) {
                System.out.println("d2在后");
            }else {
                System.out.println("时间相等");
            }
    
        }
    
        private static void extracted() {
            // 需求1
            Date d1 = new Date(0L);
            long time = d1.getTime();
            time += 1000L * 3600 * 24 * 365;
            System.out.println(time);
            d1.setTime(time);
            System.out.println(d1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    SimpleDateFormat
    作用:

    格式化: 把时间变成喜欢的格式

    解析: 把字符串表示的时间变成Date对象(2022年1月1日转为Date时间)

    常用方法:

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    有参构造中的参数 的模式对应关系

    yyyy-MM-dd HH:mm:ss

    yyyy年MM月dd日 HH:mm:ss EE

    package SimpleDateFormat;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class SimpleDateFormatDemo1 {
        public static void main(String[] args) throws ParseException {
            extracted();
    
            // 定义一个字符串表示时间
            String str = "2023-11-15 19:51:00";
            // 利用空参构造创建SimpleDateFormat对象
            // 细节:
            // 创建对象的格式要跟字符串的格式完全一致
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse(str);
            System.out.println(date.getTime()); // 得到一个Date对象
    
    
        }
    
        private static void extracted() {
            // 利用空参构造创建对象
            SimpleDateFormat sdf1 = new SimpleDateFormat();
            Date d1 = new Date(0L);
            String str1 = sdf1.format(d1);
            System.out.println(str1); //1970/1/1 08:00
    
            // 利用带参构造 指定格式输出
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss EE");
            String str2 = sdf2.format(d1);
            System.out.println(str2); // 1970-00-01 08:00:00 周四
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    练习

    把2000-11-11转换为2000年11月11日

    package SimpleDateFormat;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Demo2 {
        public static void main(String[] args) throws ParseException {
            String str = "2000-11-11";
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf1.parse(str); //
            System.out.println(date);
    
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日");
            String res = sdf2.format(date);
            System.out.println(res);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    Calendar
    概述

    Calendar代表了系统当前时间的日历对象, 可以单独修改, 获取事件中的年月日

    细节: Calendar是一个抽象类, 不能直接创建对象

    获取Calendar对象的方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    常用方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package CalenDarDemo;
    
    import java.util.Calendar;
    import java.util.Date;
    
    public class Demo1 {
        public static void main(String[] args) {
            // 1. 获取日历对象
            // 细节1: Calendar是一个抽象类, 不能直接new, 而是通过一个静态方法获取子类对象
            // 底层原理:
            // 会根据系统的不同时区来获取不同的日历对象, 默认表示当前时间
            // 会把事件中的纪元, 年, 月, 日, 时分秒星期等都放到一个数组中
            // 细节2:
            // 月份: 范围0-11 依次表示1-12月
            // 星期: 在老外的眼里, 1代表星期日, 以此类推
    
            Calendar c = Calendar.getInstance();
            System.out.println(c);
    
            // 修改日历代表的时间
            // 0 - 纪元
            // 1 - 年
            // 2 -月
            // 3 - 一年的中的第几周
            // 4 - 一个月中的第几周
            // 5 - 一个月中的第几天(日期)
            Date d = new Date(0L);
            c.setTime(d);
            System.out.println(c);
    
            // java在Calender类中, 把索引dui'y
            int year = c.get(Calendar.YEAR);
            int month = c.get(Calendar.MONTH);
            int date = c.get(Calendar.DAY_OF_MONTH);
            int week = c.get(Calendar.DAY_OF_WEEK);
            System.out.println(year + ", " + month + ", " + date + ", " + week); // 1970, 0, 1, 5
    
            // 获取毫秒值
            c.setTimeInMillis(1000);
            long timeInMillis = c.getTimeInMillis();
            System.out.println(timeInMillis);
    
            c.set(Calendar.YEAR, 1997);
            c.set(Calendar.MONTH, 4);
            // 在1号的基础加7天
            c.add(Calendar.DAY_OF_MONTH, 7);
    
            year = c.get(Calendar.YEAR);
            month = c.get(Calendar.MONTH);
            date = c.get(Calendar.DAY_OF_MONTH);
            week = c.get(Calendar.DAY_OF_WEEK);
            System.out.println(year + ", " + month + ", " + date + ", " + week); //1997, 4, 8, 5
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    7.2 JDK8新增时间相关类

    JDK7 和 JDK8 时间相关类的区别

    代码层面 安全层面

    JDK7 代码麻烦 JDK7多线程下会导致数据安全的问题

    JDK8 简单 时间日期对象都是不可变的, 解决了这个问题

    要学习的类

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    Date类
    ZoneId时区
    常用方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package ZoneIdDemo;
    
    import java.time.ZoneId;
    import java.util.Set;
    
    public class Demo1 {
        public static void main(String[] args) {
            // 获取Java中所有时区
            Set<String> s = ZoneId.getAvailableZoneIds();
            System.out.println(s);
    
            // 获取系统默认时区
            ZoneId zoneId = ZoneId.systemDefault();
            System.out.println(zoneId);
    
            // 获取指定时区
            ZoneId newYork = ZoneId.of("America/Cuiaba");
            System.out.println(newYork);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    Instant时间戳
    常见方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package ZoneIdDemo;
    
    import java.time.Instant;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    public class Demo2 {
        public static void main(String[] args) {
            // 获取当前时间的Instant对象
            Instant now = Instant.now();
            System.out.println(now); //2023-11-16T02:28:07.829588600Z
    
            // 根据(秒 毫秒 纳秒)获取Instant对象
            Instant instant1 = Instant.ofEpochSecond(0L);
            System.out.println(instant1); //1970-01-01T00:00:00Z
            Instant instant2 = Instant.ofEpochSecond(1L);
            System.out.println(instant2); // 1970-01-01T00:00:01Z
            Instant instant3 = Instant.ofEpochSecond(1L, 1000000000L);
            System.out.println(instant3); // 1970-01-01T00:00:02Z
    
            // 指定时区
            ZonedDateTime time = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));
            System.out.println(time); // 2023-11-16T10:30:36.375789800+08:00[Asia/Shanghai]
    
            // 判断 isXxx
            Instant instant4 = Instant.ofEpochMilli(0L);
            Instant instant5 = Instant.ofEpochMilli(1000L);
            // isBefore: 判断调用者时间是否在参数表示的时间前面
            // isAfter: 判断调用者时间是否在参数表示的时间后面
            boolean res1 = instant4.isBefore(instant5);
            boolean res2 = instant4.isAfter(instant5);
            System.out.println(res1 + " " + res2); // true false
    
            // 时间增加或减少的方法
            Instant instant6 = Instant.ofEpochMilli(3000L);
            Instant instant7 = instant6.minusSeconds(1);
            System.out.println(instant6); // 1970-01-01T00:00:03Z
            System.out.println(instant7); // 1970-01-01T00:00:02Z
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    ZoneDateTime
    常用方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package ZoneIdDemo;
    
    import java.time.Instant;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    public class Demo3 {
        public static void main(String[] args) {
            // 获取当前时间对象(带时区
            ZonedDateTime now = ZonedDateTime.now();
            System.out.println(now); // 2023-11-16T10:48:57.839325100+08:00[Asia/Shanghai]
    
            // 获取指定那个的时间对象(带时区
            // 年月日时分秒纳秒指定
            ZonedDateTime time1 = ZonedDateTime.of(2023,11,16,
                    10,51,0,0,ZoneId.of("Asia/Shanghai"));
            System.out.println(time1); // 2023-11-16T10:51+08:00[Asia/Shanghai]
    
            // 通过Instant + 时区的方式指定获取的时间对象
            Instant instant = Instant.ofEpochMilli(0L);
            ZoneId zoneId = ZoneId.of("Asia/Shanghai");
            ZonedDateTime time2 = ZonedDateTime.ofInstant(instant, zoneId);
            System.out.println(time2); // 1970-01-01T08:00+08:00[Asia/Shanghai]
    
            // withXxx 修改时间系列的方法
            ZonedDateTime time3 = time2.withYear(2020);
            System.out.println(time3); // 2020-01-01T08:00+08:00[Asia/Shanghai]
    
            // 减少时间
            ZonedDateTime time4 = time3.minusHours(1);
            System.out.println(time4); // 2020-01-01T07:00+08:00[Asia/Shanghai]
    
            // 增加时间
            ZonedDateTime time5 = time4.plusDays(30);
            System.out.println(time5); // 2020-01-31T07:00+08:00[Asia/Shanghai]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    日期格式化类
    DateTimeFormatter

    用于时间的格式化和解析

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    package ZoneIdDemo;
    
    import java.time.Instant;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Demo4 {
        public static void main(String[] args) {
            // 获取时间对象
            ZonedDateTime time = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));
            // 解析/格式化器
            DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EE a");
            // 格式化
            String res = dtf1.format(time);
            System.out.println(res); // 2023-11-16 11:04:06 周四 上午
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    日历类(Calendar)

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    LocalDate

    年月日

    package ZoneIdDemo;
    
    import java.time.LocalDate;
    import java.time.LocalTime;
    import java.time.Month;
    
    public class Demo5 {
        public static void main(String[] args) {
            // 1.获取当前时间的日历对象 年月日
            LocalDate nowDate = LocalDate.now();
            System.out.println(nowDate); // 2023-11-16
    
            // 2.获取指定时间的日历对象
            LocalDate date1 = LocalDate.of(2000, 1, 1);
            System.out.println(date1); // 2000-01-01
    
            // 3.get系列方法获取日历中的每一个属性值
            // 获取月有两种方式
            int year = date1.getYear();
            Month month = date1.getMonth();
            System.out.println(month); // JANUARY
            int monthValue = date1.getMonthValue();
            int dayOfMonth = date1.getDayOfMonth();
            System.out.println(year + "-" + monthValue + "-" + dayOfMonth); // 2000-1-1
    
            // 判断日期前后
            LocalDate date2 = LocalDate.of(2023,11,16);
            boolean res1 = date1.isBefore(date2);
            System.out.println(res1); // true
            boolean res2 = date1.isAfter(date2);
            System.out.println(res2); // false
    
            // with修改时间
            LocalDate date3 = date2.withYear(2020);
            System.out.println(date3); // 2020-11-16, 也就是说只修改了年份, 月份日期都不变
    
            // minus 减少 plus增加时间
            LocalDate date4 = date3.minusMonths(1);
            System.out.println(date4); // 2020-10-16
            LocalDate date5 = date3.plusDays(1);
            System.out.println(date5); // 2020-11-17
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    LocalTime

    时分秒

    LocalDateTime

    年月日 时分秒

    LocalDateTime还能转换为其他两者

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    工具类
    Duration

    用于计算两个时间间隔(秒 纳秒)

    package ZoneIdDemo;
    
    import java.time.Duration;
    import java.time.LocalDateTime;
    
    public class DurationDemo {
        public static void main(String[] args) {
            // 现在的时间
            LocalDateTime today = LocalDateTime.now();
            System.out.println(today); // 2023-11-16T14:59:17.564971100
    
            LocalDateTime birthday = LocalDateTime.of(1997,4,8,0,0);
            System.out.println(birthday); // 1997-04-08T00:00
    
            Duration time = Duration.between(today, birthday);
            System.out.println(time); // PT-233247H-37.1452772S
            System.out.println("------------------------------------");
            System.out.println(time.toDays());
            System.out.println(time.toHours());
            System.out.println(time.toMinutes());
            System.out.println(time.toMillis());
            System.out.println(time.toNanos());
    //        -9718
    //        -233247
    //        -13994822
    //        -839689361893
    //        -839689361893931200
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    Period

    用于计算两个日期间隔(年月日)

    package ZoneIdDemo;
    
    import java.time.LocalDate;
    import java.time.Period;
    
    public class PeriodDemo {
        public static void main(String[] args) {
            // 当前时间的年月日
            LocalDate today = LocalDate.now();
            System.out.println(today); // 2023-11-16
            // 之前的一个时间
            LocalDate birthday = LocalDate.of(1997,4,8);
            System.out.println(birthday); // 1997-04-08
    
            Period period = Period.between(today, birthday);
            System.out.println(period); //P-26Y-7M-8D
            System.out.println(period.getYears()); // -26
            System.out.println(period.getMonths()); // -7
            System.out.println(period.getDays()); // -8
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    ChronoUnit

    用于计算两个日期间隔, 全面

    package ZoneIdDemo;
    
    import java.time.LocalDateTime;
    import java.time.temporal.ChronoUnit;
    import java.util.TooManyListenersException;
    
    public class ChronoUnitDemo {
        public static void main(String[] args) {
            // 当前时间
            LocalDateTime now = LocalDateTime.now();
            // 生日时间
            LocalDateTime birth = LocalDateTime.of(1997,4,8,0,0,0);
    
            System.out.println("相差的年数: " + ChronoUnit.YEARS.between(birth, now));
            System.out.println("相差的月数: " + ChronoUnit.MONTHS.between(birth, now));
            System.out.println("相差的周数: " + ChronoUnit.WEEKS.between(birth, now));
            System.out.println("相差的天数: " + ChronoUnit.DAYS.between(birth, now));
            System.out.println("相差的时数: " + ChronoUnit.HOURS.between(birth, now));
            System.out.println("相差的分数: " + ChronoUnit.MINUTES.between(birth, now));
            System.out.println("相差的秒数: " + ChronoUnit.SECONDS.between(birth, now));
            System.out.println("相差的毫秒数: " + ChronoUnit.MILLIS.between(birth, now));
            System.out.println("相差的微秒数: " + ChronoUnit.MICROS.between(birth, now));
            System.out.println("相差的纳秒数: " + ChronoUnit.NANOS.between(birth, now));
            System.out.println("相差的半天数: " + ChronoUnit.HALF_DAYS.between(birth, now));
            System.out.println("相差的十年数: " + ChronoUnit.DECADES.between(birth, now));
            System.out.println("相差的世纪数: " + ChronoUnit.CENTURIES.between(birth, now));
            System.out.println("相差的千年数: " + ChronoUnit.MILLENNIA.between(birth, now));
            System.out.println("相差的纪元数: " + ChronoUnit.ERAS.between(birth, now));
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    8.包装类

    包装类: 基本数据类型对应的引用数据类型

    如何理解包装类:

    用一个对象, 把基本数据类型给包起来

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    8种包装类

    1. byte: Byte
    2. short: Short
    3. int: Integer
    4. long: Long
    5. float: Float
    6. double: Double
    7. char: Character
    8. boolean: Boolean

    构造方法获取Integer对象和静态方法获取Integer对象的区别

    二者都是JDK5以前的方法, 现在已经不用了, 但是需要知道区别

    package BaoZhuangDemo;
    
    public class IntegerDemo {
        public static void main(String[] args) {
            // 静态方法获取Integer对象
            // 传入的数据在-128 ~ 127 之间
            // 会把提前擦创建好的对象提供出来, 不会创建新的, 可以节约内存
            // 否则会创建新的对象, 地址值就不一样了
            Integer i1 = Integer.valueOf(127);
            Integer i2 = Integer.valueOf(127);
            System.out.println(i1 == i2); // true
    
            Integer i3 = Integer.valueOf(128);
            Integer i4 = Integer.valueOf(128);
            System.out.println(i3 == i4); // false
    
            // new关键字在Java中每次都是创建了一个新的对象
            // 所以两个new出来的对象地址一定是不一样的
            // 构造方法获取Integeri对象
            Integer i5 = new Integer(127);
            Integer i6 = new Integer(127);
            System.out.println(i5 == i6); // false
    
            Integer i7 = new Integer(128);
            Integer i8 = new Integer(128);
            System.out.println(i7 == i8); // false
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    以前的包装类如何相加?

    1. 把对象进行拆箱
    2. 相加
    3. 把得到的结果进行装箱

    但是很麻烦

    自动装箱和自动拆箱

    JDK5的时候提出自动装箱和自动拆箱

    自动装箱: 把基本数据类型自动变为其对应的包装类

    自动拆箱: 把包装类自动变成其对象的基本数据类型

    // 在底层, 此时还会去自动调用静态方法valueof得到一个Integer对象, 只不过这个动作不需要我们自己去操作
    // 自动装箱的动作
    Integer i = 10;
    
    Integer ii = new Integer(12);
    // 自动拆箱的动作
    i = ii;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在JDK5以后, int和Integer可以看作是同一个东西, 因为在内部可以自动转化

    以后也会经常使用自动装箱的方式来获取包装类对象

    Integer成员方法

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    前三种方法都是返回字符串的原因:

    1. 二进制可能是0开头
    2. int类型有长度限制
    方法演示
    package BaoZhuangDemo;
    
    public class IntegerDemo2 {
        public static void main(String[] args) {
            // 1.把整数转为二进制 八进制 十六进制
            String str1 = Integer.toBinaryString(100);
            System.out.println(str1); // 1100100
            String str2 = Integer.toOctalString(100);
            System.out.println(str2); // 144
            String str3 = Integer.toHexString(100);
            System.out.println(str3); // 64
    
            // 2. 将字符串种类型的证书转为int类型的整数
            // Java是一种强类型语言, 每种数据都有各自的数据类型
            // 在计算的时候, 入股不是同一种数据类型, 是无法直接计算的
            int i = Integer.parseInt("123");
            System.out.println(i + 1); // 124
            // 细节1:
            // 在类型转换的时候, 括号中的参数只能是数字不能是其他的, 否则会报错
            // 细节2:
            // 8种包装类中, 除了Character都有对应的parseXxx的方法, 进行类型转换
            String str = "true";
            boolean b = Boolean.parseBoolean(str);
            System.out.println(b); // true
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    键盘录入
    package BaoZhuangDemo;
    
    import java.util.Scanner;
    
    public class IntegerDemo3 {
        public static void main(String[] args) {
            // 键盘录入
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入一个字符串:");
            // 弊端:
            // 当我们在使用next,nextInt,nextDouble在接收数据的时候,
            // 遇到空格,回车,制表符的时候就停止了
            // 键盘录入的是123 123 那么此时只能接收到空格前面的数据
            // 我想要的是接收一整行数据
            // 约定:
            // 以后我们如果想要键盘录入,不管什么类型,统一使用nextLine
            // 特点遇到回车才停止
            String line = sc.nextLine();
            System.out.println(line);
            // 然后再利用parse方法转换
            int i = Integer.parseInt(line);
            System.out.println(i);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    练习题

    package Practice;
    
    import java.util.ArrayList;
    import java.util.Scanner;
    
    public class Practice1 {
        public static void main(String[] args) {
    //        test01();
            test02();
        }
    
        // 及那盘录入一些1-100之间的整数, 并添加到集合中
        // 直到集合中所有数据和超过200为止
        public static void test01(){
            Scanner sc = new Scanner(System.in);
            ArrayList<Integer> list = new ArrayList<>();
            while(!moreThan200(list)){
                System.out.println("请输入1-200之间的整数: ");
                String s = sc.nextLine();
                int num = Integer.parseInt(s);
                list.add(num);
            }
            System.out.println("总和已超过200");
        }
    
        public static boolean moreThan200(ArrayList<Integer> list){
            int res = 0;
            for (int i = 0; i < list.size(); i++) {
                res += list.get(i);
            }
            return res > 200;
        }
    
        public static void test02(){
            String str = "23658105";
            // 校验字符串
            if(!str.matches("[1-9]\\d{0,9}]")){
                System.out.println("错误的数据");
                return;
            }
            int sum = 0;
            for (int i = 0; i < str.length(); ++i) {
                char c = str.charAt(i);
                int num = c - '0';
                
                sum = sum * 10 + num;
            }
            System.out.println(sum);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    package Practice;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.time.LocalDate;
    import java.time.temporal.ChronoUnit;
    import java.util.Date;
    
    public class Practice2 {
        public static void main(String[] args) throws ParseException {
            String s1 = tenTo2(123);
            System.out.println(s1);
            // 验证
            String s2 = Integer.toBinaryString(123);
            System.out.println(s2);
    
            test02();
    
            System.out.println(isLeapYear(2000)); // true
            System.out.println(isLeapYear(2001)); // false
    
    
        }
    
        public static String tenTo2(int num){
            // 将十进制整数转成字符串表示的二进制
            StringBuilder sb = new StringBuilder();
            while(num > 0){
                int x = num % 2;
                num /= 2;
                sb.insert(0, x);
            }
            return sb.toString();
        }
    
        public static void test02() throws ParseException {
            // 用代码计算活了多少天
            // JDK7
            String bir = "1997-04-08";
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse(bir);
            // 获取生日的毫秒值
            long time1 = date.getTime();
            //System.out.println(time1);
            // 获取当前的毫秒值
            long time2 = System.currentTimeMillis();
            //System.out.println(time2);
            // 求差值
            long time = time2 - time1;
            System.out.println(time / 1000 / 3600 / 24);
    
    
            // JDK8
            LocalDate d1 = LocalDate.now();
            LocalDate d2 = LocalDate.of(1997, 4, 8);
            long days = ChronoUnit.DAYS.between(d2, d1);
            System.out.println(days);
        }
    
        // 判断是否为闰年
        public static boolean isLeapYear(int year){
            LocalDate d1 = LocalDate.of(year, 2, 1);
            LocalDate d2 = LocalDate.of(year, 3, 1);
            //return ChronoUnit.DAYS.between(d1, d2) == 29;
    
            // 还有一个专门的函数
            return d1.isLeapYear();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  • 相关阅读:
    git 提交代码
    2022最新PPT模板,免费下载
    一个高精度24位ADC芯片ADS1222的使用方法及参考电路程序成都控制器定制
    分布式执行引擎ray入门--(2)Ray Data
    06 图形学——光照模型
    java计算机毕业设计小区宠物管理系统源码+系统+数据库+lw文档
    文件输入输出处理-File
    Springboot企业工资管理系统r9a51计算机毕业设计-课程设计-期末作业-毕设程序代做
    前端基础(四十一):你不知道的JavaScript - 行为委托 及 类写法的实例应用
    <C++> 模板-上
  • 原文地址:https://blog.csdn.net/f593256/article/details/134458701