课程目标 能够熟练使用 Math 类中的常见方法
能够熟练使用 System 类中的常见方法
能够理解 Object 类的常见方法作用
能够熟练使用 Objects 类的常见方法
能够熟练使用 BigInteger 类的常见方法
能够熟练使用 BigDecimal 类的常见方法
1 Math 类 11 概述
tips:了解内容
查看 API 文档,我们可以看到 API 文档中关于 Math 类的定义如下:
Math 类所在包为 javalang 包,因此在使用的时候不需要进行导包。并且 Math 类被 final 修饰了,因此该类是不能被继承的。
Math 类包含执行基本数字运算的方法,我们可以使用 Math 类完成基本的数学运算。
要想使用 Math 类我们就需要先创建该类的对象,那么创建对象就需要借助于构造方法。因此我们就需要首先查看一下 API 文档,看看 API 文档中针对 Math 类有没有提供对应的构造方法。通过 API 文档来查看
一下 Math 类的成员,如下所示:
在 API 文档中没有体现可用的构造方法,因此我们就不能直接通过 new 关键字去创建 Math 类的对象。同时我们发现 Math 类中的方法都是静态的,因此在使用的时候我们可以直接通过类名去调用。在 Math 类中
定义了很多数学运算的方法,但是我们并不可能将所有的方法学习一遍,我们主要学习的就是一些常见的方法。
12 常见方法
tips:重点讲解内容
常见方法介绍
我们要学习的 Math 的常见方法如下所示:
1 2 3 4 5 6 7 8 public static int abs (int a) public static double ceil (double a) public static double floor (double a) public static int round (float a) public static int max (int a,int b) public static int min (int a,int b) public static double pow (double a,double b) public static double random ()
案例演示
接下来我们就来演示一些这些方法的执行效果,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class MathDemo01 { public static void main (String[] args) { Systemoutprintln("-2的绝对值为:" + Mathabs(-2 )); Systemoutprintln("2的绝对值为:" + Mathabs(2 )); Systemoutprintln("大于或等于2345的最小整数位:" + Mathceil(2345 )); Systemoutprintln("大于或等于-2345的最小整数位:" + Mathceil(-2345 )); Systemoutprintln("小于或等于2345的最大整数位:" + Mathfloor(2345 )); Systemoutprintln("小于或等于-2345的最大整数位:" + Mathfloor(-2345 )); Systemoutprintln("2345四舍五入的结果为:" + Mathround(2345 )); Systemoutprintln("2355四舍五入的结果为:" + Mathround(2355 )); Systemoutprintln("23和45的最大值为: " + Mathmax(23 , 45 )); Systemoutprintln("12和34的最小值为: " + Mathmin(12 , 34 )); Systemoutprintln("2的3次幂计算结果为: " + Mathpow(2 ,3 )); Systemoutprintln("获取到的0-1之间的随机数为: " + Mathrandom()); } }
运行程序进行测试,控制台输出结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 -2 的绝对值为:2 2 的绝对值为:2 大于或等于2345 的最小整数位:240 大于或等于-2345 的最小整数位:-230 小于或等于2345 的最大整数位:230 小于或等于-2345 的最大整数位:-240 2345 四舍五入的结果为:23 2355 四舍五入的结果为:24 23 和45 的最大值为: 45 12 和34 的最小值为: 12 2 的3 次幂计算结果为: 80 获取到的0 -1 之间的随机数为: 07322484131745958
13 算法小题(质数) 需求:
判断一个数是否为一个质数
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class MathDemo2 { public static void main (String[] args) { Systemoutprintln(isPrime(997 )); } public static boolean isPrime (int number) { int count = 0 ; for (int i = 2 ; i <= Mathsqrt(number); i++) { count++; if (number % i == 0 ) { return false ; } } Systemoutprintln(count); return true ; } }
14 算法小题(自幂数) 自幂数,一个 n 位自然数等于自身各个数位上数字的 n 次幂之和
举例 1:三位数 1^3 + 5^3 + 3^3 = 153
举例 2:四位数 1^4 + 6^4 + 3^4 + 4^3 = 1634
如果自幂数是:
一位自幂数,也叫做:独身数
三位自幂数:水仙花数 四位自幂数:四叶玫瑰数
五位自幂数:五角星数 六位自幂数:六合数
七位自幂数:北斗七星数 八位自幂数:八仙数
九位自幂数:九九重阳数 十位自幂数:十全十美数
要求 1:统计一共有多少个水仙花数。
要求 2:(课后作业)证明没有两位的自幂数。
要求 3:(课后作业)分别统计有多少个四叶玫瑰数和五角星数。(答案:都是 3 个)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int count = 0 ;for (int i = 100 ; i <= 999 ; i++) { int ge = i % 10 ; int shi = i / 10 % 10 ; int bai = i / 100 % 10 ; double sum = Mathpow(ge, 3 ) + Mathpow(shi, 3 ) + Mathpow(bai, 3 ); if (sum == i) { count++; Systemoutprintln(count); } }
15 课后练习 要求 2:(课后作业)证明没有两位的自幂数。
要求 3:(课后作业)分别统计有多少个四叶玫瑰数和五角星数。(答案:都是 3 个)
2 System 类 21 概述
tips:了解内容
查看 API 文档,我们可以看到 API 文档中关于 System 类的定义如下:
System 类所在包为 javalang 包,因此在使用的时候不需要进行导包。并且 System 类被 final 修饰了,因此该类是不能被继承的。
System 包含了系统操作的一些常用的方法。比如获取当前时间所对应的毫秒值,再比如终止当前 JVM 等等。
要想使用 System 类我们就需要先创建该类的对象,那么创建对象就需要借助于构造方法。因此我们就需要首先查看一下 API 文档,看看 API 文档中针对 System 类有没有提供对应的构造方法。通过 API 文档来
查看一下 System 类的成员,如下所示:
在 API 文档中没有体现可用的构造方法,因此我们就不能直接通过 new 关键字去创建 System 类的对象。同时我们发现 System 类中的方法都是静态的,因此在使用的时候我们可以直接通过类名去调用(Nested
Class Summary 内部类或者内部接口的描述)。
22 常见方法
tips:重点讲解内容
常见方法介绍
我们要学习的 System 类中的常见方法如下所示:
1 2 3 public static long currentTimeMillis () public static void exit (int status) public static native void arraycopy (Object src, int srcPos, Object dest, int destPos, int length) ;
案例演示
接下来我们就来通过一些案例演示一下这些方法的特点。
案例 1 :演示 currentTimeMillis 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 public class SystemDemo01 { public static void main (String[] args) { long millis = SystemcurrentTimeMillis(); Systemoutprintln("当前时间所对应的毫秒值为:" + millis); } }
运行程序进行测试,控制台的输出结果如下:
1 当前时间所对应的毫秒值为:1576050298343
获取到当前时间的毫秒值的意义:我们常常来需要统计某一段代码的执行时间。此时我们就可以在执行这段代码之前获取一次时间,在执行完毕以后再次获取一次系统时间,然后计算两个时间的差值,
这个差值就是这段代码执行完毕以后所需要的时间。如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class SystemDemo2 { public static void main (String[] args) { long start = SystemcurrentTimeMillis(); for (int i = 1 ; i <= 100000 ; i++) { boolean flag = isPrime2(i); if (flag) { Systemoutprintln(i); } } long end = SystemcurrentTimeMillis(); Systemoutprintln(end - start); } 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 <= Mathsqrt(number); i++) { if (number % i == 0 ) { return false ; } } return true ; } }
案例 2 :演示 exit 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SystemDemo01 { public static void main (String[] args) { Systemoutprintln("程序开始执行了" ); Systemexit(0 ); Systemoutprintln("程序终止了" ); } }
运行程序进行测试,控制台输出结果如下:
此时可以看到在控制台只输出了”程序开始了”,由于 JVM 终止了,因此输出”程序终止了”这段代码没有被执行。
案例 3 :演示 arraycopy 方法
方法参数说明:
1 2 3 4 5 6 public static native void arraycopy (Object src, int srcPos, Object dest, int destPos, int length) ;
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class SystemDemo01 { public static void main (String[] args) { int [] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ; int [] desArray = new int [10 ] ; Systemarraycopy(srcArray , 0 , desArray , 1 , 3 ); for (int x = 0 ; x < desArraylength ; x++) { if (x != desArraylength - 1 ) { Systemoutprint(desArray[x] + ", " ); }else { Systemoutprintln(desArray[x]); } } } }
运行程序进行测试,控制台输出结果如下所示:
1 0 , 23 , 45 , 67 , 0 , 0 , 0 , 0 , 0 , 0
通过控制台输出结果我们可以看到,数组元素的确进行复制了。
使用这个方法我们也可以完成数组元素的删除操作,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class SystemDemo02 { public static void main (String[] args) { int [] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ; Systemarraycopy(srcArray , 3 , srcArray , 2 , 3 ); for (int x = 0 ; x < srcArraylength ; x++) { if (x != desArraylength - 1 ) { Systemoutprint(srcArray[x] + ", " ); }else { Systemoutprintln(srcArray[x]); } } } }
运行程序进行测试,控制台的输出结果如下所示:
通过控制台输出结果我们可以看到此时多出了一个 56 元素,此时我们只需要将最后一个位置设置为 0 即可。如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class SystemDemo02 { public static void main (String[] args) { int [] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ; Systemarraycopy(srcArray , 3 , srcArray , 2 , 3 ); srcArray[srcArraylength - 1 ] = 0 ; for (int x = 0 ; x < srcArraylength ; x++) { if (x != srcArraylength - 1 ) { Systemoutprint(srcArray[x] + ", " ); }else { Systemoutprintln(srcArray[x]); } } } }
运行程序进行测试,控制台输出结果如下所示:
此时我们可以看到元素”67”已经被删除掉了。67 后面的其他元素依次向前进行移动了一位。
arraycopy 方法底层细节:
1 如果数据源数组和目的地数组都是基本数据类型,那么两者的类型必须保持一致,否则会报错
2 在拷贝的时候需要考虑数组的长度,如果超出范围也会报错
3 如果数据源数组和目的地数组都是引用数据类型,那么子类类型可以赋值给父类类型
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 public class SystemDemo3 { public static void main (String[] args) { Student s1 = new Student ("zhangsan" , 23 ); Student s2 = new Student ("lisi" , 24 ); Student s3 = new Student ("wangwu" , 25 ); Student[] arr1 = {s1, s2, s3}; Person[] arr2 = new Person [3 ]; Systemarraycopy(arr1, 0 , arr2, 0 , 3 ); for (int i = 0 ; i < arr2length; i++) { Student stu = (Student) arr2[i]; Systemoutprintln(stugetName() + "," + stugetAge()); } } } class Person { private String name; private int age; public Person () { } public Person (String name, int age) { thisname = name; thisage = age; } public String getName () { return name; } public void setName (String name) { thisname = name; } public int getAge () { return age; } public void setAge (int age) { thisage = age; } public String toString () { return "Person{name = " + name + ", age = " + age + "}" ; } } class Student extends Person { public Student () { } public Student (String name, int age) { super (name, age); } }
3 Runtime 31 概述 Runtime 表示 Java 中运行时对象,可以获取到程序运行时设计到的一些信息
32 常见方法 常见方法介绍
我们要学习的 Object 类中的常见方法如下所示:
1 2 3 4 5 6 7 public static Runtime getRuntime () public void exit (int status) public int availableProcessors () public long maxMemory () public long totalMemory () public long freeMemory () public Process exec (String command)
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class RunTimeDemo1 { public static void main (String[] args) throws IOException { Systemoutprintln(RuntimegetRuntime()availableProcessors()); Systemoutprintln(RuntimegetRuntime()maxMemory() / 1024 / 1024 ); Systemoutprintln(RuntimegetRuntime()totalMemory() / 1024 / 1024 ); Systemoutprintln(RuntimegetRuntime()freeMemory() / 1024 / 1024 ); RuntimegetRuntime()exec("shutdown -s -t 3600" ); } }
33 恶搞好基友 需求:
界面上方按钮默认隐藏
界面中间有一个提示文本和三个按钮
当你的好基友点击中间三个按钮的时候就在 N 秒之后关机,不同的按钮 N 的值不一样
任意一个按钮被点击之后,上方了按钮出现。当点击上方按钮之后取消关机任务
1 2 3 4 5 public class Test { public static void main (String[] args) { new MyJframe (); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 public class MyJframe extends JFrame implements ActionListener { JButton yesBut = new JButton ("帅爆了" ); JButton midBut = new JButton ("一般般吧" ); JButton noBut = new JButton ("不帅,有点磕碜" ); JButton dadBut = new JButton ("饶了我吧!" ); boolean flag = false ; public MyJframe () { initJFrame(); initView(); thissetVisible(true ); } private void initView () { thisgetContentPane()removeAll(); if (flag) { dadButsetBounds(50 , 20 , 100 , 30 ); dadButaddActionListener(this ); thisgetContentPane()add(dadBut); } JLabel text = new JLabel ("你觉得自己帅吗?" ); textsetFont(new Font ("微软雅黑" , 0 , 30 )); textsetBounds(120 , 150 , 300 , 50 ); yesButsetBounds(200 , 250 , 100 , 30 ); midButsetBounds(200 , 325 , 100 , 30 ); noButsetBounds(160 , 400 , 180 , 30 ); yesButaddActionListener(this ); midButaddActionListener(this ); noButaddActionListener(this ); thisgetContentPane()add(text); thisgetContentPane()add(yesBut); thisgetContentPane()add(midBut); thisgetContentPane()add(noBut); thisgetContentPane()repaint(); } private void initJFrame () { thissetSize(500 , 600 ); thissetTitle("恶搞好基友" ); thissetDefaultCloseOperation(3 ); thissetAlwaysOnTop(true ); thissetLocationRelativeTo(null ); thissetLayout(null ); } @Override public void actionPerformed (ActionEvent e) { Object obj = egetSource(); if (obj == yesBut) { showJDialog("xxx,你太自信了,给你一点小惩罚" ); try { RuntimegetRuntime()exec("shutdown -s -t 3600" ); } catch (IOException ioException) { ioExceptionprintStackTrace(); } flag = true ; initView(); } else if (obj == midBut) { Systemoutprintln("你的好基友点击了一般般吧" ); showJDialog("xxx,你还是太自信了,也要给你一点小惩罚" ); try { RuntimegetRuntime()exec("shutdown -s -t 7200" ); } catch (IOException ioException) { ioExceptionprintStackTrace(); } flag = true ; initView(); } else if (obj == noBut) { Systemoutprintln("你的好基友点击了不帅" ); showJDialog("xxx,你还是有一点自知之明的,也要给你一点小惩罚" ); try { RuntimegetRuntime()exec("shutdown -s -t 1800" ); } catch (IOException ioException) { ioExceptionprintStackTrace(); } flag = true ; initView(); } else if (obj == dadBut) { showJDialog("xxx,这次就饶了你~" ); try { RuntimegetRuntime()exec("shutdown -a" ); } catch (IOException ioException) { ioExceptionprintStackTrace(); } } } public void showJDialog (String content) { JDialog jDialog = new JDialog (); jDialogsetSize(200 , 150 ); jDialogsetAlwaysOnTop(true ); jDialogsetLocationRelativeTo(null ); jDialogsetModal(true ); JLabel warning = new JLabel (content); warningsetBounds(0 , 0 , 200 , 150 ); jDialoggetContentPane()add(warning); jDialogsetVisible(true ); } }
4 Object 类 41 概述
tips:重点讲解内容
查看 API 文档,我们可以看到 API 文档中关于 Object 类的定义如下:
Object 类所在包是 javalang 包。Object 是类层次结构的根,每个类都可以将 Object 作为超类。所有类都直接或者间接的继承自该类;换句话说,该类所具备的方法,其他所有类都继承了。
查看 API 文档我们可以看到,在 Object 类中提供了一个无参构造方法,如下所示:
但是一般情况下我们很少去主动的创建 Object 类的对象,调用其对应的方法。更多的是创建 Object 类的某个子类对象,然后通过子类对象调用 Object 类中的方法。
42 常见方法
tips:重点讲解内容
常见方法介绍
我们要学习的 Object 类中的常见方法如下所示:
1 2 3 public String toString () public boolean equals (Object obj) protected Object clone ()
案例演示
接下来我们就来通过一些案例演示一下这些方法的特点。
案例 1 :演示 toString 方法
实现步骤:
1 创建一个学生类,提供两个成员变量(name , age);并且提供对应的无参构造方法和有参构造方法以及 get/set 方法 2 创建一个测试类(ObjectDemo01),在测试类的 main 方法中去创建学生对象,然后调用该对象的 toString 方法获取该对象的字符串表现形式,并将结果进行输出
如下所示:
Student 类
1 2 3 4 5 6 7 8 9 public class Student { private String name ; private String age ; }
ObjectDemo01 测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ObjectDemo01 { public static void main (String[] args) { Student s1 = new Student ("itheima" , "14" ) ; String result1 = s1toString(); Systemoutprintln("s1对象的字符串表现形式为:" + result1); } }
运行程序进行测试,控制台输出结果如下所示:
1 s1对象的字符串表现形式为:comitheimaapisystemdemo04Student@3f3afe78
为什么控制台输出的结果为:comitheimaapisystemdemo04Student@3f3afe78; 此时我们可以查看一下 Object 类中 toString 方法的源码,如下所示:
1 2 3 public String toString () { return getClass()getName() + "@" + IntegertoHexString(hashCode()); }
其中 getClass()getName()对应的结果就是:comitheimaapisystemdemo04Student;IntegertoHexString(hashCode())对应的结果就是 3f3afe78。
我们常常将”comitheimaapisystemdemo04Student@3f3afe78”这一部分称之为对象的内存地址值。但是一般情况下获取对象的内存地址值没有太大的意义。获取对象的成员变量的字符串拼接形式才
算有意义,怎么实现呢?此时我们就需要在 Student 类中重写 Object 的 toString 方法。我们可以通过 idea 开发工具进行实现,具体步骤如下所示:
1 在空白处使用快捷键:alt + insert。此时会弹出如下的对话框
2 选择 toString,此时会弹出如下的对话框
同时选择 name 和 age 属性,点击 OK。此时就会完成 toString 方法的重写,代码如下所示:
1 2 3 4 5 6 7 @Override public String toString () { return "Student{" + "name='" + name + '/' ' + ", age=' " + age + '/'' + '}'; }
这段代码就是把 Student 类中的成员变量进行了字符串的拼接。重写完毕以后,再次运行程序,控制台输出结果如下所示:
1 s1对象的字符串表现形式为:Student{name='itheima' , age='14' }
此时我们就可以清楚的查看 Student 的成员变量值,因此重写 toString 方法的意义就是以良好的格式,更方便的展示对象中的属性值
我们再来查看一下如下代码的输出:
1 2 3 4 5 Student s1 = new Student ("itheima" , "14" ) ;Systemoutprintln(s1);
运行程序进行测试,控制台输出结果如下所示:
1 Student{name='itheima' , age='14' }
我们可以看到和刚才的输出结果是一致的。那么此时也就证明直接输出一个对象,那么会默认调用对象的 toString 方法,因此如上代码的等同于如下代码:
1 2 3 4 5 Student s1 = new Student ("itheima" , "14" ) ;Systemoutprintln(s1toString());
因此后期为了方便进行测试,我们常常是通过输出语句直接输出一个对象的名称。
小结:
1 在通过输出语句输出一个对象时,默认调用的就是 toString()方法 2 输出地址值一般没有意义,我们可以通过重写 toString 方法去输出对应的成员变量信息(快捷键:atl + insert , 空白处 右键 -> Generate -> 选择 toString) 3 toString 方法的作用:以良好的格式,更方便的展示对象中的属性值 4 一般情况下 Jdk 所提供的类都会重写 Object 类中的 toString 方法
案例 2 :演示 equals 方法
实现步骤:
1 在测试类(ObjectDemo02)的 main 方法中,创建两个学生对象,然后比较两个对象是否相同
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ObjectDemo02 { public static void main (String[] args) { Student s1 = new Student ("itheima" , "14" ) ; Student s2 = new Student ("itheima" , "14" ) ; Systemoutprintln(s1 == s2); } }
运行程序进行测试,控制台的输出结果如下所示:
因为”==”号比较的是对象的地址值,而我们通过 new 关键字创建了两个对象,它们的地址值是不相同的。因此比较结果就是 false。
我们尝试调用 Object 类中的 equals 方法进行比较,代码如下所示:
1 2 3 4 5 boolean result = s1equals(s2);Systemoutprintln(result);
运行程序进行测试,控制台的输出结果为:
为什么结果还是 false 呢?我们可以查看一下 Object 类中 equals 方法的源码,如下所示:
1 2 3 public boolean equals (Object obj) { return (this == obj); }
通过源码我们可以发现默认情况下 equals 方法比较的也是对象的地址值。比较内存地址值一般情况下是没有意义的,我们希望比较的是对象的属性,如果两个对象的属性相同,我们认为就是同一个对象;
那么要比较对象的属性,我们就需要在 Student 类中重写 Object 类中的 equals 方法。equals 方法的重写,我们也可以使用 idea 开发工具完成,具体的操作如下所示:
1 在空白处使用快捷键:alt + insert。此时会弹出如下的对话框
2 选择 equals() and hashCode()方法,此时会弹出如下的对话框
点击 next,会弹出如下对话框:
选择 neme 和 age 属性点击 next,此时就会弹出如下对话框:
取消 name 和 age 属性(因为此时选择的是在生成 hashCode 方法时所涉及到的属性,关于 hashCode 方法后期再做重点介绍),点击 Finish 完成生成操作。生成的 equals 方法和 hashCode 方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != ogetClass()) return false ; Student student = (Student) o; return Objectsequals(name, studentname) && Objectsequals(age, studentage); } @Override public int hashCode () { return 0 ; }
hashCode 方法我们暂时使用不到,可以将 hashCode 方法删除。重写完毕以后运行程序进行测试,控制台输出结果如下所示:
此时 equals 方法比较的是对象的成员变量值,而 s1 和 s2 两个对象的成员变量值都是相同的。因此比较完毕以后的结果就是 true。
小结:
1 默认情况下 equals 方法比较的是对象的地址值 2 比较对象的地址值是没有意义的,因此一般情况下我们都会重写 Object 类中的 equals 方法
案例 2 :对象克隆
把 A 对象的属性值完全拷贝给 B 对象,也叫对象拷贝,对象复制
对象克隆的分类:
深克隆和浅克隆
浅克隆:
不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来
基本数据类型拷贝过来的是具体的数据,引用数据类型拷贝过来的是地址值。
Object 类默认的是浅克隆
深克隆:
基本数据类型拷贝过来,字符串复用,引用数据类型会重新创建新的
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 package comitheimaa04objectdemo;public class ObjectDemo4 { public static void main (String[] args) throws CloneNotSupportedException { int [] data = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 0 }; User u1 = new User (1 , "zhangsan" , "1234qwer" , "girl11" , data); } } package comitheimaa04objectdemo;import javautilStringJoiner;public class User implements Cloneable { private int id; private String username; private String password; private String path; private int [] data; public User () { } public User (int id, String username, String password, String path, int [] data) { thisid = id; thisusername = username; thispassword = password; thispath = path; thisdata = data; } public int getId () { return id; } public void setId (int id) { thisid = id; } public String getUsername () { return username; } public void setUsername (String username) { thisusername = username; } public String getPassword () { return password; } public void setPassword (String password) { thispassword = password; } public String getPath () { return path; } public void setPath (String path) { thispath = path; } public int [] getData() { return data; } public void setData (int [] data) { thisdata = data; } public String toString () { return "角色编号为:" + id + ",用户名为:" + username + "密码为:" + password + ", 游戏图片为:" + path + ", 进度:" + arrToString(); } public String arrToString () { StringJoiner sj = new StringJoiner (", " , "[" , "]" ); for (int i = 0 ; i < datalength; i++) { sjadd(data[i] + "" ); } return sjtoString(); } @Override protected Object clone () throws CloneNotSupportedException { int [] data = thisdata; int [] newData =new int [datalength]; for (int i = 0 ; i < datalength; i++) { newData[i] = data[i]; } User u=(User)superclone(); udata =newData; return u; } }
5 Objects 类 51 概述
tips:了解内容
查看 API 文档,我们可以看到 API 文档中关于 Objects 类的定义如下:
Objects 类所在包是在 javautil 包下,因此在使用的时候需要进行导包。并且 Objects 类是被 final 修饰的,因此该类不能被继承。
Objects 类提供了一些对象常见操作的方法。比如判断对象是否相等,判断对象是否为 null 等等。
接下来我们来查看一下 API 文档,看一下 Objects 类中的成员,如下所示:
我们可以发现 Objects 类中无无参构造方法,因此我们不能使用 new 关键字去创建 Objects 的对象。同时我们可以发现 Objects 类中所提供的方法都是静态的。因此我们可以通过类名直接去调用这些方法。
52 常见方法
tips:重点讲解内容
常见方法介绍
我们要重点学习的 Objects 类中的常见方法如下所示:
1 2 3 4 public static String toString (Object o) public static boolean equals (Object a, Object b) public static boolean isNull (Object obj) public static boolean nonNull (Object obj)
我们要了解的 Objects 类中的常见方法如下所示:
1 2 3 public static <T> T requireNonNull (T obj) public static <T> T requireNonNullElse (T obj, T defaultObj) public static <T> T requireNonNullElseGet (T obj, Supplier<? extends T> supplier)
上述方法中的 T 可以理解为是 Object 类型。
案例演示
接下来我们就来通过一些案例演示一下 Objects 类中的这些方法特点。
案例 1 :演示重点学习方法
实现步骤:
1 创建一个学生类,提供两个成员变量(name , age);并且提供对应的无参构造方法和有参构造方法以及 get/set 方法,并且重写 toString 方法和 equals 方法 2 创建一个测试类(ObjectsDemo01), 在该类中编写测试代码
如下所示:
Student 类
1 2 3 4 5 6 7 8 9 public class Student { private String name ; private String age ; }
ObjectsDemo01 测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public class ObjectsDemo01 { public static void main (String[] args) { method_04() ; } public static void method_04 () { Student s1 = new Student ("itheima" , "14" ) ; boolean result = ObjectsnonNull(s1); Systemoutprintln(result); } public static void method_03 () { Student s1 = new Student ("itheima" , "14" ) ; boolean result = ObjectsisNull(s1); Systemoutprintln(result); } public static void method_02 () { Student s1 = new Student ("itheima" , "14" ) ; Student s2 = new Student ("itheima" , "14" ) ; boolean result = Objectsequals(s1, s2); Systemoutprintln(result); } public static void method_01 () { Student s1 = new Student ("itheima" , "14" ) ; String result = ObjectstoString(s1); Systemoutprintln(result); } }
案例 2 :演示需要了解的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 public class ObjectsDemo02 { public static void main (String[] args) { method_03(); } public static void method_03 () { Student s1 = new Student ("itheima" , "14" ) ; Student student = ObjectsrequireNonNullElseGet(s1, () -> { return new Student ("itcast" , "14" ); }); Systemoutprintln(student); } public static void method_02 () { Student s1 = new Student ("itheima" , "14" ) ; Student student = ObjectsrequireNonNullElse(s1, new Student ("itcast" , "14" )); Systemoutprintln(student); } public static void method_01 () { Student s1 = new Student ("itheima" , "14" ) ; Student student = ObjectsrequireNonNull(s1); Systemoutprintln(student); } }
注:了解性的方法可以可以作为扩展视频进行下发。
6 BigInteger 类 61 引入 平时在存储整数的时候,Java 中默认是 int 类型,int 类型有取值范围:-2147483648 ~ 2147483647。如果数字过大,我们可以使用 long 类型,但是如果 long 类型也表示不下怎么办呢?
就需要用到 BigInteger,可以理解为:大的整数。
有多大呢?理论上最大到 42 亿的 21 亿次方
基本上在内存撑爆之前,都无法达到这个上限。
62 概述 查看 API 文档,我们可以看到 API 文档中关于 BigInteger 类的定义如下:
BigInteger 所在包是在 javamath 包下,因此在使用的时候就需要进行导包。我们可以使用 BigInteger 类进行大整数的计算
63 常见方法 构造方法
1 2 3 4 5 6 public BigInteger (int num, Random rnd) public BigInteger (String val) public BigInteger (String val, int radix) 下面这个不是构造,而是一个静态方法获取BigInteger对象 public static BigInteger valueOf (long val)
构造方法小结:
如果 BigInteger 表示的数字没有超出 long 的范围,可以用静态方法获取。
如果 BigInteger 表示的超出 long 的范围,可以用构造方法获取。
对象一旦创建,BigInteger 内部记录的值不能发生改变。
只要进行计算都会产生一个新的 BigInteger 对象
常见成员方法
BigDecimal 类中使用最多的还是提供的进行四则运算的方法,如下:
1 2 3 4 5 6 7 8 9 public BigInteger add (BigInteger val) public BigInteger subtract (BigInteger val) public BigInteger multiply (BigInteger val) public BigInteger divide (BigInteger val) public BigInteger[] divideAndRemainder(BigInteger val) public boolean equals (Object x) public BigInteger pow (int exponent) public BigInteger max/min(BigInteger val) public int intValue (BigInteger val)
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package comitheimaa06bigintegerdemo;import javamathBigInteger;public class BigIntegerDemo1 { public static void main (String[] args) { BigInteger bd4 = new BigInteger ("123" , 2 ); Systemoutprintln(bd4); BigInteger bd5 = BigIntegervalueOf(16 ); BigInteger bd6 = BigIntegervalueOf(16 ); Systemoutprintln(bd5 == bd6); BigInteger bd7 = BigIntegervalueOf(17 ); BigInteger bd8 = BigIntegervalueOf(17 ); Systemoutprintln(bd7 == bd8); BigInteger bd9 = BigIntegervalueOf(1 ); BigInteger bd10 = BigIntegervalueOf(2 ); BigInteger result=bd9add(bd10); Systemoutprintln(result); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package comitheimaa06bigintegerdemo;import javamathBigInteger;public class BigIntegerDemo2 { public static void main (String[] args) { BigInteger bd1 = BigIntegervalueOf(10 ); BigInteger bd2 = BigIntegervalueOf(5 ); BigInteger bd3 = bd1add(bd2); Systemoutprintln(bd3); BigInteger[] arr = bd1divideAndRemainder(bd2); Systemoutprintln(arr[0 ]); Systemoutprintln(arr[1 ]); boolean result = bd1equals(bd2); Systemoutprintln(result); BigInteger bd4 = bd1pow(2 ); Systemoutprintln(bd4); BigInteger bd5 = bd1max(bd2); BigInteger bd6 = BigIntegervalueOf(200 ); double v = bd6doubleValue(); Systemoutprintln(v); } }
64 底层存储方式: 对于计算机而言,其实是没有数据类型的概念的,都是 0101010101,数据类型是编程语言自己规定的,所以在实际存储的时候,先把具体的数字变成二进制,每 32 个 bit 为一组,存储在数组中。
数组中最多能存储元素个数:21 亿多
数组中每一位能表示的数字:42 亿多
理论上,BigInteger 能表示的最大数字为:42 亿的 21 亿次方。
但是还没到这个数字,电脑的内存就会撑爆,所以一般认为 BigInteger 是无限的。
存储方式如图所示:
7 BigDecimal 类 71 引入 首先我们来分析一下如下程序的执行结果:
1 2 3 4 5 6 7 public class BigDecimalDemo01 { public static void main (String[] args) { Systemoutprintln(009 + 001 ); } }
这段代码比较简单,就是计算 009 和 001 之和,并且将其结果在控制台进行输出。那么按照我们的想法在控制台输出的结果应该为 01。那么实际的运行结果是什么呢?我们来运行一下程序,控制台的输出
结果如下所示:
这样的结果其实就是一个丢失精度的结果。为什么会产生精度丢失呢?
在使用 float 或者 double 类型的数据在进行数学运算的时候,很有可能会产生精度丢失问题。我们都知道计算机底层在进行运算的时候,使用的都是二进制数据; 当我们在程序中写了一个十进制数据 ,在
进行运算的时候,计算机会将这个十进制数据转换成二进制数据,然后再进行运算,计算完毕以后计算机会把运算的结果再转换成十进制数据给我们展示; 如果我们使用的是整数类型的数据进行计算,那
么在把十进制数据转换成二进制数据的时候不会存在精度问题; 如果我们的数据是一个浮点类型的数据,有的时候计算机并不会将这个数据完全转换成一个二进制数据,而是将这个将其转换成一个无限的
趋近于这个十进数的二进制数据; 这样使用一个不太准确的数据进行运算的时候, 最终就会造成精度丢失;为了提高精度,Java 就给我们提供了 BigDecimal 供我们进行数据运算。
72 概述 查看 API 文档,我们可以看到 API 文档中关于 BigDecimal 类的定义如下:
BigDecimal 所在包是在 javamath 包下,因此在使用的时候就需要进行导包。我们可以使用 BigDecimal 类进行更加精准的数据计算。
73 常见方法 构造方法
要用 BigDecimal 类,那么就需要首先学习一下如何去创建 BigDecimal 的对象。通过查看 API 文档,我们可以发现 Jdk 中针对 BigDecimal 类提供了很多的构造方法,但是最常用的构造方法是:
了解完常见的构造方法以后,我们接下来就重点介绍一下常见的成员方法。
常见成员方法
BigDecimal 类中使用最多的还是提供的进行四则运算的方法,如下:
1 2 3 4 public BigDecimal add (BigDecimal value) public BigDecimal subtract (BigDecimal value) public BigDecimal multiply (BigDecimal value) public BigDecimal divide (BigDecimal value)
接下来我们就来通过一些案例演示一下这些成员方法的使用。
案例 1 :演示基本的四则运算
代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class BigDecimalDemo01 { public static void main (String[] args) { BigDecimal b1 = new BigDecimal ("03" ) ; BigDecimal b2 = new BigDecimal ("4" ) ; Systemoutprintln(b1add(b2)); Systemoutprintln(b1subtract(b2)); Systemoutprintln(b1multiply(b2)); Systemoutprintln(b1divide(b2)); } }
运行程序进行测试,控制台输出结果如下:
此时我们可以看到使用 BigDecimal 类来完成浮点数的计算不会存在损失精度的问题。
案例 2 :演示除法的特殊情况
如果使用 BigDecimal 类型的数据进行除法运算的时候,得到的结果是一个无限循环小数,那么就会报错:ArithmeticException。 如下代码所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class BigDecimalDemo02 { public static void main (String[] args) { BigDecimal b1 = new BigDecimal ("1" ) ; BigDecimal b2 = new BigDecimal ("3" ) ; Systemoutprintln(b1divide(b2)); } }
运行程序进行测试,控制台输出结果如下所示:
1 2 3 Exception in thread "main" javalangArithmeticException: Non-terminating decimal expansion; no exact representable decimal result at javabase/javamathBigDecimaldivide(BigDecimaljava:1716 ) at comitheimaapibigdecimaldemo02BigDecimalDemo02main (BigDecimalDemo02java:14 )
针对这个问题怎么解决,此时我们就需要使用到 BigDecimal 类中另外一个 divide 方法,如下所示:
1 BigDecimal divide (BigDecimal divisor, int scale, int roundingMode)
上述 divide 方法参数说明:
1 2 3 4 5 divisor: 除数对应的BigDecimal对象; scale: 精确的位数; roundingMode: 取舍模式; 取舍模式被封装到了RoundingMode这个枚举类中(关于枚举我们后期再做重点讲解),在这个枚举类中定义了很多种取舍方式。最常见的取舍方式有如下几个: UP(直接进1) , FLOOR(直接删除) , HALF_UP(4舍五入),我们可以通过如下格式直接访问这些取舍模式:枚举类名变量名
接下来我们就来演示一下这些取舍模式,代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class BigDecimalDemo02 { public static void main (String[] args) { method_03() ; } public static void method_03 () { BigDecimal b1 = new BigDecimal ("03" ) ; BigDecimal b2 = new BigDecimal ("4" ) ; Systemoutprintln(b1divide(b2 , 2 , RoundingModeHALF_UP)); } public static void method_02 () { BigDecimal b1 = new BigDecimal ("1" ) ; BigDecimal b2 = new BigDecimal ("3" ) ; Systemoutprintln(b1divide(b2 , 2 , RoundingModeFLOOR)); } public static void method_01 () { BigDecimal b1 = new BigDecimal ("1" ) ; BigDecimal b2 = new BigDecimal ("3" ) ; Systemoutprintln(b1divide(b2 , 2 , RoundingModeUP)); } }
小结:后期在进行两个数的除法运算的时候,我们常常使用的是可以设置取舍模式的 divide 方法。
74 底层存储方式: 把数据看成字符串,遍历得到里面的每一个字符,把这些字符在 ASCII 码表上的值,都存储到数组中。