01-Math



方法说明
static int,l,f,d abs(int,l,f,d a)返回 a 的绝对值
static int,l,f,d max(int,l,f,d x,int,l,f,d y)返回 x 和 y 中的最大值
static int,l,f,d min(int,l,f,d x,int,l,f,d y)返回 x 和 y 中的最小值
static double ceil(double a)返回大于或等于 a 的最小整数
static double floor(double a)返回小于或等于 a 的最大整数
static double rint(double a)返回最接近 a 的整数值,如果有两个同样接近的整数,则结果取偶数
static int round(float a)将参数加上 1/2 后返回与参数最近的整数
static long round(double a)将参数加上 1/2 后返回与参数最近的整数,然后强制转换为长整型
static double sin(double a)返回角的三角正弦值,参数以孤度为单位
static double cos(double a)返回角的三角余弦值,参数以孤度为单位
static double asin(double a)返回一个值的反正弦值,参数域在 [-1,1],值域在 [-PI/2,PI/2]
static double acos(double a)返回一个值的反余弦值,参数域在 [-1,1],值域在 [0.0,PI]
static double tan(double a)返回角的三角正切值,参数以弧度为单位
static double atan(double a)返回一个值的反正切值,值域在 [-PI/2,PI/2]
static double toDegrees(double angrad)将用孤度表示的角转换为近似相等的用角度表示的角
staticdouble toRadians(double angdeg)将用角度表示的角转换为近似相等的用弧度表示的角
static double exp(double a)返回 e 的 a 次幂
static double pow(double a,double b)返回以 a 为底数,以 b 为指数的幂值
static double sqrt(double a)返回 a 的平方根
static double cbrt(double a)返回 a 的立方根
static double log(double a)返回 a 的自然对数,即 lna 的值
static double log10(double a)返回以 10 为底 a 的对数

常用方法:

  abs(); ceil();  floor(); round(); max();  pow();  random();

	System.out.println("E 常量的值:" + Math.E);
	System.out.println("PI 常量的值:" + Math.PI);
	
	System.out.println("10 和 20 的较大值:" + Math.max(10, 20));
	System.out.println("15.6 和 15 的较小值:" + Math.min(15.6, 15));
	System.out.println("-12 的绝对值:" + Math.abs(-12));
	
	Scanner input = new Scanner(System.in);
	System.outprintln("请输入一个数字:");
	double num = input.nextDouble();
	System.out.println("大于或等于 "+ num +" 的最小整数:" + Math.ceil(num));
	System.out.println("小于或等于 "+ num +" 的最大整数:" + Math.floor(num));
	System.out.println("将 "+ num +" 加上 0.5 之后最接近的整数:" + Math.round(num));
	System.out.println("最接近 "+num+" 的整数:" + Math.rint(num));
	
	System.out.println{"90 度的正弦值:" + Math.sin(Math.PI/2));
	System.out.println("0 度的余弦值:" + Math.cos(0));
	System.out.println("1 的反正切值:" + Math.atan(l));
	System.out.println("120 度的弧度值:" + Math.toRadians(120.0));
	
	System.out.println("4 的立方值:" + Math.pow(4, 3));
	System.out.println("16 的平方根:" + Math.sqrt(16));
	System.out.println("10 为底 2 的对数:" + Math.log1O(2));

02-System


System 类的成员变量

  System 类有 3 个静态成员变量,分别是 PrintStream out、InputStream in 和 PrintStream err。

PrintStream out

  标准输出流。此流已打开并准备接收输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
  例如,编写一行输出数据的典型方式是:
System.out.println(data);
  其中,println 方法是属于流类 PrintStream 的方法,而不是 System 中的方法。

InputStream in

  标准输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。

PrintStream err

  标准的错误输出流。其语法与 System.out 类似,不需要提供参数就可输出错误信息。也可以用来输出用户指定的其他信息,包括变量的值。

  例 1

  编写一个 Java 程序,使用本节介绍的 System 类实现从键盘输入字符并显示出来。 具体实现代码如下:
