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

news2024/11/27 16:31:48

常用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
     * <i>e</i>, the base of the natural logarithms.
     */
    public static final double E = 2.718281828459045;

    /**
     * The {@code double} value that is closer than any other to
     * <i>pi</i> (&pi;), the ratio of the circumference of a circle to
     * its diameter.
     */
    public static final double PI = 3.141592653589793;

扩展:

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. 如果数据源数组和目的地数组都是基本数据类型, 那么两者的类型必须保持一致
    比如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");

    }
}

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);

    }
}

默认情况下, 打印一个对象打印的就是地址值, 如果想打印对象里面的属性, 可以重写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);
}
小练习
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. 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);
}

该方法会先判断参数是否为字符串, 如果是字符串, 在比较内部的属性, 如果不是, 直接返回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();
    }
}

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);
    }
}

细节:

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

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);

两个对象里的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;
}

扩展:

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

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

    }
}

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);

    }
}

常用的方法是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. 对于计算机而言, 是没有数据类型的概念的, 都是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 <em>must</em> 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 <i>big-endian</i> 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;

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. 如果要表示的数字不大, 没有超出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-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

    }
}

舍入模式:

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

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);
    }
}

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

上限: 小数总长度不超过数组长度也就是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
    // [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

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

    //此时\表示转义字符,改变了后面那个双引号原本的含义
    //把他变成了一个普普通通的双引号而已。
    System.out.println("\"");

    // \表示转义字符
    //两个\的理解方式:前面的\是一个转义字符,改变了后面\原本的含义,把他变成一个普普通通的\而已。
    System.out.println("c:Users\\moon\\IdeaProjects\\basic-code\\myapi\\src\\com\\itheima\\a08regexdemo\\RegexDemo1.java");
    //.表示任意一个字符
    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("---------------------------------------------");
    // 以上正则匹配只能校验单个字符。

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

代码示例:

    // 必须是数字 字母 下划线 至少 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. 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. 区号 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));

扩展:

平时几乎不用自己写, 下载插件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]";
        
    }
}

小结:

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

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

作用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);
        }
    }
}

练习:

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:

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);
        }
    }
}

需求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);
}

需求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);
}

小结:

带有选择性的数据爬取

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

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

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

全都获取

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

只要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
        }

    }
}
正则表达式在字符串方法中的使用

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

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]);
        }
//        消失时
//        小蛋蛋
//        小灰灰
    }
}

想知道字符串哪些识别正则表达式, 可以看这个方法的参数是否有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));
    }
}

捕获分组

正则内部使用: \\组号

正则外部使用: $组号


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

替换为: 我要学编程

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就会报错

更多使用第一个

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

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);
    }
}

练习:

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);
    }
}
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 周四
    }
}
练习

把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);

    }
}
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

    }
}

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);
    }
}
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
    }
}
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]
    }
}
日期格式化类
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 周四 上午
    }
}
日历类(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

    }

}
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
    }
}
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
    }
}
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));

    }
}

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. 把得到的结果进行装箱

但是很麻烦

自动装箱和自动拆箱

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

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

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

// 在底层, 此时还会去自动调用静态方法valueof得到一个Integer对象, 只不过这个动作不需要我们自己去操作
// 自动装箱的动作
Integer i = 10;

Integer ii = new Integer(12);
// 自动拆箱的动作
i = ii;

在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
    }
}
键盘录入
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);
    }
}

练习题

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);
    }
}
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();

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1218881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人脸106和240点位检测解决方案

人脸识别技术已经深入到我们生活的各个领域&#xff0c;从手机解锁、门禁系统到视频娱乐化等&#xff0c;都离不开高精度的人脸关键点检测。美摄科技作为行业的领军企业&#xff0c;一直致力于提供最先进、最稳定的人脸识别技术&#xff0c;近日&#xff0c;我们推出了全新的10…

阿桂天山的小工具:我将16个Excel文件中31万多条数据拆分成318个文件

1.话不多说,先上图看效果 2.技术说明及实用源码 2.1)pythonflaskpandas , 由于我的开发环境版本问题,为了能读xls,xlsx,但又不想升级,只能通过xlrd 1.2.0读取xls,xlsx文件再转换成dict字典格式,再通过 data pd.DataFrame(dict_data)实现类型转换 2.2)实用代码,保证不丢任何一行…

深入探讨TensorFlow:张量与矩阵

在机器学习和深度学习领域中&#xff0c;TensorFlow作为一款强大且受欢迎的开源机器学习框架&#xff0c;为研究人员和开发者提供了丰富的工具和资源。在TensorFlow中&#xff0c;张量&#xff08;tensor&#xff09;和矩阵&#xff08;matrix&#xff09;是核心概念&#xff0…

【vue】下载导出excel

下载导出excel 首先使用的tdesign框架&#xff0c;要导出后端返回的数据流excel 遇见的问题 下载的文件&#xff0c;里边的内容是undefined 观察报错 一看就知道并不是后端的报错&#xff0c;后端不可能是undefined 在强烈的好奇心驱动下&#xff0c;看了下接口&#xff0…

Python实现Tom与Jerry

文章目录 写在前面系列文章绘图基础Tom&Jerry写在后面 写在前面 汤姆永远抓不到杰瑞&#xff0c;我们的故事永远不会结束&#xff01;本期博主给大家带来了Tom&Jerry&#xff0c;快来看看吧~&#xff08;Tom和Jerry可以修改成自己想修改的名字哦&#xff09; 系列文章…

