API的概念
API(Application Programming Interface):应用程序编程接口
-
简单理解:API就是别人已经写好的东西,我们不需要自己编写,直接使用即可。
-
Java API:指的就是JDK中提供的各种功能的Java类
这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可
API帮助文档:帮助开发人员更好地使用API和查询API的一个工具。
API帮助文档可以通过Java官网进行下载或者直接访问。
使用方法:
- 打开API帮助文档。
- 点击显示,并找到索引下面的输入框。
- 在输入框中输入类名并点击显示。
- 查看类所在的包。
- 查看类的描述。
- 查看构造方法。
- 查看成员方法。
常用类
Math
定义:是一个帮助我们用于数学计算的工具类。
本质:私有化构造方法,所有的方法都是静态的。
常用方法:
- abs :获取绝对值
public static int abs(int a);
但是需要注意的是:所取的范围不能超过数据类型的范围,例如:
System.out.println(Math.abs(-2147483648));
//输出结果为-2147483648
由于我们选用的是int类型,范围是-2147483648-2147483647.
所以-2147483648的绝对值超出了这个范围,所以不会进行取值。
- ceil :向上取整
public static double ceil(double a);
- floor : 向下取整
public static double floor(double a);
- round : 四舍五入
public static int round(float a);
- max : 取二者中的最大值
public static int max(int a,int b);
- pow : 返回a的b次幂的值
public static double pow(double a,double b);
- random : 返回值为double的随机值,范围为[0.0,1.0)
public static double random();
System
System也是一个工具类,提供了一些与系统相关的方法。
常用方法:
- exit : 终止当前运行的Java虚拟机。
public static void exit(int status);
使用情境:当我们需要把整个程序结束的时候,就可以调用这个方法。
System.exit(0);
//括号里面是状态码
//0:表示当前虚拟机是正常停止
//非0:表示当前虚拟机是异常停止
System.out.println("嘿嘿");
如上,后面的那条打印指令就不会执行,而是终止程序。
- currentTimeMillis : 返回当前系统的时间毫秒值形式。
public static long currentTimeMillis();
也就是计算机中的时间原点到执行这个代码时的总共时间,以毫秒为单位。
时间原点(C语言的生日):1970.1.1 00:00:00。
而因为我们处于东八区,所以拥有8个小时的时差,我们的时间原点则是1970.1.1 08:00:00。
这里需要提前知道的知识点:
- 1秒 = 1000毫秒
- 1毫秒 = 1000微秒
- 1微秒 = 1000纳秒
**使用情境:**算出一个程序运行的总时间,也可以对比多个程序的效率高低(结束时间 - 开始时间)
- arraycopy : 数组拷贝
public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数);
-
数据源数组:你要copy的那个数组名
-
起始索引:从第几个开始copy,相当于规定一个copy起始点。
-
目的地数组:将数组copy到的那个数组。
-
起始索引:从这个目的地数组的什么位置开始粘贴这些内容。
-
拷贝个数:想要拷贝的内容数量。
int[] num1 = {1,2,3,4,5,6,7,8,9,10};
int[] num2 = new int[10];
System.arraycopy(num1,0,num2,0,10);
**这段代码的含义:**将num1中的数据从0开始10个数据复制,从num2的0位置开始粘贴。
细节:
- 如果数据源数组和目的地数组都是基本数据类型,那么两者的类型必须保持一致,否则会报错。
- 在拷贝的时候需要考虑数组的长度,如果超出范围也会报错。
- 如果数据源数组和目的地数组都是引用数据类型,那么子类类型可以赋值给父亲类型。
Runtime
Runtime表示当前虚拟机的运行环境。
常用方法:
- getRuntime : 当前系统的运行环境对象。
public static Runtime getRuntime();
由于Runtime是具有私构造方法的类,所以想要调用它的对象不能够用new来创建一个对象。所以想要调用的话,就得用到上面这段代码。
例如:
Runtime r1 = Runtime.getRuntime();
这样就能创建对象了。
- exit : 停止虚拟机。
public void exit(int status);
括号里的值为0时,为正常终止;括号里的值不为0时,为异常终止。
//终止虚拟机
//两种方式:
//1.直接用Runtime调用静态方法创建对象
Runtime.getRuntime().exit(0);
//2.创建一个具体对象后再去调用
Runtime r1 = Runtime.getRuntime();
r1.exit(0);
与System.exit()对比:Runtime.exit是System.exit的底层源码。
- availableProcessors : 获得CPU的线程数。
public int availableProcessors();
//获取CPU的线程数
System.out.println(Runtime.getRuntime().availableProcessors());
- maxMemory : JVM能从系统中获得总内存大小(单位byte)。
public long maxMemory();
- totalMemory : JVM已经从系统中获取总内存大小(单位byte)。
public long totalMemory();
- freeMemory : JVM剩余内存大小(单位byte)。
public long freeMemory();
- exec : 运行cmd命令。
public Process exec(String command);
exec的括号中,以字符串地形式输入指令,例如打开某个应用
Runtime.getRuntime().exec("notepad");
上面就是打开记事本的指令,但是这个时候exec的下面会有红色波浪线,表示异常。
这个时候就可以利用我们在异常中学习的抛出异常和捕获异常来解决这个问题了。
一般遇到自身学识解决不了的异常或问题,我们可以对准那个冒红线的地方,同时摁下Alt + Enter ,能够看到系统为我们建议的解决方案。
运行cmd命令的一些常用指令:
- shutdown :关机
//加上参数才能执行
//例如:
//-s : 默认在一分钟后关机
//-s -t 指定时间 : 多少秒后关机
//-a : 取消关机命令
//-r : 关机并重启
Runtime.getRuntime().exec("shutdown -s -t 3600");
//这个指令为:3600秒之后关机
**使用以上方法时,格式如下:**Runtime.gatRuntime().方法名
Object
Object是Java中的顶级父类。所有的类都直接或者间接地继承于Object类。
- Object的构造方法
public Object() //无参构造
顶级父类中只有无参构造,没有有参构造。
- Object的成员方法
-
- toString
- equals
- clone
- toString
toString
toString : 返回对象的字符串表示形式。
public String toString();
Object obj = new Object();
System.out.println(obj.toString());
//java.lang.Object@1b6d3586
创建一个对象后,直接使用这个方法,就能得到这个类的逻辑地址和物理地址。
**细节:**使用这个打印代码,直接打印这个对象和调用toString方法打印的结果是一样的。
我们来对打印代码进行分析:
- System :类名
- out : 静态变量
- System. out : 获取打印的对象
- println() : 方法
- 参数:表示打印的内容。
**核心逻辑:**当我们打印一个对象的时候,底层会调用对象的toString方法,把对象变成字符串。然后再打印在控制台上,打印完毕换行处理。
**思考:**默认情况下,因为Object类中的toString方法返回的是地址值。所以,默认情况下,打印一个对象的就是地址值。但是,地址值对于我们是没有什么意义的,如果我们想要看到对象内部的属性值,该怎么办呢?
**处理方法:**重写父类Object类中的toString方法。
//toString方法的结论:
//如果我们打印一个对象,想要看到属性值的话,那么就重写toString方法就可以了。
//在重写的方法中,把对象的属性值进行拼接。
equals
equals : 比较两个对象是否相等。
public boolean equals(Object obj);
这里的相等指的是地址值的比较,两个创建出来的对象,都有各自存放的地址值,因此它们不会相等,boolean值为false。
如果我们想要比较的是这两个对象内部的属性值是否相等,可以进行如下操作:
- 按下 Alt + Insert
- 点击equals() and hashCode()
- 不用做任何选择,直接用JDK7中的默认模版,就可以直接重写这个方法了。
这个重写后的方法就是比较的属性值了。
//结论:
//1.如果没有重写equals方法,那么默认使用Object中的方法进行比较,比较的是地址值是否相等。
//2.一般来说地址值对于我们意义不大,所以我们会重写。
//3.不同类中的equals方法所比较的内容也未必相同,所以一般都显示false。
clone
clone : 对象克隆。
protected Object clone(int a);
把A对象的属性值完全拷贝到B对象,也叫对象拷贝,对象复制。
操作方案:
-
通过其他类创建一个对象。
-
克隆这个对象
这里需要注意的事,创建对象的那个类需要实现一个接口:Cloneable接口(里面没有抽象方法)
//Cloneable
//如果一个接口里面没有抽象方法
//表示当前的接口是一个标记性接口
//现在Cloneable表示一旦实现了,那么当前类的对象就可以被克隆
//否则,不能克隆
代码如下:
User u1 = new User(属性值);//这里是用User类创建的对象
User u2 =(User)u1.clone();//这里需要强转,因为重写了toString方法。
**细节:**方法在底层会帮我们创建一个对象,并把原对象的数据拷贝过去。
书写细节:
- 重写Object中的clone方法
- 让javabean类(克隆对象的所属类)实现Cloneable接口
- 创建原对象并调用clone
克隆方式:
- 浅克隆(浅拷贝)【Object中的克隆是浅克隆】
克隆一个对象时,将它的所有数据直接复制粘贴,数据类型和引用类型所拥有的值都一样(地址值一样,数值也一样,甚至数组也是用的同一组数组)。
- 深克隆(深拷贝)
同样创建一个对象,如果是变量数据值或者引用类型数据(String),直接复制粘贴过来。但是数组的话,就会重新创建一个新的数组,再将原对象的数组值复制过去。也就是说,这两个对象的数组数据是独立的,不会相互影响。
**如何将浅克隆改为深克隆?**再次重写clone方法。
//先把克隆对象中的数组获取出来
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 gson = new Gson();
//把对象变成一个字符串。
String s = gson.toJson(u1);
//再打字符创变回对象就可以了
User user = gson.fromJson(s,User.class);
//打印对象
System.out.println(user);
Objects
Objects是一个工具类,提供了一些方法去完成一些功能。
成员方法:
- equals : 先做非空判断,比较两个对象。
public static boolean equals(Object a,Object b);
细节:
- 方法的底层会判断s1是否为null,如果为null,直接返回false。
- 如果s1不是null,那么就利用s1再次调用equals方法。
- 此时s1是会调用所属类的equals方法。
- 若没有重写,比较地址值,若重写了,比较属性值。
- isNull : 判断对象是否为null,若是则true,若不是则反之。
public static boolean isNull(Object obj);
- nonNull : 判断对象是否为null,结果与isNul相反。
public static boolean nonNull(Object obj);
BigInteger
在Java中,整数有四种类型:byte , short , int , long。
在底层占用字节个数:
- byte 1个
- short 2个
- int 4个
- long 8个
BIgInteger的方法都与大整数有关,不涉及浮点数。
构造方法
- 获得随机大整数,范围:[0 ~2^n-1];
public BigInteger(int num,Random rnd);
这里需要注意,Random需要在使用这个指令前创建一个对象,不然无法调用。
Random r = new Random();
BigInteger bd1 = new BigInteger(4,r);
System.out.println(bd1);
- 获取指定的大整数
public BigINteger(String val);
既然是String数据类型,我们需要加入引号,并且其中的数据一定得是整数。
BigInteger bd2 = new BigInteger("100");
System.out.println(bd2);
- 获取指定进制的大整数
public BigeInteger(String val,int radix);
细节:
- 字符串中的数字是整数
- 字符串中的数字必须要跟进制吻合。例如二进制中,只能有0和1,写其他的就报错。
下面就是一个二进制的大整数:
BigInteger bd3 = new BigInteger("100",2);
System.out.println(bd3);
- 静态方法获取BigInteger的对象,内部有优化
public static BigInteger valueOf(long val);
这个方法和第二个方法很相似,但是也是很有区别的:
- 它能表示的范围比较小,在long的取值范围之内,如果超出long的范围就不行了。
- 在内部对常用的数字:-16
16进行了优化,提前把 -1616 先创建好BigInteger的对象,如果多次获取不会重新创建新的。简而言之就是,即使是创建了两个对象,但只要这两个对象的值在这个范围内,它们的地址值相同。
**还有一点值得注意:**只要进行计算都会产生一个新的BigInteger对象。
成员方法
- 加法
public BigInteger add(BigInteger val);
在进行运算之前,需要创建出两个对象。
//1.创建两个对象
BigInteger bd1 =BigInteger.valueOf(10);
BigInteger bd2 =BigInteger.valueOf(5);
现在就可以利用方法进行运算了。
//2.加法
BigInteger bd3 =bd1.add(bd2);
System.out.println(bd3);
下面的减乘除一致。
- 减法
public BigInteger Subtract(BigInteger val);
- 乘法
public BigInteger multiply(BigInteger val);
- 除法,获取商
public BigInteger divide(BigInteger val);
- 除法,获取商和余数
public BigInteger divideAndRemainder(BigInteger val);
//3.除法,获取商和余数
BigInteger[] arr= bd1.divideAndRemainder(bd2);
System.out.println(arr[0]);
System.out.println(arr[1]);
这里需要创建一个数组,并且这个数组的长度只有2,0是商,1是余数。
- 比较是否相同
public boolean equals(Object x);
//4.比较是否相同
boolean result = bd1.equals(bd2);
System.out.println(result);
- 次幂
public BigInteger pow(int exponent);
//5.次幂
BigInteger bd4 = bd1.pow(2);
System.out.println(bd4);
这里的就是表示bd1的2次幂。
- 返回较大值/较小值
public BigInteger max/min(BigInteger val);
- 转为int类型整数,超出范围数据有误
public int intValue(BigInteger val);
不仅可以转换为int类型,也可以转换为其他类型:
- doubleValue double类型
- longValue long类型
底层储存方式
- 首先将一个数进行二进制化,转换为32位为一组的数组。
- 之后将这三组代码进行转码,要注意,使用的是补码方式。
- 最后结果为:[第一组,第二组,第三组, ...]
存储上限:
数组中最多能存储元素个数:21亿多。
数组中每一位能表示的数字:42亿多。
BigInteger能表示的最大数字为:42亿的21亿次方。
BigDecimal
之前刚接触浮点数的时候就说过,我们自己计算的浮点数是存在误差的,这里我们就要使用到BigDecimal来进行运算了。
误差产生的原因
计算机中,存储数据使用的都是二进制,所以浮点数也同样如此。但是它们的bit位是有限的。
float:
- 占用字节数:4个字节
- 总bit位数:32个bit位
- 小数部分bit位数:23个bit位
double:
- 占用字节数:8个字节
- 总bit位数:64个bit位
- 小数部分bit位数:52个bit位
由此可见,若是超出了这个bit范围,多出部分就会被省去,这就是产生误差的原因。
BigDecimal的作用
- 用于小数的精确计算
- 用来表示很大的小数
构造方法
- 构造方法获取BigDecimal对象
//1.
public BigDecimal(double val);
//2.
public BigDecimal(String val);
第一种用double类型来创建对象,也是可能不精确的,不建议使用。
第二种用String类型来创建对象,能够得到精确的数据,并且即便计算之后也是精确的。
BigDecimal bd1 = new BigDecimal(0.1);
BigDecimal bd2 = new BigDecimal("0.2");
System.out.println(bd1);
System.out.println(bd2);
//第一个结果:0.1000000000000000055511151231257827021181583404541015625
//第二个结果:0.2
- 静态方法获得对象
public static BigDecimal valueOf(double val);
BigDecimal bd3 = BigDecimal.valueOf(10);
这里是可以选择数据类型的,long或是double都可以。
String类型和静态方法的区别:
- 如果要表示的数字不大,没有超出double的取值范围,建议使用静态方法。
- 如果要表示的数字比较大,超出了double的取值范围,建议使用String类型。
- 如果我们传递的是0 ~ 10之间的整数,那么方法会返回已经创建好的对象,不会重新创建对象。(仅包含整数)
成员方法
- 加法
public BigDecimal add(BigeDecimal val);
- 减法
public BigDecimal subtract(BigeDecimal val);
- 乘法
public BigDecimal multiply(BigeDecimal val);
- 除法
public BigDecimal divide(BigeDecimal val);
- 除法(除不尽)
public BigDecimal divide(BigeDecimal val,精确几位,舍入模式);
BigDecimal bd3 = new BigDecimal("0.3");
BigDecimal bd4 = bd2.divide(bd3,2,RoundingMode.HALF_DOWN);
System.out.println(bd4);
这里的舍入模式需要使用RoundingMode这个类中的HALF_DOWN方法来调用,中间的精确位直接使用int类型的数据就可以了。
这里我们可以对RoundingMode类进行一些常用扩展:
- UP :远离零方向舍入的舍入模式
- DOWN :向零方向舍入的舍入模式
- CEILING : 向正无限大方向舍入的舍入模式
- FLOOR : 向负无限大方向舍入的舍入模式
- HALF_UP : 这就是我们常用的四舍五入法。
- HALF_DOWN : 这个可以被称作"五舍六入",被舍入部分>0.5时,才向上取整。
底层储存方式
将每个部分都各自取出保存:
例如:0.123 存储方式:[0,1,2,3]。
之后再将这些数据的编码号代替这些数据。(负号也算,但是正数不算)
最后存储的数据是用byte类型进行保存的。
正则表达式
作用一
- 校验字符串是否满足规则
正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性。
这是matches的方法,使用格式为:字符串.matches(规则)。
字符类
- [abc] 只能是a,b,c.
- [^abc] 除了a,b,c之外的任何字符
- [a-zA-Z] a到z,A到Z,包括范围
- [a-d[m-p]] a到d,或m到p
- [a-z&&[def]]a-z和def的交集(def)
"a".matches("[abc]");//true
"ab".matches("[abc]");///false
这里需要注意,正则表达式是从左到右一个一个去匹配的,这个匹配的只有一个标准,但是字符串里面有两个字符。
"ab".matches("[abc][abc]");//true
这样书写才是正确的。
预定义字符
- . 任何字符
- \d 一个数字:[0-9]
- \D 非数字
- \s 一个空白字符:[\t \n \x0B \f \r]
- \S 非空白字符
- \w [a-zA-Z_0-9] 英文、数字、下划线
- \W 一个非单词字符
数量词
- X? X,一次或0次
- X* X,零次或多次
- X+ X,依次或多次
- X {n} 正好n次
- X{n,} 至少n次
- X{n,m}至少n但不超过m次
作用二
- 在一段文本中查找满足要求的内容
这也是我们所熟知的爬虫,通过一些关键字来查找我们自己所需的信息。 这里需要运用到几个类:
- Pattern : 表示正则表达式。
- Matcher : 文本匹配器,作用按照正则表达式的规则去读取字符串,从头开始读取,在大串中去寻找符合要求的内容。
//创建正则表达式的对象
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();
//方法底层会根据find方法记录的索引进行字符串的截取
//subString(起始索引,结束索引);
//并且有一个特点为包头不包尾
//例如(0,4),就不包含4
String s1 = m.group();
System.out.println(s1);
//第二次在调用find的时候,会继续读取后面的内容
//读取到第二个满足要求的子串,方法会继续返回true
//并把第二个子串的起始索引和结束索引+1,进行记录
b = m.find();
//第二次调用group方法的时候,会根据find方法记录的索引再次截取子串
String s2 = m.group();
再举个扩展例子:通过网站爬取身份证号
public class Demo1 {
//爬取身份证号码
public static void main(String[] args) throws IOException {
//创建一个URL对象
URL ur1 = new URL("https://www.shbangde.com/xinxi/gklm/zhaosh/wend/2024luqgongs.pdf");
//连接上这个网址
//细节:保证网络是畅通的
URLConnection connection = ur1.openConnection();
//创建一个对象去读取网络中的数据
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
String regex = "[1-9]\d{17}";
Pattern pattern = Pattern.compile(regex);
while((line = br.readLine()) != null){
Matcher matcher = pattern.matcher(line);
while (matcher.find()){
System.out.println(line);
}
}
br.close();
}
}