public static void main(String[] args) {    
	System.out.println("请输入字符,按回车键结束输入:");
	int c;
	try {            
		c = System.in.read();
		// 读取输入的字符            
		while(c != '\r') {    
			// 判断输入的字符是不是回车                
			System.out.print((char) c);   
			// 输出字符                
			c = System.in.read();            
		}        
	} catch(IOException e) {
		System.out.println(e.toString());        
	} finally { 
		System.err.println();        
	}    
}

  以上代码中,System.in.read() 语句读入一个字符,read() 方法是 InputStream 类拥有的方法。变量 c 必须用 int 类型而不能用 char 类型,否则会因为丢失精度而导致编译失败。

  以上的程序如果输入汉字将不能正常输出。如果要正常输出汉字,需要把 System.in 声明为 InputStreamReader 类型的实例,最终在 try 语句块中的代码为:

InputStreamReader in = new InputStreamReader(System.in, "GB2312");
c = in.read();
	while(c != '\r') {
	System.out.print((char) c);
	c = in.read();
}

  如上述代码所示,语句 InputStreamReader in=new InputStreamReader(System.in,"GB2312") 声明一个新对象 in,它从 Reader 继承而来,此时就可以读入完整的 Unicode 码,显示正常的汉字。

System 类的成员方法

  System 类中提供了一些系统级的操作方法,常用的方法有 arraycopy()、currentTimeMillis()、exit()、gc() 和 getProperty()。

  1. arraycopy() 方法

  该方法的作用是数组复制,即从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。该方法的具体定义如下:
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
  其中,src 表示源数组,srcPos 表示从源数组中复制的起始位置,dest 表示目标数组,destPos 表示要复制到的目标数组的起始位置,length 表示复制的个数。

  例 2

  下面的示例代码演示了 arraycopy() 方法的使用:

public static void main(String[] args) {
	char[] srcArray = {'A','B','C','D'};
	char[] destArray = {'E','F','G','H'};
	System.arraycopy(srcArray,1,destArray,1,2);
	System.out.println("源数组:");
	for(int i = 0;i < srcArray.length;i++) {
		System.out.println(srcArray[i]); 
	}        
	System.out.println("目标数组:");
	for(int j = 0;j < destArray.length;j++) {
		System.out.println(destArray[j]);        
	}    
}

  如上述代码,将数组 srcArray 中,从下标 1 开始的数据复制到数组 destArray 从下标 1 开始的位置,总共复制两个。也就是将 srcArray[1] 复制给 destArray[1],将 srcArray[2] 复制给 destArray[2]。这样经过复制之后,数组 srcArray 中的元素不发生变化,而数组 destArray 中的元素将变为 E、B、C、 H,下面为输出结果:

源数组:
A
B
C
D
目标数组:
E
B
C
H

  2. currentTimeMillis() 方法

  该方法的作用是返回当前的计算机时间,时间的格式为当前计算机时间与 GMT 时间(格林尼治时间)1970 年 1 月 1 日 0 时 0 分 0 秒所差的毫秒数。一般用它来测试程序的执行时间。例如:
long m = System.currentTimeMillis();

  上述语句将获得一个长整型的数字,该数字就是以差值表达的当前时间。

  例 3

  使用 currentTimeMillis() 方法来显示时间不够直观,但是可以很方便地进行时间计算。例如,计算程序运行需要的时间就可以使用如下的代码:
public static void main(String[] args) {
	long start = System.currentTimeMillis();
    for(int i = 0;i < 100000000;i++) {
        int temp = 0;        
    }        
    long end = System.currentTimeMillis();
    long time = end - start;
    System.out.println("程序执行时间" + time + "秒");
}

  上述代码中的变量 time 的值表示代码中 for 循环执行所需要的毫秒数,使用这种方法可以测试不同算法的程序的执行效率高低,也可以用于后期线程控制时的精确延时实现。

  3. exit() 方法

  该方法的作用是终止当前正在运行的 Java 虚拟机,具体的定义格式如下:
public static void exit(int status)

  其中,status 的值为 0 时表示正常退出,非零时表示异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。

  4. gc() 方法

  该方法的作用是请求系统进行垃圾回收,完成内存中的垃圾清除。至于系统是否立刻回收,取决于系统中垃圾回收算法的实现以及系统执行时的情况。定义如下:
public static void gc()

  5. getProperty() 方法

  该方法的作用是获得系统中属性名为 key 的属性对应的值,具体的定义如下:
public static String getProperty(String key)

  系统中常见的属性名以及属性的说明如表 1 所示。

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

  例 4

  下面的示例演示了 getProperty() 方法的使用。
public static void main(String[] args) {
	String jversion = System.getProperty("java.version");
	String oName = System.getProperty("os.name");
	String user = System.getProperty("user.name");
	System.out.println("Java 运行时环境版本:"+jversion);
	System.out.println("当前操作系统是:"+oName);
	System.out.println("当前用户是:"+user);
}

  运行该程序,输出的结果如下:

Java 运行时环境版本:17.0.4.1
当前操作系统是:Windows 11
当前用户是:QCQCQC

03-Runtime


一、Runtime类的作用

  用来获取当前虚拟机的运行环境

二、Runtime类的常用方法

  在使用runtime类前,需要获取对象:Runtime getRuntime()

方法作用
exit()停止虚拟机
availableProcessors()获取CPU线程数
maxMemory()虚拟机从操作系统获取的内存大小
totalMemory()虚拟机已经获取的内存大小
freeMemory()虚拟机的剩余内存大小
exec(String command)运行CMD命令
        Runtime r1 =  Runtime.getRuntime();

        System.out.println("总线程数:" + r1.availableProcessors());
        System.out.println("可以获取的最大内存:" +r1.maxMemory() / 1024 / 1024);
        System.out.println("已经获取的内存大小:" +r1.totalMemory() / 1024 / 1024);
        System.out.println("剩余内存大小:" +r1.freeMemory() / 1024 / 1024);
        r1.exec("notepad");

04-Object&Objects


一、什么是Object

  object是java中的顶级父类,所有类都间接或者直接继承于他

  因为Object类中的方法可以被所有子类访问,所以我们需要学习object类和其中的方法

方法说明
Object clone()创建与该对象的类相同的新对象
boolean equals(Object)比较两对象是否相等
void finalize()当垃圾回收器确定不存在对该对象的更多引用时,对象垃圾回收器调用该方法
Class getClass()返回一个对象运行时的实例类
int hashCode()返回该对象的散列码值
void notify()激活等待在该对象的监视器上的一个线程
void notifyAll()激活等待在该对象的监视器上的全部线程
String toString()返回该对象的字符串表示
void wait()在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待

二、常用方法

  1.toString()

    返回对象的字符串表达形式,在自定义对象时通常需要重写该方法

// 定义Demo类,实际上继承Object类
class Demo {
	}
public class ObjectDemo01 {
	public static void main(String[] args) {
		Demo d = new Demo(); // 实例化Demo对象
		System.out.println("不加toString()输出:" + d);
		System.out.println("加上toString()输出:" + d.toString());
	}
}

  2.equals()

    比较两个对象是否相等

    在Java自带的类中都已经重写此方法,比如在字符串比较时比较内容

     例:在这里使用 equals() 方法将用户输入的字符串与保存 admin 的字符串对象进行比较,具体的代码如下:
import java.util.Scanner;
public class Test01 {
// 验证用户名和密码    
	public static boolean validateLogin(String uname, String upwd) {
		// 比较两个 String 对象                  
			return uname.equals("admin") && upwd.equals("admin");
	}   
	public static void main(String[] args) {   
		Scanner input = new Scanner(System.in);
		System.out.println("用户名:");
		String username = input.next();
		// 获取用户输入的用户名        
		System.out.println("密码:");
		String pwd = input.next();
		// 获取用户输入的密码        
		boolean con = validateLogin(username, pwd);
		if (con) {
			System.out.println("登录成功!");        
		} else {            
			System.out.println("用户名或密码有误!");       
		}    
	}
}

