目录
1.Math
Math中的函数都为静态的,因此直接调用就好不用创建对象,因为静态是共享的,且只存在一份,所以表现为共性而不是个性,所以不需要个性的对象来调用
package com.itheima.a01mathdemo1;
public class MathDemo1 {
public static void main(String[] args) {
/*
public static int abs(int a) 获取参数绝对值
*/
//abs 获取参数绝对值
System.out.println(Math.abs(88));//88
System.out.println(Math.abs(-88));//88
//bug
//以int类型为例,取值范围: -2147483648 ~ 2147483647
//如果没有正数与负数对应,那么传递负数结果有误
//-2147483648 没有正数与之对应,所以abs结果产生bug
System.out.println("--------------------------");
System.out.println(Math.abs(-2147483648));
System.out.println("--------------------------");
//进一法
System.out.println(Math.ceil(12.54));
System.out.println(Math.ceil(12.34));
System.out.println(Math.ceil(-12.34));
System.out.println(Math.ceil(-12.54));
System.out.println("--------------------------");
//去尾法
System.out.println(Math.floor(12.34));
System.out.println(Math.floor(12.54));
System.out.println(Math.floor(-12.34));
System.out.println(Math.floor(-12.54));
System.out.println("--------------------------");
//四舍五入
System.out.println(Math.round(12.34));
System.out.println(Math.round(12.54));
System.out.println(Math.round(-12.34));
System.out.println(Math.round(-12.54));
System.out.println("--------------------------");
// 获取两个正数较大值
System.out.println(Math.max(20,30));
System.out.println("--------------------------");
// 获取两个整数的较小值
System.out.println(Math.min(20,30));
System.out.println("--------------------------");
// 获取a的b次幂
System.out.println(Math.pow(2,3));//8
//细节 :
System.out.println("--------------------------");
//如果第二个参数为 0~1之间的小数
System.out.println(Math.pow(4,0.5));
System.out.println(Math.pow(2,-2));
System.out.println("--------------------------");
//开平方根和立方根
System.out.println(Math.sqrt(4)); // 2.0
System.out.println(Math.cbrt(8)); // 2.0
}
}
效果图
1.abs 取整
//bug
//以int类型为例,取值范围: -2147483648 ~ 2147483647
//如果没有正数与负数对应,那么传递负数结果有误
//-2147483648 没有正数与之对应,所以abs结果产生bug
2.进一法 Math.ceil() 向x正轴进1
3.去尾法 Math.floor() 去掉小数点后面的数
4. 四舍五入 Math.round()
5. 最大值 Math.max() 最小值 Math.min() 取a的b次幂 Math.pow()
6.开平方根 Math.sqrt() 开立方根 Math.cbrt()
2. System
public static void exit() 终止当前运行的JAVA虚拟机
调用格式: System.exit(0)
细节: 括号里面参数为0的话 则程序是正常终止,若非0则为异常终止
public static long currentTimeMillis() 返回当前系统的时间毫秒值形式(程序执行时间)
public static void arraycopy() 数组拷贝
array copy(数据源数组,起始索引,目的地,我要把数据拷贝到哪个数组,目的地数组的索引,拷贝的个数)
例如:将arr2中的值复制给arr1, 期望arr1中的形式为0 0 0 1 2 3 0 0 0 则代码为:
int arr1[] = new int[10];
int arr2[] = {1,2,3,4,5,6,7,8,9,10 };
System.arraycopy(arr2,0,arr1,4,3);
for (int i = 0; i < arr1.length; i++) {
System.out.print(arr1[i]);
}
效果图
细节: 1.如果数据源数组和目的地数组都是基本数据类型,那么两者的类型必须保持一致,否则会报错 2.在拷贝的时候需要考虑数组的长度,如果超出范围也会报错 3.如果数据源数组和目的地数组都是引用数据类型,那么子类类型可以赋值父类类型 例如:double arr1[] = new double[10]; int arr2[] = {1,2,3,4,5,6,7,8,9,10 };int arr1[] = new int[5];
int arr2[] = {1,2,3,4,5,6,7,8,9,10 };
在这两种情况下就会报错
3.第三种情况 如果数组为引用类型数组(类,接口,)
此代码中Student类继承Person类 Student类中用super调用父类的构造函数
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("wangwu",22);
Student s3 = new Student("lisi",21);
Student[] arr3 = {s1,s2,s3};
Person[] arr4 = new Student[3];
System.arraycopy(arr3,0,arr4,0,3);
for (int i = 0; i < arr4.length; i++) {
Student stu = (Student) arr4[i];
System.out.println(stu.getAge() + "," + stu.getName());
}
结果图
可以看出子类中的数据复制给了父类中的对象
//Runtime 类 运行环境中的参数 如果需要JAVA代码监控虚拟机内存
//1.获取Runtime的对象 为什么不用new 因为源码中对象使用final修饰 因此每次只能使用同一个Runtime对象 Runtime r1= Runtime.getRuntime(); //exit 停止虚拟机 // Runtime.getRuntime().exit(0); //获得CPU线程数 System.out.println(Runtime.getRuntime().availableProcessors()); //总内存大小,单位是byte 想转化成MB或者 GB 需要除1024 System.out.println(Runtime.getRuntime().maxMemory() /1024 /1024); //虚拟机已经获取的总内存大小 单位byte System.out.println(Runtime.getRuntime().totalMemory() /1024 /1024); //剩余内存大小 System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024); //运行cmd命令 //shutdown : 关机 //加上参数才能执行 //-s : 默认一分钟后关机 //-s -t 指定时间:指定关机时间 //-a 取消关机操作 // -r 关机并重启 try { Runtime.getRuntime().exec("shutdown -s -t 3"); } catch (IOException e) { e.printStackTrace(); }
Object类中常用的三个方法
1.toString 返回对象的字符串形式 (其实就是返回对象的地址值)
//1. toString 返回对象的字符串形式 Object obj = new Object(); String str1 = obj.toString(); System.out.println(str1);
处理方法:如果想用toString方法获取对象属性中的值,则需要重写Obj中的toString方法。可在JavaBean中书写拼接字符串的方法
public String toString() { return "Student{id = " + id + ", name = " + name + ", age = " + age + "}"; }
2.equals() 比较方法
如果没重写equals方法,那么默认使用Object中的方法进行比较,比较的是对象中的地址值
这是obj类中的源码
那么如果我们想比较的是两个对象中的属性值该怎么办呢?
解决方法: 可以在javaBean中重写这个方法
操作步骤:如果用的是IDEA的话 可直接在JAVABEAN中使用快捷键alt+insert选中 hashcode and equals() 进行重写
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Studen1 studen1 = (Studen1) o; return Objects.equals(name, studen1.name) && Objects.equals(age, studen1.age); }
对于该方法进行一个实验
obj.equals(str1); Studen1 stu1 = new Studen1("zhangsan","22"); Studen1 stu2 = new Studen1("zhangsan","22"); System.out.println(stu1.equals(stu2));
如果用String和StringBuilder同时创建两个内容相同的字符串呢?调用equals对比会相同吗?
测试结果:
那么为什么会这样呢? 这就是其中的一个小细节,如果你用不同类的对象去调用equals方法,那么谁调用的这个方法,用的就是哪个类中重写的这个方法,然而StringBuilder和String中的equals方法不同。
String类中的equals方法是先判断参数是否为字符串,如果是字符串再去判断内部的属性,如果参数不是字符串,那么直接返回false
然后在查询StringBuilder的源码时发现他没有复写过equals的方法,因此他就继承的object中的equals也就是比较两个对象的地址值。
3. Clone() : 对象克隆Clones 将对象中的属性值复制给另一个对象
//细节: //方法在底层会帮我们创建一个对象,并把原对象的数据拷贝过去 //书写细节: ///1.重写Object中的clone方法 //2.让javabean类实现Cloneable接口 //3.创建原对象并调用clone
这里作者写了一个User类的JavaBean并且在JavaBean中重写了Object中的Clone方法,因为OBJ中的克隆方法是用protected修饰的,因此如果你想用该方法的话就只能在Java.lang包下面写,但是我们不可能这样去做,因此就需要在JavaBean中去复写该类,并且复写完之后还需要实现一个Cloneable接口
其中Cloneable是一个空接口
如果一个接口里面没有抽象方法 //表示当前的接口时一个标记行接口 //现在Cloneable表示一旦实现了接口,那么当前类的对象就可以被克隆 //如果没有实现,当前类的对象就不能被克隆
普通数据类型和引用数据类型的拷贝方式不同,普通数据类型拷贝是直接将变量的值给复制给另一个变量,而引用数据类型则是复制其地址值。
Clone()方法中共有两种拷贝方法,浅拷贝和深拷贝
浅拷贝:
例如数组和String字符串,因为字符串是存储在串池当中,因此当使用克隆方法时他会找到串池中的地址,然后将地址给引用变量,同样的数组也是,将数组的地址给另一个数组,这种拷贝方式称作浅拷贝,然而这种方式有一个特点,例如数组,当你修改源数组的值时,因为你两个引用变量用的是同一个数组,则你拷贝后的数组的值也会随之改变。
在IDEA中实现一下 这个是浅拷贝后的数组U2
int[] data = {1,2,3,4,5,6,7,8,9}; User u1= new User(1,"zhangsan",data); //2.克隆对象 //细节: //方法在底层会帮我们创建一个对象,并把原对象的数据拷贝过去 //书写细节: ///1.重写Object中的clone方法 //2.让javabean类实现Cloneable接口 //3.创建原对象并调用clone User u2 = (User)u1.clone(); System.out.println(u1); System.out.println(u2);
然后当我们改变U1数组中的值后可以清楚的发现u2的中数组的值也发生了改变
深克隆:
基本数据类型还是跟浅拷贝一样,直接复制值,而引用数据类型拷贝方法有些不同,例如数组,他会再创建一个数组对象,然后将原数组中的值给复制到新创建的数组对象当中,再将新的数组对象的地址值赋值给引用变量,但是String不太一样,因为串池中已经存在该变量,那么他会进行一个字符串的复用。
总结一下就是基本数据类型拷贝过来 字符串复用 引用数据类型会重新创建新的
那么深拷贝怎么实现呢? 同样的复写拷贝方法
//先把被克隆对象中的数组获取出来 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;
此时回到主函数再调用一次看看效果
Objects工具类
Objects中的equals() 方法
在object类中也有equals这个方法,但是如果第一个引用变量为null,那么你在调用的时候就会报空指针异常,因为此时你的stu1变量为空,因此就无法进行调用
这个时候我们就可以用到objects工具类中的equals方法,先来看一下源码
可以看到,objects中的equals先进行了一个非空判断再去进行一个值的对比。
BigDecimal
用于解决浮点型运算精度失真的问题,因为计算机底层计算是用二进制数字计算的,因此如果用基本数据类型计算一些小数的加减乘除的时候可能会导致数据的丢失或者不准确,因此这个时候就可以用BigDecimal来对数据进行包装计算
package com.itheima.BigDecimal;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo {
public static void main(String[] args) {
// 浮点型运算的时候直接 + * / 可能会出现数据失真(精度问题)
System.out.println(0.09 + 0.01);
System.out.println(1.0 + 0.32);
System.out.println(1.015 * 100);
System.out.println(1.301 / 100);
System.out.println("-------------------------");
double a = 0.1;
double b = 0.2;
double c = a +b;
System.out.println(c);
System.out.println("-------------------");
//包装成Bigdecimal 成为大数据对象 解决精度失真问题
BigDecimal a1= BigDecimal.valueOf(a);
BigDecimal b1= BigDecimal.valueOf(b);
BigDecimal c1 = a1.add(b1);
//打印出来是值 说明方法重写过了 对象打印出来应该是地址值
System.out.println(c1);
//用double值接收
double rs= c1.doubleValue();
BigDecimal a11 = BigDecimal.valueOf(10.0);
BigDecimal b11 = BigDecimal.valueOf(3.0);
/*
参数一: 除数 参数二: 保留小数位数 参数三: 舍入模式 向上取整 等...
*/
BigDecimal c11 = a11.divide(b11,2, RoundingMode.CEILING);
}
}
正则表达式
正则表达式可以用一些规定的字符来制定规则,并用来校验数据格式的合法性,检验多个字符 需要用到贪婪量词 不要随意加空格 。
下面是正则表达式的格式。
字符 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
x | 字符 x | ||||||||||||||
\\ | 反斜线字符 | ||||||||||||||
\0n | 带有八进制值 0 的字符 n (0 <= n <= 7) | ||||||||||||||
\0nn | 带有八进制值 0 的字符 nn (0 <= n <= 7) | ||||||||||||||
\0mnn | 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) | ||||||||||||||
\xhh | 带有十六进制值 0x 的字符 hh | ||||||||||||||
\uhhhh | 带有十六进制值 0x 的字符 hhhh | ||||||||||||||
\t | 制表符 ('\u0009') | ||||||||||||||
\n | 新行(换行)符 ('\u000A') | ||||||||||||||
\r | 回车符 ('\u000D') | ||||||||||||||
\f | 换页符 ('\u000C') | ||||||||||||||
\a | 报警 (bell) 符 ('\u0007') | ||||||||||||||
\e | 转义符 ('\u001B') | ||||||||||||||
\cx | 对应于 x 的控制符 | ||||||||||||||
字符类 | |||||||||||||||
[abc] | a、b 或 c(简单类) | ||||||||||||||
[^abc] | 任何字符,除了 a、b 或 c(否定) | ||||||||||||||
[a-zA-Z] | a 到 z 或 A 到 Z,两头的字母包括在内(范围) | ||||||||||||||
[a-d[m-p]] | a 到 d 或 m 到 p:[a-dm-p](并集) | ||||||||||||||
[a-z&&[def]] | d、e 或 f(交集) | ||||||||||||||
[a-z&&[^bc]] | a 到 z,除了 b 和 c:[ad-z](减去) | ||||||||||||||
[a-z&&[^m-p]] | a 到 z,而非 m 到 p:[a-lq-z](减去) | ||||||||||||||
预定义字符类 | |||||||||||||||
. | 任何字符(与行结束符可能匹配也可能不匹配) | ||||||||||||||
\d | 数字:[0-9] | ||||||||||||||
\D | 非数字: [^0-9] | ||||||||||||||
\s | 空白字符:[ \t\n\x0B\f\r] | ||||||||||||||
\S | 非空白字符:[^\s] | ||||||||||||||
\w | 单词字符:[a-zA-Z_0-9] | ||||||||||||||
\W | 非单词字符:[^\w] | ||||||||||||||
|
String类的matches方法与正则表达式相匹配
package com.itheima.d6_regex;
public class RegexDemo1 {
public static void main(String[] args) {
// 需求 校验qq号码,必须全部数字 6-20位
}
public static boolean check(String QQ)
{
//正则表达式
return QQ !=null && QQ.matches("\\d{6,20}");
}
public static boolean checkQQ(String qq)
{
if (qq == null || qq.length() < 6 || qq.length() > 20)
{
return false;
}
//判断qq中是否全部是数字,不是返回false
return true;
}
}
正则表达式: 邮箱判定和手机号判定
package com.itheima.d6_regex;
import java.util.Scanner;
public class RegexDemo2 {
public static void main(String[] args) {
// checkPhone();
checkEmail();
}
public static void checkEmail()
{
Scanner sc = new Scanner(System.in);
while (true)
{
System.out.println("输入邮箱");
String email = sc.next();
// 判断邮箱格式是否正确 852516496@qq.com
// 判断邮箱格式是否正确 852132136496@163.com.cn
if (email.matches("\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-z]{2,20}){1,2}"))
{
System.out.println("格式正确");
break;
}else {
System.out.println("格式有误!");
}
}
}
public static void checkPhone(){
Scanner sc = new Scanner(System.in);
while (true)
{
System.out.println("输入手机号");
String phone = sc.next();
if (phone.matches("1[3-9]\\d{9}"))
{
System.out.println("格式正确,注册成功");
break;
}else {
System.out.println("格式有误");
}
}
}
}
正则表达式与String类方法相结合使用
package com.itheima.d6_regex;
public class RegexDemo3 {
/*
正则表达式与Stirng方法相结合使用
*/
public static void main(String[] args) {
String names = "小路hasdasdasd蓉儿asdjoiasjdio过儿";
String[] arrs = names.split("\\w+");
for (int i = 0; i < arrs.length; i++) {
System.out.println(arrs[i]);
}
String name = names.replaceAll("\\w+"," ");
System.out.println(name);
}
}
从爬虫爬出来的信息中找到自己想要的信息
package com.itheima.d6_regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo4 {
public static void main(String[] args) {
String rs = "来黑马程序学习JAVA,电话020-43422424,或者联系邮箱" +
"itcast@itcast.cn,电话18762832633,020232323"
+"邮箱bozai@itcast.cn,400-100-3233,4001003232";
/*
需求: 从上面的内容中爬取出 电话号码和邮箱
1.定义爬取规则, 字符串形式。
*/
String regex = "(\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-z]{2,20}){1,2})|(\"1[3-9]\\d{9})|(0\\d{2,6}-?\\d{5,20})" +
"|(400-?\\d{3,9}\\d{3,9})";
//2. 把这个爬取规则编译成匹配对象
Pattern pattern = Pattern.compile(regex);
//3.得到一个内容匹配器对象
Matcher matcher = pattern.matcher(rs);
//4. 开始找了
while (matcher.find())
{
String rs1 = matcher.group();
System.out.println(rs1);
}
}
}