解决SSH连接自动断开的问题

一、环境 centos7.6 xshell7 二、目标 ssh长联状态&#xff0c;不主动断开 三、实施 1.修改/etc/profile文件 末尾添加export TMOUT0 vim /etc/profileexport TMOUT02.修改/etc/ssh/sshd_config文件 默认都被注释掉&#xff0c;放开并设置CAI参数为0-60间 vim /etc…

轻松一刻|Walrus CLI与CI/CD工具集成,轻松部署2048游戏

Walrus 是一款开源的基于平台工程理念、以应用为中心、以完整应用系统自动化编排交付为目标进行设计开发的云原生应用平台&#xff0c;简化和自动化应用部署与发布流程并与现有的 CI/CD 流水线无缝集成。今天我们来点有趣的&#xff0c;跟随本教程&#xff0c;一起将 Walrus CL…

2023年第九届数维杯国际大学生数学建模挑战赛A题

2023年第九届数维杯国际大学生数学建模挑战赛正在火热进行&#xff0c;小云学长又在第一时间给大家带来最全最完整的思路代码解析&#xff01;&#xff01;&#xff01; A题思路解析如下&#xff1a; 完整版解题过程及代码&#xff0c;稍后继续给大家分享~ 更多题目完整解析点…

数据结构与算法【队列】的Java实现

队列&#xff1a;以顺序的方式维护的一组数据集合&#xff0c;在一端添加数据&#xff0c;从另一端移除数据。习惯来说&#xff0c;添加的一端称为尾&#xff0c;移除的一端称为头。 通用接口 public interface Queue<E> {/*** 插入队列*/boolean offer(E value);/*** 从…

Web浏览器的同源策略(same-origin policy)

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

卷积神经网络(CNN)mnist手写数字分类识别的实现

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3.归一化4.可视化5.调整图片格式 二、构建CNN网络模型三、编译模型四、训练模型五、预测六、知识点详解1. MNIST手写数字数据集介绍2. 神经网络程序说明3. 网…

6.docker运行mysql容器-理解容器数据卷

运行mysql容器-理解容器数据卷 1.什么是容器数据卷2.如何使用容器数据卷2.1 数据卷挂载命令2.2 容器数据卷的继承2.3 数据卷的读写权限2.4 容器数据卷的小实验&#xff08;加深理解&#xff09;2.4.1 启动挂载数据卷的centos容器2.4.2 启动后&#xff0c;在宿主机的data目录下会…

IDEA创建SpringBoot的多模块项目教程

最近在写一个多模块的SpringBoot项目&#xff0c;基于过程总了一些总结&#xff0c;故把SpringBoot多个模块的项目创建记录下来。 首先&#xff0c;先建立一个父工程&#xff1a; &#xff08;1&#xff09;在IDEA工具栏选择File->New->Project &#xff08;2&#xff0…

热点检测/降级框架Akali的部分原理解析

发现个“轻量级本地化热点检测/降级框架 这个框架名为Akali,项目地址&#xff1a;https://gitee.com/bryan31/Akali主要有两个作用 1&#xff1a;热点检测及处理 2&#xff1a;降级检测及处理 从官网文档来看使用是比较简单的&#xff0c;一个注解就能搞定 怀着好奇的心情c…

Echarts 实现两两柱图重叠(背景和实际值柱图)

Echarts实现两两重叠柱状图_echarts 重叠柱状图_Web_阿凯的博客-CSDN博客 引用启发的博客 先来效果&#xff1a; option {backgroundColor: #03213D,animation: true, // 控制动画是否开启animationDuration: 1000, // 动画的时长, 它是以毫秒为单位animationDuration: func…

数据结构C语言之线性表

发现更多计算机知识&#xff0c;欢迎访问Cr不是铬的个人网站 1.1线性表的定义 线性表是具有相同特性的数据元素的一个有限序列 对应的逻辑结构图形&#xff1a; 从线性表的定义中可以看出它的特性&#xff1a; &#xff08;1&#xff09;有穷性&#xff1a;一个线性表中的元…

Homography详解在MVSNet中的应用

Homography&#xff08;单应性变换&#xff09;是计算机视觉中的一个重要概念&#xff0c;用于描述两个平面之间的透视关系。在图像处理和计算机视觉中&#xff0c;Homography通常表示两个平面之间的投影关系&#xff0c;这种关系可以通过一个3x3的矩阵来表示。 在数学上&…

YB4019是一款完整的单电池锂离子恒流/恒压线性充电器电池

YB4019 耐压18V 1A线性双节8.4V 锂电充电芯片 概述&#xff1a; YB4019是一款完整的单电池锂离子恒流/恒压线性充电器电池。底部采用热增强ESOP8封装&#xff0c;外部组件数量低使YB4019成为便携式应用的理想选择。此外&#xff0c;YB4019设计用于在USB电源规格范围内工作。Y…

洗袜子的洗衣机哪款好?内衣洗衣机测评

随着人们的生活水平的提升&#xff0c;越来越多小伙伴来开始追求更高的生活水平&#xff0c;一些智能化的小家电就被发明出来&#xff0c;而且内衣洗衣机是其中一个。现在通过内衣裤感染到细菌真的是越来越多&#xff0c;所以我们对内衣裤的清洗频次会高于普通衣服&#xff0c;…

File类和IO流

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…