调用者不同的区别:

        String s = "abc";
        StringBuilder sb = new StringBuilder("abc");
        System.out.println(s.equals(sb));//false
        System.out.println(sb.equals(s));//false

 在第一个equals调用中:
    * <mark style="background: #BBFABBA6;">因为equals方法是被s调用的,而且s是字符串</mark>
    * <mark style="background: #BBFABBA6;">所以equals要看String类中的</mark>
    * 字符串中的equals方法,先判断参数是否为字符串
    * <mark style="background: #ABF7F7A6;">如果是字符串,在比较内部的属性</mark>
    * 但是如果参数不是字符串,直接返回false
在第二个equals调用中:
    * <mark style="background: #BBFABBA6;">因为equals方法是被sb调用的,而且sb是StringBuilder类型</mark>
    * <mark style="background: #BBFABBA6;">所以这里的equals方法要看StringBuilder中的</mark>
    * 那么在StringBuilder中,没有重写equals方法
    * 使用的是object中的
    * <mark style="background: #ABF7F7A6;">在object当中默认是使用==比较两个对象的地址值</mark>
    * 而这里的s和sb记录的地址值是不一样的,所以返回false

  3.clone()

    对象克隆,返回一个与该对象的类相同的对象

  4.getclass()

    getClass() 方法返回对象所属的类,是一个 Class 对象。通过 Class 对象可以获取该类的各种信息,包括类名、父类以及它所实现接口的名字等。

public class Test02 {
    public static void printClassInfo(Object obj) {
        // 获取类名
        System.out.println("类名:" + obj.getClass().getName());
        // 获取父类名
        System.out.println("父类:" + obj.getClass().getSuperclass().getName());
        System.out.println("实现的接口有:");
        // 获取实现的接口并输出
        for (int i = 0; i < obj.getClass().getInterfaces().length; i++) {
            System.out.println(obj.getClass().getInterfaces()[i]);
        }
    }
    public static void main(String[] args) {
        String strObj = new String();
        printClassInfo(strObj);
    }
}
该程序的运行结果如下:
类名:java.lang.String
父类:java.lang.Object
实现的接口有:
interface java.io.Serializable
interface java.lang.Comparable
interface java.lang.CharSequence

05-浅克隆、深克隆和对象工具类Objects


1、什么叫Java浅拷贝?

 浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。

2、什么叫Java深拷贝?

 深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制。深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

3、Java浅拷贝和深拷贝的区别是什么?

 通俗来讲浅拷贝的复制其引用,当引用指向的值改变时也会跟着变化;而深拷贝则是与原来的对象完全隔离,互补影响。

4、思维导图

Java浅拷贝与深拷贝

5、测试用例分析

浅拷贝测试用例

public class ShallowExperience {
    private String skill;

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public void setShallowExperience(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return skill;
    }
}

public class ShallowCloneTest implements Cloneable {

    private int age;
    private ShallowExperience shallowExperience;

    public ShallowCloneTest() {
        this.age = 10;
        this.shallowExperience = new ShallowExperience();
    }

    public ShallowExperience getExperience() {
        return shallowExperience;
    }

    public void setShallowExperience(String skill) {
        shallowExperience.setShallowExperience(skill);
    }

    public void show() {
        System.out.println(shallowExperience.toString());
    }

    public int getAge() {
        return age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (ShallowCloneTest) super.clone();
    }
}

public class TestMain {

    public static void main(String[] args) throws CloneNotSupportedException {
        System.out.println("======浅拷贝======");
        shallowCloneTest();
    }

