課程目標
能夠熟練使用Math類中的常見方法
能夠熟練使用System類中的常見方法
能夠理解Object類的常見方法作用
能夠熟練使用Objects類的常見方法
能夠熟練使用BigInteger類的常見方法
能夠熟練使用BigDecimal類的常見方法
1 Math類
1.1 概述
tips:了解內容
查看API文檔,我們可以看到API文檔中關于Math類的定義如下:
Math類所在包為java.lang包,因此在使用的時候不需要進行導包。并且Math類被final修飾了,因此該類是不能被繼承的。
Math類包含執行基本數字運算的方法,我們可以使用Math類完成基本的數學運算。
要想使用Math類我們就需要先創建該類的對象,那么創建對象就需要借助于構造方法。因此我們就需要首先查看一下API文檔,看看API文檔中針對Math類有沒有提供對應的構造方法。通過API文檔來查看
一下Math類的成員,如下所示:
在API文檔中沒有體現可用的構造方法,因此我們就不能直接通過new關鍵字去創建Math類的對象。同時我們發現Math類中的方法都是靜態的,因此在使用的時候我們可以直接通過類名去調用。在Math類中
定義了很多數學運算的方法,但是我們并不可能將所有的方法學習一遍,我們主要學習的就是一些常見的方法。
1.2 常見方法
tips:重點講解內容
常見方法介紹
我們要學習的Math的常見方法如下所示:
public static int abs(int a) // 返回參數的絕對值
public static double ceil(double a) // 返回大于或等于參數的最小整數
public static double floor(double a) // 返回小于或等于參數的最大整數
public static int round(float a) // 按照四舍五入返回最接近參數的int類型的值
public static int max(int a,int b) // 獲取兩個int值中的較大值
public static int min(int a,int b) // 獲取兩個int值中的較小值
public static double pow (double a,double b) // 計算a的b次冪的值
public static double random() // 返回一個[0.0,1.0)的隨機值
案例演示
接下來我們就來演示一些這些方法的執行效果,如下所示:
public class MathDemo01 {public static void main(String[] args) {// public static int abs(int a) 返回參數的絕對值System.out.println("-2的絕對值為:" + Math.abs(-2));System.out.println("2的絕對值為:" + Math.abs(2));// public static double ceil(double a) 返回大于或等于參數的最小整數System.out.println("大于或等于23.45的最小整數位:" + Math.ceil(23.45));System.out.println("大于或等于-23.45的最小整數位:" + Math.ceil(-23.45));// public static double floor(double a) 返回小于或等于參數的最大整數System.out.println("小于或等于23.45的最大整數位:" + Math.floor(23.45));System.out.println("小于或等于-23.45的最大整數位:" + Math.floor(-23.45));// public static int round(float a) 按照四舍五入返回最接近參數的intSystem.out.println("23.45四舍五入的結果為:" + Math.round(23.45));System.out.println("23.55四舍五入的結果為:" + Math.round(23.55));// public static int max(int a,int b) 返回兩個int值中的較大值System.out.println("23和45的最大值為: " + Math.max(23, 45));// public static int min(int a,int b) 返回兩個int值中的較小值System.out.println("12和34的最小值為: " + Math.min(12 , 34));// public static double pow (double a,double b)返回a的b次冪的值System.out.println("2的3次冪計算結果為: " + Math.pow(2,3));// public static double random()返回值為double的正值,[0.0,1.0)System.out.println("獲取到的0-1之間的隨機數為: " + Math.random());}}
運行程序進行測試,控制臺輸出結果如下:
-2的絕對值為:2
2的絕對值為:2
大于或等于23.45的最小整數位:24.0
大于或等于-23.45的最小整數位:-23.0
小于或等于23.45的最大整數位:23.0
小于或等于-23.45的最大整數位:-24.0
23.45四舍五入的結果為:23
23.55四舍五入的結果為:24
23和45的最大值為: 45
12和34的最小值為: 12
2的3次冪計算結果為: 8.0
獲取到的0-1之間的隨機數為: 0.7322484131745958
1.3 算法小題(質數)
需求:
判斷一個數是否為一個質數
代碼實現:
public class MathDemo2 {public static void main(String[] args) {//判斷一個數是否為一個質數System.out.println(isPrime(997));//997 2~996 995次}public static boolean isPrime(int number) {int count = 0;for (int i = 2; i <= Math.sqrt(number); i++) {count++;if (number % i == 0) {return false;}}System.out.println(count);return true;}
}
1.4 算法小題(自冪數)
自冪數,一個n位自然數等于自身各個數位上數字的n次冪之和
舉例1:三位數 13 + 53 + 3^3 = 153
舉例2:四位數 14 + 64 + 34 + 43 = 1634
如果自冪數是:
- 一位自冪數,也叫做:獨身數
- 三位自冪數:水仙花數 四位自冪數:四葉玫瑰數
- 五位自冪數:五角星數 六位自冪數:六合數
- 七位自冪數:北斗七星數 八位自冪數:八仙數
- 九位自冪數:九九重陽數 十位自冪數:十全十美數
要求1:統計一共有多少個水仙花數。
要求2:(課后作業)證明沒有兩位的自冪數。
要求3:(課后作業)分別統計有多少個四葉玫瑰數和五角星數。(答案:都是3個)
//水仙花數:100 ~ 999
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 = Math.pow(ge, 3) + Math.pow(shi, 3) + Math.pow(bai, 3);if (sum == i) {count++;//System.out.println(i);System.out.println(count);}
}
1.5 課后練習
要求2:(課后作業)證明沒有兩位的自冪數。
要求3:(課后作業)分別統計有多少個四葉玫瑰數和五角星數。(答案:都是3個)
2 System類
2.1 概述
tips:了解內容
查看API文檔,我們可以看到API文檔中關于System類的定義如下:
System類所在包為java.lang包,因此在使用的時候不需要進行導包。并且System類被final修飾了,因此該類是不能被繼承的。
System包含了系統操作的一些常用的方法。比如獲取當前時間所對應的毫秒值,再比如終止當前JVM等等。
要想使用System類我們就需要先創建該類的對象,那么創建對象就需要借助于構造方法。因此我們就需要首先查看一下API文檔,看看API文檔中針對System類有沒有提供對應的構造方法。通過API文檔來
查看一下System類的成員,如下所示:
在API文檔中沒有體現可用的構造方法,因此我們就不能直接通過new關鍵字去創建System類的對象。同時我們發現System類中的方法都是靜態的,因此在使用的時候我們可以直接通過類名去調用(Nested
Class Summary內部類或者內部接口的描述)。
2.2 常見方法
tips:重點講解內容
常見方法介紹
我們要學習的System類中的常見方法如下所示:
public static long currentTimeMillis() // 獲取當前時間所對應的毫秒值(當前時間為0時區所對應的時間即就是英國格林尼治天文臺舊址所在位置)
public static void exit(int status) // 終止當前正在運行的Java虛擬機,0表示正常退出,非零表示異常退出
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); // 進行數值元素copy
案例演示
接下來我們就來通過一些案例演示一下這些方法的特點。
案例1:演示currentTimeMillis方法
public class SystemDemo01 {public static void main(String[] args) {// 獲取當前時間所對應的毫秒值long millis = System.currentTimeMillis();// 輸出結果System.out.println("當前時間所對應的毫秒值為:" + millis);}}
運行程序進行測試,控制臺的輸出結果如下:
當前時間所對應的毫秒值為:1576050298343
獲取到當前時間的毫秒值的意義:我們常常來需要統計某一段代碼的執行時間。此時我們就可以在執行這段代碼之前獲取一次時間,在執行完畢以后再次獲取一次系統時間,然后計算兩個時間的差值,
這個差值就是這段代碼執行完畢以后所需要的時間。如下代碼所示:
public class SystemDemo2 {public static void main(String[] args) {//判斷1~100000之間有多少個質數long start = System.currentTimeMillis();for (int i = 1; i <= 100000; i++) {boolean flag = isPrime2(i);if (flag) {System.out.println(i);}}long end = System.currentTimeMillis();//獲取程序運行的總時間System.out.println(end - start); //方式一:1514 毫秒 方式二:71毫秒}//以前判斷是否為質數的方式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;}
}
案例2:演示exit方法
public class SystemDemo01 {public static void main(String[] args) {// 輸出System.out.println("程序開始執行了.....");// 終止JVMSystem.exit(0);// 輸出System.out.println("程序終止了..........");}}
運行程序進行測試,控制臺輸出結果如下:
程序開始執行了.....
此時可以看到在控制臺只輸出了"程序開始了...",由于JVM終止了,因此輸出"程序終止了..."這段代碼沒有被執行。
案例3:演示arraycopy方法
方法參數說明:
// src: 源數組
// srcPos: 源數值的開始位置
// dest: 目標數組
// destPos: 目標數組開始位置
// length: 要復制的元素個數
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
代碼如下所示:
public class SystemDemo01 {public static void main(String[] args) {// 定義源數組int[] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ;// 定義目標數組int[] desArray = new int[10] ;// 進行數組元素的copy: 把srcArray數組中從0索引開始的3個元素,從desArray數組中的1索引開始復制過去System.arraycopy(srcArray , 0 , desArray , 1 , 3);// 遍歷目標數組for(int x = 0 ; x < desArray.length ; x++) {if(x != desArray.length - 1) {System.out.print(desArray[x] + ", ");}else {System.out.println(desArray[x]);}}}}
運行程序進行測試,控制臺輸出結果如下所示:
0, 23, 45, 67, 0, 0, 0, 0, 0, 0
通過控制臺輸出結果我們可以看到,數組元素的確進行復制了。
使用這個方法我們也可以完成數組元素的刪除操作,如下所示:
public class SystemDemo02 {public static void main(String[] args) {// 定義一個數組int[] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ;// 刪除數組中第3個元素(67):要刪除67這個元素,我們只需要將67后面的其他元素依次向前進行移動即可System.arraycopy(srcArray , 3 , srcArray , 2 , 3);// 遍歷srcArray數組for(int x = 0 ; x < srcArray.length ; x++) {if(x != desArray.length - 1) {System.out.print(srcArray[x] + ", ");}else {System.out.println(srcArray[x]);}}}
}
運行程序進行測試,控制臺的輸出結果如下所示:
23, 45, 89, 14, 56, 56
通過控制臺輸出結果我們可以看到此時多出了一個56元素,此時我們只需要將最后一個位置設置為0即可。如下所示:
public class SystemDemo02 {public static void main(String[] args) {// 定義一個數組int[] srcArray = {23 , 45 , 67 , 89 , 14 , 56 } ;// 刪除數組中第3個元素(67):要刪除67這個元素,我們只需要將67后面的其他元素依次向前進行移動即可System.arraycopy(srcArray , 3 , srcArray , 2 , 3);// 將最后一個位置的元素設置為0srcArray[srcArray.length - 1] = 0 ;// 遍歷srcArray數組for(int x = 0 ; x < srcArray.length ; x++) {if(x != srcArray.length - 1 ) {System.out.print(srcArray[x] + ", ");}else {System.out.println(srcArray[x]);}}}
}
運行程序進行測試,控制臺輸出結果如下所示:
23, 45, 89, 14, 56, 0
此時我們可以看到元素"67"已經被刪除掉了。67后面的其他元素依次向前進行移動了一位。
arraycopy方法底層細節:
1.如果數據源數組和目的地數組都是基本數據類型,那么兩者的類型必須保持一致,否則會報錯
2.在拷貝的時候需要考慮數組的長度,如果超出范圍也會報錯
3.如果數據源數組和目的地數組都是引用數據類型,那么子類類型可以賦值給父類類型
代碼示例:
public class SystemDemo3 {public static void main(String[] args) {//public static void arraycopy(數據源數組,起始索引,目的地數組,起始索引,拷貝個數) 數組拷貝//細節://1.如果數據源數組和目的地數組都是基本數據類型,那么兩者的類型必須保持一致,否則會報錯//2.在拷貝的時候需要考慮數組的長度,如果超出范圍也會報錯//3.如果數據源數組和目的地數組都是引用數據類型,那么子類類型可以賦值給父類類型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];//把arr1中對象的地址值賦值給arr2中System.arraycopy(arr1, 0, arr2, 0, 3);//遍歷數組arr2for (int i = 0; i < arr2.length; i++) {Student stu = (Student) arr2[i];System.out.println(stu.getName() + "," + stu.getAge());}}
}class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}/*** 獲取** @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;}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
3.1 概述
Runtime表示Java中運行時對象,可以獲取到程序運行時設計到的一些信息
3.2 常見方法
常見方法介紹
我們要學習的Object類中的常見方法如下所示:
public static Runtime getRuntime() //當前系統的運行環境對象
public void exit(int status) //停止虛擬機
public int availableProcessors() //獲得CPU的線程數
public long maxMemory() //JVM能從系統中獲取總內存大小(單位byte)
public long totalMemory() //JVM已經從系統中獲取總內存大小(單位byte)
public long freeMemory() //JVM剩余內存大小(單位byte)
public Process exec(String command) //運行cmd命令
代碼示例:
public class RunTimeDemo1 {public static void main(String[] args) throws IOException {/*public static Runtime getRuntime() 當前系統的運行環境對象public void exit(int status) 停止虛擬機public int availableProcessors() 獲得CPU的線程數public long maxMemory() JVM能從系統中獲取總內存大小(單位byte)public long totalMemory() JVM已經從系統中獲取總內存大小(單位byte)public long freeMemory() JVM剩余內存大小(單位byte)public Process exec(string command) 運行cmd命令*///1.獲取Runtime的對象//Runtime r1 =Runtime.getRuntime();//2.exit 停止虛擬機//Runtime.getRuntime().exit(0);//System.out.println("看看我執行了嗎?");//3.獲得CPU的線程數System.out.println(Runtime.getRuntime().availableProcessors());//8//4.總內存大小,單位byte字節System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);//4064//5.已經獲取的總內存大小,單位byte字節System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);//254//6.剩余內存大小System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);//251//7.運行cmd命令//shutdown :關機//加上參數才能執行//-s :默認在1分鐘之后關機//-s -t 指定時間 : 指定關機時間//-a :取消關機操作//-r: 關機并重啟Runtime.getRuntime().exec("shutdown -s -t 3600");}
}
3.3 惡搞好基友
需求:
界面上方按鈕默認隱藏
界面中間有一個提示文本和三個按鈕
當你的好基友點擊中間三個按鈕的時候就在N秒之后關機,不同的按鈕N的值不一樣
任意一個按鈕被點擊之后,上方了按鈕出現。當點擊上方按鈕之后取消關機任務
public class Test {public static void main(String[] args) {new MyJframe();}
}
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();//顯示this.setVisible(true);}private void initView() {this.getContentPane().removeAll();if (flag) {//展示按鈕dadBut.setBounds(50, 20, 100, 30);dadBut.addActionListener(this);this.getContentPane().add(dadBut);}JLabel text = new JLabel("你覺得自己帥嗎?");text.setFont(new Font("微軟雅黑", 0, 30));text.setBounds(120, 150, 300, 50);yesBut.setBounds(200, 250, 100, 30);midBut.setBounds(200, 325, 100, 30);noBut.setBounds(160, 400, 180, 30);yesBut.addActionListener(this);midBut.addActionListener(this);noBut.addActionListener(this);this.getContentPane().add(text);this.getContentPane().add(yesBut);this.getContentPane().add(midBut);this.getContentPane().add(noBut);this.getContentPane().repaint();}private void initJFrame() {//設置寬高this.setSize(500, 600);//設置標題this.setTitle("惡搞好基友");//設置關閉模式this.setDefaultCloseOperation(3);//置頂this.setAlwaysOnTop(true);//居中this.setLocationRelativeTo(null);//取消內部默認布局this.setLayout(null);}@Overridepublic void actionPerformed(ActionEvent e) {Object obj = e.getSource();if (obj == yesBut) {//給好基友一個彈框showJDialog("xxx,你太自信了,給你一點小懲罰");try {Runtime.getRuntime().exec("shutdown -s -t 3600");} catch (IOException ioException) {ioException.printStackTrace();}flag = true;initView();} else if (obj == midBut) {System.out.println("你的好基友點擊了一般般吧");//給好基友一個彈框showJDialog("xxx,你還是太自信了,也要給你一點小懲罰");try {Runtime.getRuntime().exec("shutdown -s -t 7200");} catch (IOException ioException) {ioException.printStackTrace();}flag = true;initView();} else if (obj == noBut) {System.out.println("你的好基友點擊了不帥");//給好基友一個彈框showJDialog("xxx,你還是有一點自知之明的,也要給你一點小懲罰");try {Runtime.getRuntime().exec("shutdown -s -t 1800");} catch (IOException ioException) {ioException.printStackTrace();}flag = true;initView();} else if (obj == dadBut) {//給好基友一個彈框showJDialog("xxx,這次就饒了你~");try {Runtime.getRuntime().exec("shutdown -a");} catch (IOException ioException) {ioException.printStackTrace();}}}public void showJDialog(String content) {//創建一個彈框對象JDialog jDialog = new JDialog();//給彈框設置大小jDialog.setSize(200, 150);//讓彈框置頂jDialog.setAlwaysOnTop(true);//讓彈框居中jDialog.setLocationRelativeTo(null);//彈框不關閉永遠無法操作下面的界面jDialog.setModal(true);//創建Jlabel對象管理文字并添加到彈框當中JLabel warning = new JLabel(content);warning.setBounds(0, 0, 200, 150);jDialog.getContentPane().add(warning);//讓彈框展示出來jDialog.setVisible(true);}
}
4 Object類
4.1 概述
tips:重點講解內容
查看API文檔,我們可以看到API文檔中關于Object類的定義如下:
Object類所在包是java.lang包。Object 是類層次結構的根,每個類都可以將 Object 作為超類。所有類都直接或者間接的繼承自該類;換句話說,該類所具備的方法,其他所有類都繼承了。
查看API文檔我們可以看到,在Object類中提供了一個無參構造方法,如下所示:
但是一般情況下我們很少去主動的創建Object類的對象,調用其對應的方法。更多的是創建Object類的某個子類對象,然后通過子類對象調用Object類中的方法。
4.2 常見方法
tips:重點講解內容
常見方法介紹
我們要學習的Object類中的常見方法如下所示:
public String toString() //返回該對象的字符串表示形式(可以看做是對象的內存地址值)
public boolean equals(Object obj) //比較兩個對象地址值是否相等;true表示相同,false表示不相同
protected Object clone() //對象克隆
案例演示
接下來我們就來通過一些案例演示一下這些方法的特點。
案例1:演示toString方法
實現步驟:
- 創建一個學生類,提供兩個成員變量(name , age);并且提供對應的無參構造方法和有參構造方法以及get/set方法
- 創建一個測試類(ObjectDemo01),在測試類的main方法中去創建學生對象,然后調用該對象的toString方法獲取該對象的字符串表現形式,并將結果進行輸出
如下所示:
Student類
public class Student {private String name ; // 姓名private String age ; // 年齡// 無參構造方法和有參構造方法以及get和set方法略...}
ObjectDemo01測試類
public class ObjectDemo01 {public static void main(String[] args) {// 創建學生對象Student s1 = new Student("itheima" , "14") ;// 調用toString方法獲取s1對象的字符串表現形式String result1 = s1.toString();// 輸出結果System.out.println("s1對象的字符串表現形式為:" + result1);}}
運行程序進行測試,控制臺輸出結果如下所示:
s1對象的字符串表現形式為:com.itheima.api.system.demo04.Student@3f3afe78
為什么控制臺輸出的結果為:com.itheima.api.system.demo04.Student@3f3afe78; 此時我們可以查看一下Object類中toString方法的源碼,如下所示:
public String toString() { // Object類中toString方法的源碼定義return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
其中getClass().getName()對應的結果就是:com.itheima.api.system.demo04.Student;Integer.toHexString(hashCode())對應的結果就是3f3afe78。
我們常常將"com.itheima.api.system.demo04.Student@3f3afe78"這一部分稱之為對象的內存地址值。但是一般情況下獲取對象的內存地址值沒有太大的意義。獲取對象的成員變量的字符串拼接形式才
算有意義,怎么實現呢?此時我們就需要在Student類中重寫Object的toString方法。我們可以通過idea開發工具進行實現,具體步驟如下所示:
- 在空白處使用快捷鍵:alt + insert。此時會彈出如下的對話框
- 選擇toString,此時會彈出如下的對話框
同時選擇name和age屬性,點擊OK。此時就會完成toString方法的重寫,代碼如下所示:
@Override
public String toString() {return "Student{" +"name='" + name + '\'' +", age='" + age + '\'' +'}';
}
這段代碼就是把Student類中的成員變量進行了字符串的拼接。重寫完畢以后,再次運行程序,控制臺輸出結果如下所示:
s1對象的字符串表現形式為:Student{name='itheima', age='14'}
此時我們就可以清楚的查看Student的成員變量值,因此重寫toString方法的意義就是以良好的格式,更方便的展示對象中的屬性值
我們再來查看一下如下代碼的輸出:
// 創建學生對象
Student s1 = new Student("itheima" , "14") ;// 直接輸出對象s1
System.out.println(s1);
運行程序進行測試,控制臺輸出結果如下所示:
Student{name='itheima', age='14'}
我們可以看到和剛才的輸出結果是一致的。那么此時也就證明直接輸出一個對象,那么會默認調用對象的toString方法,因此如上代碼的等同于如下代碼:
// 創建學生對象
Student s1 = new Student("itheima" , "14") ;// 調用s1的toString方法,把結果進行輸出
System.out.println(s1.toString());
因此后期為了方便進行測試,我們常常是通過輸出語句直接輸出一個對象的名稱。
小結:
- 在通過輸出語句輸出一個對象時,默認調用的就是toString()方法
- 輸出地址值一般沒有意義,我們可以通過重寫toString方法去輸出對應的成員變量信息(快捷鍵:atl + insert , 空白處 右鍵 -> Generate -> 選擇toString)
- toString方法的作用:以良好的格式,更方便的展示對象中的屬性值
- 一般情況下Jdk所提供的類都會重寫Object類中的toString方法
案例2:演示equals方法
實現步驟:
- 在測試類(ObjectDemo02)的main方法中,創建兩個學生對象,然后比較兩個對象是否相同
代碼如下所示:
public class ObjectDemo02 {public static void main(String[] args) {// 創建兩個學生對象Student s1 = new Student("itheima" , "14") ;Student s2 = new Student("itheima" , "14") ;// 比較兩個對象是否相等System.out.println(s1 == s2);}}
運行程序進行測試,控制臺的輸出結果如下所示:
false
因為"=="號比較的是對象的地址值,而我們通過new關鍵字創建了兩個對象,它們的地址值是不相同的。因此比較結果就是false。
我們嘗試調用Object類中的equals方法進行比較,代碼如下所示:
// 調用equals方法比較兩個對象是否相等
boolean result = s1.equals(s2);// 輸出結果
System.out.println(result);
運行程序進行測試,控制臺的輸出結果為:
false
為什么結果還是false呢?我們可以查看一下Object類中equals方法的源碼,如下所示:
public boolean equals(Object obj) { // Object類中的equals方法的源碼return (this == obj);
}
通過源碼我們可以發現默認情況下equals方法比較的也是對象的地址值。比較內存地址值一般情況下是沒有意義的,我們希望比較的是對象的屬性,如果兩個對象的屬性相同,我們認為就是同一個對象;
那么要比較對象的屬性,我們就需要在Student類中重寫Object類中的equals方法。equals方法的重寫,我們也可以使用idea開發工具完成,具體的操作如下所示:
- 在空白處使用快捷鍵:alt + insert。此時會彈出如下的對話框
- 選擇equals() and hashCode()方法,此時會彈出如下的對話框
點擊next,會彈出如下對話框:
選擇neme和age屬性點擊next,此時就會彈出如下對話框:
取消name和age屬性(因為此時選擇的是在生成hashCode方法時所涉及到的屬性,關于hashCode方法后期再做重點介紹),點擊Finish完成生成操作。生成的equals方法和hashCode方法如下:
@Override
public boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return Objects.equals(name, student.name) && Objects.equals(age, student.age); // 比較的是對象的name屬性值和age屬性值
}@Override
public int hashCode() {return 0;
}
hashCode方法我們暫時使用不到,可以將hashCode方法刪除。重寫完畢以后運行程序進行測試,控制臺輸出結果如下所示:
true
此時equals方法比較的是對象的成員變量值,而s1和s2兩個對象的成員變量值都是相同的。因此比較完畢以后的結果就是true。
小結:
- 默認情況下equals方法比較的是對象的地址值
- 比較對象的地址值是沒有意義的,因此一般情況下我們都會重寫Object類中的equals方法
案例2:對象克隆
把A對象的屬性值完全拷貝給B對象,也叫對象拷貝,對象復制
對象克隆的分類:
深克隆和淺克隆
淺克隆:
不管對象內部的屬性是基本數據類型還是引用數據類型,都完全拷貝過來
基本數據類型拷貝過來的是具體的數據,引用數據類型拷貝過來的是地址值。
Object類默認的是淺克隆
深克隆:
基本數據類型變量記錄的數據值直接拷貝過來;
字符串復用(StringTable(串池));
引用數據類型會重新創建新的
代碼實現:
package com.itheima.a04objectdemo;public class ObjectDemo4 {public static void main(String[] args) throws CloneNotSupportedException {// protected object clone(int a) 對象克隆 //1.先創建一個對象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);//2.克隆對象//細節://方法在底層會幫我們創建一個對象,并把原對象中的數據拷貝過去。//書寫細節://1.重寫Object中的clone方法//2.讓javabean類實現Cloneable接口//3.創建原對象并調用clone就可以了//User u2 =(User)u1.clone();//驗證一件事情:Object中的克隆是淺克隆//想要進行深克隆,就需要重寫clone方法并修改里面的方法體//int[] arr = u1.getData();//arr[0] = 100;//System.out.println(u1);//System.out.println(u2);//以后一般會用第三方工具進行克隆//1.第三方寫的代碼導入到項目中//2.編寫代碼//Gson gson =new Gson();//把對象變成一個字符串//String s=gson.toJson(u1);//再把字符串變回對象就可以了//User user =gson.fromJson(s, User.class);//int[] arr=u1.getData();//arr[0] = 100;//打印對象//System.out.println(user);}
}package com.itheima.a04objectdemo;import java.util.StringJoiner;//Cloneable
//如果一個接口里面沒有抽象方法
//表示當前的接口是一個標記性接口
//現在Cloneable表示一旦實現了,那么當前類的對象就可以被克降
//如果沒有實現,當前類的對象就不能克隆
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) {this.id = id;this.username = username;this.password = password;this.path = path;this.data = data;}/*** 獲取** @return id*/public int getId() {return id;}/*** 設置** @param id*/public void setId(int id) {this.id = id;}/*** 獲取** @return username*/public String getUsername() {return username;}/*** 設置** @param username*/public void setUsername(String username) {this.username = username;}/*** 獲取** @return password*/public String getPassword() {return password;}/*** 設置** @param password*/public void setPassword(String password) {this.password = password;}/*** 獲取** @return path*/public String getPath() {return path;}/*** 設置** @param path*/public void setPath(String path) {this.path = path;}/*** 獲取** @return data*/public int[] getData() {return data;}/*** 設置** @param data*/public void setData(int[] data) {this.data = data;}public String toString() {return "角色編號為:" + id + ",用戶名為:" + username + "密碼為:" + password + ", 游戲圖片為:" + path + ", 進度:" + arrToString();}public String arrToString() {StringJoiner sj = new StringJoiner(", ", "[", "]");for (int i = 0; i < data.length; i++) {sj.add(data[i] + "");}return sj.toString();}@Overrideprotected 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;}
}
5 Objects類
ps: 該equals先去判斷對象是否為空,不為空在用在對象去調用equals方法(不重寫比較的還是地址值,重寫了才是比較屬性值)
5.1 概述
tips:了解內容
查看API文檔,我們可以看到API文檔中關于Objects類的定義如下:
Objects類所在包是在java.util包下,因此在使用的時候需要進行導包。并且Objects類是被final修飾的,因此該類不能被繼承。
Objects類提供了一些對象常見操作的方法。比如判斷對象是否相等,判斷對象是否為null等等。
接下來我們來查看一下API文檔,看一下Objects類中的成員,如下所示:
我們可以發現Objects類中無無參構造方法,因此我們不能使用new關鍵字去創建Objects的對象。同時我們可以發現Objects類中所提供的方法都是靜態的。因此我們可以通過類名直接去調用這些方法。
5.2 常見方法
tips:重點講解內容
常見方法介紹
我們要重點學習的Objects類中的常見方法如下所示:
public static String toString(Object o) // 獲取對象的字符串表現形式
public static boolean equals(Object a, Object b) // 比較兩個對象是否相等
public static boolean isNull(Object obj) // 判斷對象是否為null
public static boolean nonNull(Object obj) // 判斷對象是否不為null
我們要了解的Objects類中的常見方法如下所示:
public static <T> T requireNonNull(T obj) // 檢查對象是否不為null,如果為null直接拋出異常;如果不是null返回該對象;
public static <T> T requireNonNullElse(T obj, T defaultObj) // 檢查對象是否不為null,如果不為null,返回該對象;如果為null返回defaultObj值
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) // 檢查對象是否不為null,如果不為null,返回該對象;如果 // 為null,返回由Supplier所提供的值
上述方法中的T可以理解為是Object類型。
案例演示
接下來我們就來通過一些案例演示一下Objects類中的這些方法特點。
案例1:演示重點學習方法
實現步驟:
- 創建一個學生類,提供兩個成員變量(name , age);并且提供對應的無參構造方法和有參構造方法以及get/set方法,并且重寫toString方法和equals方法
- 創建一個測試類(ObjectsDemo01), 在該類中編寫測試代碼
如下所示:
Student類
public class Student {private String name ; // 姓名private String age ; // 年齡// 其他代碼略...}
ObjectsDemo01測試類
public class ObjectsDemo01 {public static void main(String[] args) {// 調用方法method_04() ;}// 測試nonNull方法public static void method_04() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects類中的nonNull方法boolean result = Objects.nonNull(s1);// 輸出結果System.out.println(result);}// 測試isNull方法public static void method_03() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects類中的isNull方法boolean result = Objects.isNull(s1);// 輸出結果System.out.println(result);}// 測試equals方法public static void method_02() {// 創建兩個學生對象Student s1 = new Student("itheima" , "14") ;Student s2 = new Student("itheima" , "14") ;// 調用Objects類中的equals方法,比較兩個對象是否相等boolean result = Objects.equals(s1, s2); // 如果Student沒有重寫Object類中的equals方法,此處比較的還是對象的地址值// 輸出結果System.out.println(result);}// 測試toString方法public static void method_01() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects中的toString方法,獲取s1對象的字符串表現形式String result = Objects.toString(s1); // 如果Student沒有重寫Object類中的toString方法,此處還是返回的對象的地址值// 輸出結果System.out.println(result);}}
案例2:演示需要了解的方法
public class ObjectsDemo02 {public static void main(String[] args) {// 調用方法method_03();}// 演示requireNonNullElseGetpublic static void method_03() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects對象的requireNonNullElseGet方法,該方法的第二個參數是Supplier類型的,查看源碼我們發現Supplier是一個函數式接口,// 那么我們就可以為其傳遞一個Lambda表達式,而在Supplier接口中所定義的方法是無參有返回值的方法,因此具體調用所傳入的Lambda表達式如下所示Student student = Objects.requireNonNullElseGet(s1, () -> {return new Student("itcast", "14");});// 輸出System.out.println(student);}// 演示requireNonNullElsepublic static void method_02() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects對象的requireNonNullElse方法Student student = Objects.requireNonNullElse(s1, new Student("itcast", "14"));// 輸出System.out.println(student);}// 演示requireNonNullpublic static void method_01() {// 創建一個學生對象Student s1 = new Student("itheima" , "14") ;// 調用Objects對象的requireNonNull方法Student student = Objects.requireNonNull(s1);// 輸出System.out.println(student);}}
注:了解性的方法可以可以作為擴展視頻進行下發。
6 BigInteger類
6.1 引入
平時在存儲整數的時候,Java中默認是int類型,int類型有取值范圍:-2147483648 ~ 2147483647。如果數字過大,我們可以使用long類型,但是如果long類型也表示不下怎么辦呢?
就需要用到BigInteger,可以理解為:大的整數。
有多大呢?理論上最大到42億的21億次方
基本上在內存撐爆之前,都無法達到這個上限。
6.2 概述
查看API文檔,我們可以看到API文檔中關于BigInteger類的定義如下:
BigInteger所在包是在java.math包下,因此在使用的時候就需要進行導包。我們可以使用BigInteger類進行大整數的計算
6.3 常見方法
構造方法
public BigInteger(int num, Random rnd) //獲取隨機大整數,范圍:[0 ~ 2的num次方-1]
public BigInteger(String val) //獲取指定的大整數
public BigInteger(String val, int radix) //獲取指定進制的大整數下面這個不是構造,而是一個靜態方法獲取BigInteger對象
public static BigInteger valueOf(long val) //靜態方法獲取BigInteger的對象,內部有優化
構造方法小結:
- 如果BigInteger表示的數字沒有超出long的范圍,可以用靜態方法獲取。
- 如果BigInteger表示的超出long的范圍,可以用構造方法獲取。
- 對象一旦創建,BigInteger內部記錄的值不能發生改變。
- 只要進行計算都會產生一個新的BigInteger對象
常見成員方法
BigDecimal類中使用最多的還是提供的進行四則運算的方法,如下:
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) //轉為int類型整數,超出范圍數據有誤
代碼實現:
package com.itheima.a06bigintegerdemo;import java.math.BigInteger;public class BigIntegerDemo1 {public static void main(String[] args) {/*public BigInteger(int num, Random rnd) 獲取隨機大整數,范圍:[0~ 2的num次方-11public BigInteger(String val) 獲取指定的大整數public BigInteger(String val, int radix) 獲取指定進制的大整數public static BigInteger valueOf(long val) 靜態方法獲取BigInteger的對象,內部有優化細節:對象一旦創建里面的數據不能發生改變。*///1.獲取一個隨機的大整數/* Random r=new Random();for (int i = e; i < 100; i++) {BigInteger bd1 = new BigInteger(4,r);System.out.println(bd1);//[@ ~ 15]}}*///2.獲取一個指定的大整數,可以超出long的取值范圍//細節:字符串中必須是整數,否則會報錯/* BigInteger bd2 = new BigInteger("1.1");System.out.println(bd2);*//*BigInteger bd3 = new BigInteger("abc");System.out.println(bd3);*///3.獲取指定進制的大整數//細節://1.字符串中的數字必須是整數//2.字符串中的數字必須要跟進制吻合。//比如二進制中,那么只能寫日和1,寫其他的就報錯。BigInteger bd4 = new BigInteger("123", 2);System.out.println(bd4);//4.靜態方法獲取BigInteger的對象,內部有優化//細節://1.能表示范圍比較小,只能在long的取值范圍之內,如果超出long的范圍就不行了。//2.在內部對常用的數字: -16 ~ 16 進行了優化。// 提前把-16~16 先創建好BigInteger的對象,如果多次獲取不會重新創建新的。BigInteger bd5 = BigInteger.valueOf(16);BigInteger bd6 = BigInteger.valueOf(16);System.out.println(bd5 == bd6);//trueBigInteger bd7 = BigInteger.valueOf(17);BigInteger bd8 = BigInteger.valueOf(17);System.out.println(bd7 == bd8);//false//5.對象一旦創建內部的數據不能發生改變BigInteger bd9 =BigInteger.valueOf(1);BigInteger bd10 =BigInteger.valueOf(2);//此時,不會修改參與計算的BigInteger對象中的借,而是產生了一個新的BigInteger對象記錄BigInteger result=bd9.add(bd10);System.out.println(result);//3}
}
package com.itheima.a06bigintegerdemo;import java.math.BigInteger;public class BigIntegerDemo2 {public static void main(String[] args) {/*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) 轉為int類型整數,超出范圍數據有誤*///1.創建兩個BigInteger對象BigInteger bd1 = BigInteger.valueOf(10);BigInteger bd2 = BigInteger.valueOf(5);//2.加法BigInteger bd3 = bd1.add(bd2);System.out.println(bd3);//3.除法,獲取商和余數BigInteger[] arr = bd1.divideAndRemainder(bd2);System.out.println(arr[0]);System.out.println(arr[1]);//4.比較是否相同boolean result = bd1.equals(bd2);System.out.println(result);//5.次冪BigInteger bd4 = bd1.pow(2);System.out.println(bd4);//6.maxBigInteger bd5 = bd1.max(bd2);//7.轉為int類型整數,超出范圍數據有誤/* BigInteger bd6 = BigInteger.valueOf(2147483647L);int i = bd6.intValue();System.out.println(i);*/BigInteger bd6 = BigInteger.valueOf(200);double v = bd6.doubleValue();System.out.println(v);//200.0}
}
6.4 底層存儲方式:
對于計算機而言,其實是沒有數據類型的概念的,都是0101010101,數據類型是編程語言自己規定的,所以在實際存儲的時候,先把具體的數字變成二進制,每32個bit為一組,存儲在數組中。
數組中最多能存儲元素個數:21億多
數組中每一位能表示的數字:42億多
理論上,BigInteger能表示的最大數字為:42億的21億次方。
但是還沒到這個數字,電腦的內存就會撐爆,所以一般認為BigInteger是無限的。
存儲方式如圖所示:
7 BigDecimal類
7.1 引入
首先我們來分析一下如下程序的執行結果:
public class BigDecimalDemo01 {public static void main(String[] args) {System.out.println(0.09 + 0.01);}}
這段代碼比較簡單,就是計算0.09和0.01之和,并且將其結果在控制臺進行輸出。那么按照我們的想法在控制臺輸出的結果應該為0.1。那么實際的運行結果是什么呢?我們來運行一下程序,控制臺的輸出
結果如下所示:
0.09999999999999999
這樣的結果其實就是一個丟失精度的結果。為什么會產生精度丟失呢?
在使用float或者double類型的數據在進行數學運算的時候,很有可能會產生精度丟失問題。我們都知道計算機底層在進行運算的時候,使用的都是二進制數據; 當我們在程序中寫了一個十進制數據 ,在
進行運算的時候,計算機會將這個十進制數據轉換成二進制數據,然后再進行運算,計算完畢以后計算機會把運算的結果再轉換成十進制數據給我們展示; 如果我們使用的是整數類型的數據進行計算,那
么在把十進制數據轉換成二進制數據的時候不會存在精度問題; 如果我們的數據是一個浮點類型的數據,有的時候計算機并不會將這個數據完全轉換成一個二進制數據,而是將這個將其轉換成一個無限的
趨近于這個十進數的二進制數據; 這樣使用一個不太準確的數據進行運算的時候, 最終就會造成精度丟失;為了提高精度,Java就給我們提供了BigDecimal供我們進行數據運算。
package com.itheima.a07bigdecimaldemo;import java.math.BigDecimal;public class BigDecimalDemo2 {public static void main(String[] args) {/*構造方法獲取BigDecimal對象public BigDecimal(double val) public BigDecimal(string val)靜態方法獲取BigDecimal對象public static BigDecimal valuef(double val)*///1.通過傳遞double類型的小數來創建對象//細節://這種方式有可能是不精確的,所以不建議使用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");BigDecimal bd5 = bd3.add(bd4);System.out.println(bd3);System.out.println(bd4);System.out.println(bd5);//3.通過靜態方法獲取對象//細節://1.如果要表示的數字不大,沒有超出double的取值范圍,建議使用靜態方法//2.如果要表示的數字比較大,超出了double的取值范圍,建議使用構造方法//3.如果我們傳遞的是0~10之間的整數,包含0,包含10,那么方法會返回已經創建好的對象,不會重新newBigDecimal bd6 = BigDecimal.valueOf(10.0);BigDecimal bd7 = BigDecimal.valueOf(10.0);System.out.println(bd6 == bd7);}
}
7.2 概述
查看API文檔,我們可以看到API文檔中關于BigDecimal類的定義如下:
BigDecimal所在包是在java.math包下,因此在使用的時候就需要進行導包。我們可以使用BigDecimal類進行更加精準的數據計算。
7.3 常見方法
構造方法
要用BigDecimal類,那么就需要首先學習一下如何去創建BigDecimal的對象。通過查看API文檔,我們可以發現Jdk中針對BigDecimal類提供了很多的構造方法,但是最常用的構造方法是:
了解完常見的構造方法以后,我們接下來就重點介紹一下常見的成員方法。
常見成員方法
BigDecimal類中使用最多的還是提供的進行四則運算的方法,如下:
public BigDecimal add(BigDecimal value) // 加法運算
public BigDecimal subtract(BigDecimal value) // 減法運算
public BigDecimal multiply(BigDecimal value) // 乘法運算
public BigDecimal divide(BigDecimal value) // 除法運算
接下來我們就來通過一些案例演示一下這些成員方法的使用。
案例1:演示基本的四則運算
代碼如下所示:
public class BigDecimalDemo01 {public static void main(String[] args) {// 創建兩個BigDecimal對象BigDecimal b1 = new BigDecimal("0.3") ;BigDecimal b2 = new BigDecimal("4") ;// 調用方法進行b1和b2的四則運算,并將其運算結果在控制臺進行輸出System.out.println(b1.add(b2)); // 進行加法運算System.out.println(b1.subtract(b2)); // 進行減法運算System.out.println(b1.multiply(b2)); // 進行乘法運算System.out.println(b1.divide(b2)); // 進行除法運算}}
運行程序進行測試,控制臺輸出結果如下:
4.3
-3.7
1.2
0.075
此時我們可以看到使用BigDecimal類來完成浮點數的計算不會存在損失精度的問題。
案例2:演示除法的特殊情況
如果使用BigDecimal類型的數據進行除法運算的時候,得到的結果是一個無限循環小數,那么就會報錯:ArithmeticException。 如下代碼所示:
public class BigDecimalDemo02 {public static void main(String[] args) {// 創建兩個BigDecimal對象BigDecimal b1 = new BigDecimal("1") ;BigDecimal b2 = new BigDecimal("3") ;// 調用方法進行b1和b2的除法運算,并且將計算結果在控制臺進行輸出System.out.println(b1.divide(b2));}}
運行程序進行測試,控制臺輸出結果如下所示:
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.at java.base/java.math.BigDecimal.divide(BigDecimal.java:1716)at com.itheima.api.bigdecimal.demo02.BigDecimalDemo02.main(BigDecimalDemo02.java:14)
針對這個問題怎么解決,此時我們就需要使用到BigDecimal類中另外一個divide方法,如下所示:
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
上述divide方法參數說明:
divisor: 除數對應的BigDecimal對象;
scale: 精確的位數;
roundingMode: 取舍模式;
取舍模式被封裝到了RoundingMode這個枚舉類中(關于枚舉我們后期再做重點講解),在這個枚舉類中定義了很多種取舍方式。最常見的取舍方式有如下幾個:
UP(直接進1) , FLOOR(直接刪除) , HALF_UP(4舍五入),我們可以通過如下格式直接訪問這些取舍模式:枚舉類名.變量名
接下來我們就來演示一下這些取舍模式,代碼如下所示:
public class BigDecimalDemo02 {public static void main(String[] args) {// 調用方法method_03() ;}// 演示取舍模式HALF_UPpublic static void method_03() {// 創建兩個BigDecimal對象BigDecimal b1 = new BigDecimal("0.3") ;BigDecimal b2 = new BigDecimal("4") ;// 調用方法進行b1和b2的除法運算,并且將計算結果在控制臺進行輸出System.out.println(b1.divide(b2 , 2 , RoundingMode.HALF_UP));}// 演示取舍模式FLOORpublic static void method_02() {// 創建兩個BigDecimal對象BigDecimal b1 = new BigDecimal("1") ;BigDecimal b2 = new BigDecimal("3") ;// 調用方法進行b1和b2的除法運算,并且將計算結果在控制臺進行輸出System.out.println(b1.divide(b2 , 2 , RoundingMode.FLOOR));}// 演示取舍模式UPpublic static void method_01() {// 創建兩個BigDecimal對象BigDecimal b1 = new BigDecimal("1") ;BigDecimal b2 = new BigDecimal("3") ;// 調用方法進行b1和b2的除法運算,并且將計算結果在控制臺進行輸出System.out.println(b1.divide(b2 , 2 , RoundingMode.UP));}}
小結:后期在進行兩個數的除法運算的時候,我們常常使用的是可以設置取舍模式的divide方法。
7.4 底層存儲方式:
把數據看成字符串,遍歷得到里面的每一個字符,把這些字符在ASCII碼表上的值,都存儲到數組中。