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

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android Studio 写一个Java调用c++ 的demo

前提条件&#xff1a; 本地已经配置好了ndk环境,如果没有配置好&#xff0c;建议参考macos 配置ndk环境-CSDN博客 这篇链接。 新建一个Empty Project 比如我这里的Project的名字是HelloJNI&#xff0c;包名是com.example.hellojni 然后在src目录下&#xff0c;右键选择Add C …

解决Requests中使用httpbin服务器问题:自定义URL的实现与验证

问题背景 在使用Python的Requests模块进行单元测试时&#xff0c;可能会遇到无法使用本地运行的httpbin服务器进行测试的问题。这是因为测试脚本允许通过环境变量HTTPBIN_URL指定用于测试的本地httpbin实例&#xff0c;但在某些测试用例中&#xff0c;URL是硬编码为httpbin.or…

SpringCloud -Token传递之Feign

目录 方法一 RequestHeader 方法二 使用Feign的Interceptor 步骤一 实现RequestInterceptor接口 步骤二&#xff1a;配置Feign 通常微服务对于用户认证信息解析有两种方案 在 gateway 就解析用户的 token 然后路由的时候把 userId 等相关信息添加到 header 中传递下去。在…

提取纯色马赛克

​​​​​​ 图像预处理 将彩色图像加载到内存。 转换图像为灰度图像&#xff0c;以简化处理。 对灰度图像应用二值化处理&#xff0c;将图像中的纯色区域分为前景和背景。这可以使用阈值处理来完成。 轮廓检测 使用轮廓检测算法&#xff0c;例如OpenCV的 findContours 函数&…

vite+vue3+electron开发环境搭建

环境 node 18.14.2 yarn 1.22 项目创建 yarn create vite test01安装vue环境 cd test01 yarn yarn dev说明vue环境搭建成功 安装electron # 因为有的版本会报错所以指定了版本 yarn add electron26.1.0 -D安装vite-plugin-electron yarn add -D vite-plugin-electron根目…

〖大前端 - 基础入门三大核心之JS篇㊱〗- JavaScript 的DOM节点操作

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

专注于绘画,不受限制!尝试Growly Draw for Mac的快速绘画应用

Growly Draw Mac版是Mac平台上的一款绘画应用&#xff0c;它提供了简单易用的画板页面和多种色彩、画笔工具&#xff0c;让你可以轻松地完成作画。无论你是初学者还是专业人士&#xff0c;都可以在这款应用中找到适合自己的绘画方式。通过使用Growly Draw Mac版&#xff0c;你可…

ChatGPT + DALL·E 3

参考链接&#xff1a; https://chat.xutongbao.top/

基于R语言平台Biomod2模型的物种分布建模与可视化分析

!](https://img-blog.csdnimg.cn/84e1cc8c7f9b4b6ab60903ffa17d82f0.jpeg#pic_center)

​软考-高级-系统架构设计师教程(清华第2版)【第11章 未来信息综合技术(P384~P419)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第11章 未来信息综合技术&#xff08;P384~P419&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

Pandas 累计统计函数【cumsum、cumprod、cummax、cummin】【计算前1/2/3/…/n个数的和、积、最大值、最小值】

一、累计统计函数 函数作用cumsum计算前1/2/3/…/n个数的和cummax计算前1/2/3/…/n个数的最大值cummin计算前1/2/3/…/n个数的最小值cumprod计算前1/2/3/…/n个数的积 import numpy as np import pandas as pd# np.nan &#xff1a;空值 df pd.DataFrame({key1: np.arange(1…

LLM大模型 (chatgpt) 在搜索和推荐上的应用

目录 1 大模型在搜索的应用1.1 召回1.1.1 倒排索引1.1.2 倒排索引存在的问题1.1.3 大模型在搜索召回的应用 (实体倒排索引&#xff09; 1.2 排序1.2.1 大模型在搜索排序应用&#xff08;融入LLM实体排序&#xff09; 2 大模型在推荐的应用2.1 学术界关于大模型在推荐的研究2.2 …

HttpClient示例

HttpClient官网 HttpClient - HttpClient Home 每个对应版本都有 快速开始的示例 maven项目 pom依赖 <dependencies><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.…

智能指针面试题

智能指针被问到的概率还是很大的&#xff0c;特别是Shared_ptr&#xff0c;最好会手撕&#xff0c;亲身经历&#xff01; 基本概念 1. RAll RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种利用对象生命周期来控制程序资源&#xff08;如内存、文…

(七)什么是Vite——vite优劣势、命令

vite分享ppt&#xff0c;感兴趣的可以下载&#xff1a; ​​​​​​​Vite分享、原理介绍ppt 什么是vite系列目录&#xff1a; &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff0…

Python入门学习篇(一)——注释变量输入输出

1 注释 1.1 作用 a 方便他人和自己阅读代码 b 告诉编译器这部分内容是不用执行的。1.2 单行注释 # 注释内容1.3 多行注释(引号) 1.3.1 三对双引号 """ 注释内容 """1.3.2 三对单引号 注释内容 1.4 pycharm快捷键使用 ctrl/ 多行注释(以# …

挑战视觉边界,探索图形验证码背后的黑科技

在日常生活中&#xff0c;我们登录网站或者其他平台时&#xff0c;在填写完账号密码之后&#xff0c;还会让我们填写4或6位的数字或者英文字母等&#xff0c;填写正确才能请求登录。这个其实是防止某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试&#xff0c;如下…

【观察】华为:数智世界“一触即达”,应对数智化转型“千变万化”

毫无疑问&#xff0c;数智化既是这个时代前进所趋&#xff0c;也是国家战略所指&#xff0c;更是所有企业未来发展进程中达成的高度共识。 但也要看到&#xff0c;由于大量新兴技术的出现&#xff0c;技术热点不停的轮转&#xff0c;加上市场环境的快速变化&#xff0c;让数智化…

ThreadLocal优化

测试类证明一下ThreadLocal存储的数据是线程程安全的 package com.lin.springboot01;import org.junit.jupiter.api.Test;public class testThreadLocal {Testpublic void testThreadLocalSetAndGet(){//提供一个ThreadLocal对象ThreadLocal t1 new ThreadLocal();new Thread…

无重复最长字符串(最长无重复子字符串),剑指offer,力扣

目录 原题&#xff1a; 力扣地址&#xff1a; 我们直接看题解吧&#xff1a; 解题方法&#xff1a; 难度分析&#xff1a; 难度算中下吧&#xff0c;这个总体不算很难&#xff0c;而且滑动窗口&#xff0c;以及哈希都比较常见 审题目事例提示&#xff1a; 解题思路&#xff08;…