    /**
     * 浅拷贝测试用例
     *
     * @throws CloneNotSupportedException
     */
    private static void shallowCloneTest() throws CloneNotSupportedException {
        ShallowCloneTest test = new ShallowCloneTest();
        test.setShallowExperience("我是小明,我精通Java,C++的复制粘贴");
        test.show();
        ShallowCloneTest cloneTest = (ShallowCloneTest) test.clone();
        cloneTest.show();
        cloneTest.setShallowExperience("我是小明的副本,我精通Java,C++");
        cloneTest.show();
        test.show();
        System.out.println(cloneTest.getAge());
    }
}

//运行结果
======浅拷贝======
我是小明,我精通Java,C++的复制粘贴
我是小明,我精通Java,C++的复制粘贴
我是小明的副本,我精通Java,C++
我是小明的副本,我精通Java,C++

深拷贝测试用例

public class DeepExperience implements Cloneable{
    private String skill;

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public void setDeepExperience(String skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return skill;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class DeepCloneTest implements Cloneable {

    private int age;
    private DeepExperience deepExperience;

    public DeepCloneTest() {
        this.age = 10;
        this.deepExperience = new DeepExperience();
    }

    public DeepExperience getExperience() {
        return deepExperience;
    }

    public void setDeepExperience(String skill) {
        deepExperience.setDeepExperience(skill);
    }

    public void show() {
        System.out.println(deepExperience.toString());
    }

    public int getAge() {
        return age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        DeepCloneTest deepCloneTest = (DeepCloneTest) super.clone();
        deepCloneTest.deepExperience = (DeepExperience) deepCloneTest.getExperience().clone();
        return deepCloneTest;
    }
}

public class TestMain {

    public static void main(String[] args) throws CloneNotSupportedException {
        System.out.println("======深拷贝======");
        deepCloneTest();
    }

    /**
     * 深拷贝测试用例
     *
     * @throws CloneNotSupportedException
     */
    private static void deepCloneTest() throws CloneNotSupportedException {
        DeepCloneTest test = new DeepCloneTest();
        test.setDeepExperience("我是小明,我精通Java,C++的复制粘贴");
        test.show();
        DeepCloneTest cloneTest = (DeepCloneTest) test.clone();
        cloneTest.show();
        cloneTest.setDeepExperience("我是小明的副本,我精通Java,C++");
        cloneTest.show();
        test.show();
        System.out.println(cloneTest.getAge());
    }
}

//运行结果
======深拷贝======
我是小明,我精通Java,C++的复制粘贴
我是小明,我精通Java,C++的复制粘贴
我是小明的副本,我精通Java,C++
我是小明,我精通Java,C++的复制粘贴

Java 浅拷贝与深拷贝_xing.tang的博客-CSDN博客

在Java中clone方法属于浅拷贝


Objects工具类

一、什么是Objects类

  Objects是jdk1.7添加的一个工具类,进行一些常用的检查操作。

    此类包含static实用程序方法,用于操作对象或在操作前检查某些条件。

    这些实用程序包括nullnull方法,用于计算对象的哈希代码,返回对象的字符串,比较两个对象,以及检查索引或子范围值是否超出范围。

二、三个方法

  1.equals(Object o1,Object o2):

    作用:先做非空判断,再比较两个对象

  2.inNull(Object o):

    作用:判断对象是否为空,为空就返回true

  3.nonNull(Object o):

    作用:判断对象是否为null,和前者返回值相反


06-BigInteger


一、什么是BigInteger

  BigInteger隶属于java.math,是进行大数的高精度运算的一个类,是大整数在java中的表现形式

  方法摘要:

Modifier and TypeMethod and Description
BigIntegerabs() 返回一个BigInteger,它的值是此BigInteger的绝对值。
BigIntegeradd(BigInteger val) 返回值为 (this + val)
BigIntegerand(BigInteger val) 返回值为 (this & val)
BigIntegerandNot(BigInteger val) 返回值为 (this & ~val)
intbitCount() 返回与其符号位不同的BigInteger的二进制补码表示中的位数。
intbitLength() 返回此BigInteger的最小二进制补码表示中的位数, 包括符号位。
bytebyteValueExact() 将此 BigInteger转换为 byte ,检查丢失的信息。
BigIntegerclearBit(int n) 返回一个BigInteger,其值等于此BigInteger,指定的位被清零。
intcompareTo(BigInteger val) 将此BigInteger与指定的BigInteger进行比较。
BigIntegerdivide(BigInteger val) 返回值为 (this / val)
BigInteger[]divideAndRemainder(BigInteger val) 返回两个BigInteger的数组,其中包含 (this / val)后跟 (this % val)
doubledoubleValue() 将此BigInteger转换为 double
booleanequals(Object x) 将此BigInteger与指定的对象进行比较以实现相等。
BigIntegerflipBit(int n) 返回一个BigInteger,其值等于此BigInteger,指定的位被翻转。
floatfloatValue() 将此BigInteger转换为 float
BigIntegergcd(BigInteger val) 返回一个BigInteger,其值是 abs(this)abs(val)
intgetLowestSetBit() 返回此BigInteger中最右(最低位)一位的索引(最右边一位右侧的零位数)。
inthashCode() 返回此BigInteger的哈希码。
intintValue() 将此BigInteger转换为 int
intintValueExact() 将此 BigInteger转换为 int ,检查丢失的信息。
booleanisProbablePrime(int certainty) 返回 true如果这个BigInteger可能是素数, false如果它是绝对复合。
longlongValue() 将此BigInteger转换为 long
longlongValueExact() 将此 BigInteger转换为 long ,检查丢失的信息。
BigIntegermax(BigInteger val) 返回此BigInteger和 val
BigIntegermin(BigInteger val) 返回此BigInteger和 val
BigIntegermod(BigInteger m) 返回值为 (this mod m )。
BigIntegermodInverse(BigInteger m) 返回值为 (this -1 mod m)
BigIntegermodPow(BigInteger exponent, BigInteger m) 返回值为 (thisexponent mod m)的BigInteger
BigIntegermultiply(BigInteger val) 返回值为 (this * val)
BigIntegernegate() 返回值为 (-this)
BigIntegernextProbablePrime() 返回大于这个 BigIntegerBigInteger的第一个整数。
BigIntegernot() 返回值为 (~this)
BigIntegeror(BigInteger val) 返回值为 (this | val)
BigIntegerpow(int exponent) 返回值为 (thisexponent)的BigInteger
static BigIntegerprobablePrime(int bitLength, Random rnd) 返回一个正的BigInteger,它可能是素数,具有指定的位长度。
BigIntegerremainder(BigInteger val) 返回值为 (this % val)
BigIntegersetBit(int n) 返回一个BigInteger,其值等于具有指定位集合的BigInteger。
BigIntegershiftLeft(int n) 返回值为 (this << n)
BigIntegershiftRight(int n) 返回值为 (this >> n)
shortshortValueExact() 将此 BigInteger转换为 short ,检查丢失的信息。
intsignum() 返回此BigInteger的signum函数。
BigIntegersubtract(BigInteger val) 返回值为 (this - val)
booleantestBit(int n) 返回 true当且仅当指定的位被设置。
byte[]toByteArray() 返回一个包含此BigInteger的二进制补码表示的字节数组。
StringtoString() 返回此BigInteger的十进制字符串表示形式。
StringtoString(int radix) 返回给定基数中BigInteger的String表示形式。
static BigIntegervalueOf(long val) 返回一个BigInteger,其值等于指定的 long
BigIntegerxor(BigInteger val) 返回值为 (this ^ val)

二、常用构造方法

  1.BigInteger(int num, Random rnd) 获取堆积大整数范围0~2的num次-1

  2.BigInteger(String val) 获取指定大整数

  3.BigInteger(String val,int radix)获取指定进制的大整数

三、常用成员方法

  add,subtract,multiply,divide,divideAndRemainder,equals,pow,max/min,intValue

四、小结

  1.如果biginteger表示的数没有超出long的范围,可以用静态方法获取。

  2.如果biginteger表示的超出long的范围,可以用构造方法获取。

  3.对象一旦创建,biginteger内部记录的值不能改变。

  4.只要进行计算都会产生一个新的biginteger对象。


07-BigDecima基本使用和原理


BigDecima与BigInteger类似,都用于高精度计算

构造方法:

  可以传入double,也可以传入string,但是传入double可能会不精确

成员方法:

  加:add ,减:subtract ,乘:multiply , 除:divide(四舍五入:RoundingMode.HALF_UP)


08-正则表达式初体验和基本规则


一、什么是正则表达式

  正则表达式(Regular Expression)又称正规表示法、常规表示法,在代码中常简写为 regex、regexp 或 RE,它是计算机科学的一个概念。

  正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作,是一种可以用于模式匹配和替换的规范。一个正则表达式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)组成的文字模式,它用以描述在查找文字主体时待匹配的一个或多个字符串。

案例、

  假如现在要求检验一个qq号码是否正确:6位及20位之内,0不能在开头,必须全部是数字

使用传统方法
        public static void main(){
        	String qq = "1234567890";
        	System.out.println(check(qq));
        }
        public static boolean check(String qq){
        	//长度校验:
        	int len = qq.length();
        	if(len < 6 || len > 20){
            	return false;
        	}
        	//校验不能以0开头
        	if(qq.startsWith("0")){
        	    return false;
        	}
        	//检验是否为全部数字
        	for (int i = 0; i < qq.length(); i++) {
        	    char c = qq.charAt(i);
        	    if(c < '0' || c > '9'){
        	        return false;
        	    }
        	}
        	//假如全部都通过
        	return true;
   	 	}
使用正则表达式
System.out.println(qq.matches("[1-9]\\d{5,19}"));

二、正则表达式的作用

  1.校验字符串是否满足规则

  2.在一段文本中查找满足要求的内容

三、正则表达式的规则

  字符类:

举例匹配目标
[abc]只能是a,b,c,
[^abc][abc]的补集
[a-zA-Z]a到z A到Z,包括边界
[a-d[m-p]]a到d,或者m-p
[a-z&&[def]]a-z和def的交集
[a-z&&[^bc]]a-z和非bc的交集
[a-z&&[^m-p]]a-z和除了m-p的交集

  特殊字符:

特殊字符说明
$匹配一行的结尾。要匹配 $ 字符本身,请使用\$
^匹配一行的开头。要匹配 ^ 字符本身,请使用\^
()标记子表达式的开始和结束位置。要匹配这些字符,请使用\(\)
[]用于确定中括号表达式的开始和结束位置。要匹配这些字符,请使用\[\]
{}用于标记前面子表达式的出现频度。要匹配这些字符,请使用\{\}
*指定前面子表达式可以出现零次或多次。要匹配 * 字符本身,请使用\*
+指定前面子表达式可以出现一次或多次。要匹配 + 字符本身,请使用\+
?指定前面子表达式可以出现零次或一次。要匹配 ?字符本身,请使用\?
.匹配除换行符\n之外的任何单字符。要匹配.字符本身,请使用\.
\用于转义下一个字符,或指定八进制、十六进制字符。如果需匹配\字符,请用\\
|指定两项之间任选一项。如果要匹配字符本身,请使用\|

  预定义字符:

举例匹配目标
.任何字符
\d一个数字:[0-9]
\D非数字:[^0-9]
\s一个空白字符:[\t\n\x0B\f\r]
\S非空白字符:[^\s]
\w[a-zA-Z_0-9]英文,数字,下划线
\W[^\w]一个非单词字符

  出现次数控制:

举例匹配目标
X?X,一次或者0次
X*X,零次或者多次
X+X,一次或者多次
XX,正好n次
X{n,}X,至少n次
X{n,m}X,至少n但不超过m

  数量标识符的模式:

贪婪模式勉强模式占用模式说明
X?X??X?+X表达式出现零次或一次
X*X*?X*+X表达式出现零次或多次
X+X+?X++X表达式出现一次或多次
XX?X+X表达式出现 n 次
X{n,}X{n,}?X{n,}+X表达式最少出现 n 次
X{n,m}X{n,m}?X{n,m}+X表达式最少出现 n 次,最多出现 m 次
关于贪婪模式和勉强模式的对比,看如下代码:
String str = "hello,java!";
// 贪婪模式的正则表达式
System.out.println(str.replaceFirst("\\w*" , "■"));  //输出■,java!
// 勉强模式的正则表达式
System.out.println(str.replaceFirst("\\w*?" , "■"")); //输出■hello, java!
当从“hello java!”字符串中查找匹配\\w*子串时,因为\w*使用了贪婪模式,数量表示符*会一直匹配下去,所以该字符串前面的所有单词字符都被它匹配到,直到遇到空格,所以替换后的效果是“■,Java!”;如果使用勉强模式,数量表示符*会尽量匹配最少字符,即匹配 0 个字符,所以替换后的结果是“■hello,java!”。

四、正则表达式的使用

  1.获取正则表达式的对象

Pattern p = Pattern.compile("Java\\d{0,2}");

  2.准备需要处理的字符串

String str = "Java自从95年问世以来,迭代了很多版本,目前企业中使用最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在不久的未来,Java17也会逐渐登上历史的舞台!";

  3.获取文本匹配器的对象

    拿着m去匹配str,找符合p规则的子串

Matcher m = p.matcher(str);

  4.循环捕获

while (m.find()) {
	String s = m.group();
	System.out.println(s);
}

五、案例:爬取网络数据

        //爬取网络数据:
        //1.创建URL对象:
        URL url = new URL("http://sfz.uzuzuz.com/?region=350781&birthday=19640307&sex=2&num=19&r=86");

        //链接网址
        URLConnection conn = url.openConnection();

        //创建一个对象去读取网络中的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        //创建正则表达式对象
        Pattern p2 = Pattern.compile("[1-9]\\d{17}");
        //在读取的时候每次读取一整行
        String line;
        while((line = br.readLine()) != null){
            Matcher m2 = p2.matcher(line);
            while(m2.find()) {
                System.out.println(m2.group());
            }
        }

六、捕获分组

  分组就是小括号,将表达式分组后,每个组视为一个整体

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

  规则:

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

    规则2. 从 左括号为基准 ,最左边的是第一组,其次为第二组

    如(\\d+(\\d+))(\\d+)中有三个左括号,所以有三组

    (\\组号)表示在正则内部将该组的内容重复一次

    捕获分组:将某一组的数据捕获出来,再用一次

  案例:

//需求一、判断一个字符串的开始字符和结束字符是否一致,只考虑一个字符
        String regex1 = "(.).+\\1";
        System.out.println("a123a".matches(regex1));
        System.out.println("b9871a".matches(regex1));
//需求二、判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
        String regex2 = "(.+).+\\1";
        System.out.println("abc123abc".matches(regex2));
        System.out.println("bdc9871adc".matches(regex2));
//需求三、判断一个字符串的开始部分和结束部分是否一致,开始部分内部每个字符也要一致
        String regex3 = "((.)\\2*).+\\1";
        System.out.println("aaa123aaa".matches(regex3));
        System.out.println("aabc12cbaa".matches(regex3));
        System.out.println("babc12cbaa".matches(regex3));

在正则表达式外面使用 $ 获取分组

//在正则表达式外用($组号)获取分组
		String str1 = "我要要要学学学学编编编编编编编程程程程程程程";
		System.out.println(str1.replaceAll("(.)\\1+","$1"));

七、非捕获分组

/*非捕获分组:仅仅把数据括起来,不占用组号

*(? : 正则) 获取所有

*(? = 正则) 获取前面部分

*(? ! 正则) 获取不是指定内容的前面部分

	    String regex4 = "[1-9]\\d{16}(?:d|X|x)\\1";//不会指定组号,所以红色错误提示
		System.out.println("350781196403073866".matches(regex4));