本系列為:從零開始學Java,為千鋒資深Java教學老師獨家創作
緻力于為大家講解清晰Java學習相關知識點,含有豐富的代碼案例及講解。如果感覺對大家有幫助的話,可以【關注】持續追更~
文末有本文重點總結!關于技術類問題,也歡迎大家和我們溝通交流!
前言
我們在解決實際問題時,除了經常需要對數字、日期、時間進行操作之外,有時候還需要對系統進行設定,另外還需要生成一些随機數字。
那麼我們又該如何實作這些需求呢?接下來我們會帶着大家來學習一下Java中的另幾個常用類,包括System、Random、SecureRandom等。
全文大約 【4000】字, 不說廢話,隻講可以讓你學到技術、明白原理的純幹貨!本文帶有豐富的案例及配圖,讓你更好地了解和運用文中的技術概念,并可以給你帶來具有足夠啟迪的思考...
一. System類
1. 簡介
System類位于java.lang包中,代表着目前Java程式的運作平台,系統級的很多屬性和控制方法都放在該類中。
由于該類的構造方法是private的,是以我們無法直接通過new的方式來建立該類的對象。System類提供了一些靜态變量和靜态方法,允許我們直接通過System類來調用這些類變量和類方法。在System類中,雖然有挺多的靜态變量和方法,但對我們來說,隻需記住一些常用的即可。
1.1 常用靜态變量
System類中常用的靜态變量有如下幾個:
● PrintStream out:标準輸出流;
● InputStream in:标準輸入流;
● PrintStream err:标準錯誤輸出流;
1.2 常用靜态方法
System類中常用的靜态方法有如下幾個:
● currentTimeMillis():傳回目前的計算機時間;
● exit():終止目前正在運作的 Java 虛拟機;
● gc():請求系統進行垃圾回收,完成記憶體中的垃圾清除;
● getProperty():獲得系統中屬性名為 key 的屬性對應的值;
● arraycopy():進行數組複制,即從指定源數組中複制一個數組。
接下來我們就把
以上這些靜态變量和靜态方法的基本使用,給大家簡要介紹一下。
2. 靜态變量的使用
首先我們來看看System類中幾個常用靜态變量該如何使用。
2.1 out
out靜态變量屬于PrintStream類型,是System類中的标準輸出流,用于接收要輸出的資料。out中的資料内容通常會輸出到顯示器,或使用者指定的某個輸出目标。其實對我們來說,out并不陌生,可以說在我們之前的案例中經常使用,尤其是out中的print方法,最近我們一直在使用。但我們要搞清楚,print屬于PrintStream流的方法,并不是 System類的方法。
//輸出字元串不換行
System.out.print("Hello World");
//輸出字元串并換行
System.out.println("Hello World");
2.2 in
in靜态變量屬于InputStream類型,是System類中的标準輸入流,用于接收輸入的資料。in通常是對應着鍵盤的輸入,或是使用者指定的另一個輸入源。我們在之前的案例中,也簡單使用過in常量,但它沒有out用的那麼頻繁。
import java.io.IOException;
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
//in的用法
//用法1:配合Scanner,作為它的參數
System.out.println("請輸入内容:");
Scanner scanner=new Scanner(System.in);
String content = scanner.next();
System.out.println("content="+content);
//用法2:挨個讀取輸入的每個字元
System.out.println("請輸入内容,按Enter鍵結束輸入:");
int c;
try {
//讀取輸入的每個字元
c = System.in.read();
// 判斷輸入的字元是不是Enter鍵
while(c != '\r') {
//輸出字元
System.out.print((char) c);
c = System.in.read();
}
} catch(IOException e) {
//捕獲異常,我們以後會給大家專門講解異常類
System.out.println(e.toString());
}
}
}
上面的這個案例,System.in.read()語句可以讀入一個字元,read()方法是InputStream類擁有的方法。變量c必須用 int 類型,而不能用char類型,否則可能會丢失精度而導緻編譯失敗。另外上面的程式,如果輸入的是漢字将不能正常輸出。如果我們想正常輸出漢字,需要把 System.in聲明為 InputStreamReader類型的執行個體。比如
InputStreamReader in=new InputStreamReader(System.in,"GB2312"),此時就可以讀入完整的Unicode碼,才能顯示正常的漢字。
2.3 err
err靜态變量屬于PrintStream類型,是System類中的标準錯誤輸出流,用于接收要輸出的資料。err中的資料内容通常會輸出到顯示器,或使用者指定的某個輸出目标。其用法與System.out一樣,隻是不需要我們提供參數就可以輸出錯誤資訊,也可以用來輸出使用者指定的其他資訊,包括一些變量的值。
//err的用法
System.err.println();
//輸出指定的内容
System.err.println("錯誤資訊");
以上這幾個靜态變量都很簡單,大家記住其用法即可。
3. 靜态方法的使用
接下來再跟大家說說System類中的幾個常用靜态方法的用法。
3.1 currentTimeMillis()方法
currentTimeMillis()方法用于傳回目前計算機的時間戳,時間格式是目前計算機的時間與GMT時間(格林尼治時間),自1970年 1月 1日 0時 0分 0秒以來所經曆的毫秒數,我們一般用它來測試程式的執行時間。通過調用currentTimeMillis()方法,我們可以獲得一個長整型的數字,該數字是以內插補點表達的目前時間。其實currentTimeMillis()方法我們在之前的文章中已經詳細講解過,這裡就不再細說了。
long time = System.currentTimeMillis();
3.2 exit()方法
exit()方法用于終止目前正在運作的Java虛拟機,也就是可以用于退出程式。該方法需要一個整型的status參數,0表示正常退出,非零表示異常退出。我們使用該方法,可以在圖形界面程式設計中實作程式的退出功能。該方法的用法如下:
public class Demo01 {
public static void main(String[] args) {
//exit的用法
try {
//睡眠5秒
Thread.sleep(5000);
//5秒後正常退出程式
System.exit(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.3 gc()方法
gc()方法用于請求對系統主動進行垃圾回收,完成記憶體中的垃圾清除。但系統是否會立刻回收這些垃圾,卻取決于系統中垃圾回收算法的具體實作,以及系統執行時的具體情況。一般我們在開發時不會主動調用該方法,有時候調用了也未必有效果。
//主動進行垃圾回收
System.gc();
3.4 getProperty()方法
getProperty()方法可以根據指定的key,獲得系統中對應的某些屬性值,系統中常見的屬性名及其屬性如下表所示:
public class Demo03 {
public static void main(String[] args) {
//getProperty的用法
//擷取java版本
String version = System.getProperty("java.version");
System.out.println("Java版本:"+version);
//擷取java安裝目錄
String home = System.getProperty("java.home");
System.out.println("Java目錄:"+home);
//系統名稱
String name = System.getProperty("os.name");
System.out.println("作業系統名稱:"+name);
//使用者名稱
String user = System.getProperty("user.name");
System.out.println("目前使用者名稱:"+user);
}
}
3.5 arraycopy()
arraycopy()方法用于數組複制,可以從指定的源數組中複制出一個數組,複制會從指定的位置開始,到目标數組的指定位置結束。arraycopy()方法一般有5個參數,其中,src表示源數組,srcPos表示從源數組中複制的起始位置,dest表示目标數組,destPos表示要複制到的目标數組的起始位置,length表示複制的個數。
public class Demo04 {
public static void main(String[] args) {
//arraycopy的用法
//源數組
char[] srcArray = {'A','B','C','D'};
//目标數組
char[] destArray = {'1','2','3','4','5'};
//進行數組複制
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]);
}
}
}
二. Random随機類
1. 簡介
我們在開發時,除了操作一些固定的數字之外,有時候還要操作一些不确定的随機數。Java中給我們提供了兩種生成指定範圍内随機數的方法:
● 使用Random類:僞随機數類,用來建立僞随機數。所謂僞随機數,就是指我們隻要給定一個初始的種子,産生的随機數序列是完全一樣的;
● 調用Math類的random()方法:Math.random()内部其實是在調用Random類,它也是僞随機數,但我們無法指定種子。
Random類為我們提供了比較豐富的随機數生成方法,比如nextInt()、nextLong()、nextFloat()、nextDouble()等方法。這些方法可以産生boolean、int、long、float、byte數組以及double類型的随機數,這是它比random()方法更好的地方,random()方法隻能産生0~1之間的double類型随機數。
而且Random類提供的所有方法,生成的随機數字都是均勻分布的,也就是說區間内部的數字生成的機率是均等的。Random類位于java.util包中,該類有如下兩個常用的構造方法:
● Random():預設利用目前系統的時間戳作為種子數,使用該種子數構造出Random對象。
● Random(long seed):使用單個的long類型參數,建立一個新的随機數生成器。
2. 常用API方法
在Random類中,有如下一些常用的API方法供我們操作随機數:
3. 基本用法
接下來我們通過一個案例,來給大家講解一下上述方法該如何使用。
import java.util.Random;
public class Demo07 {
public static void main(String[] args) {
// 随機類生成随機數
Random r = new Random();
// 生成[0,1.0]區間的小數
double d1 = r.nextDouble();
System.out.println("d1="+d1);
// 生成[0,10.0]區間的小數
double d2 = r.nextDouble() * 10;
System.out.println("d2="+d2);
// 生成[0,10]區間的整數
int i1 = r.nextInt(10);
System.out.println("i1="+i1);
// 生成[0,25)區間的整數
int i2 = r.nextInt(30) - 5;
System.out.println("i2="+i2);
// 生成一個随機長整型值
long l1 = r.nextLong();
System.out.println("l1="+l1);
// 生成一個随機布爾型值
boolean b1 = r.nextBoolean();
System.out.println("b1="+b1);
// 生成一個随機浮點型值
float f1 = r.nextFloat();
System.out.println("f1="+f1);
}
}
但是我們從上面的案例中,會發現每次生成的随機數可能都是不同的,并沒有展現出僞随機數的特性,這是為什麼呢?其實這是因為我們建立Random執行個體時,如果沒有給定種子,預設是使用系統的目前時間戳作為種子。是以每次運作時,種子都不同,是以得到的僞随機數序列就不同。如果我們在建立Random執行個體時指定一個固定的種子,就會得到完全确定的随機數序列。
三. SecureRandom類
1. 簡介
之前給大家說過,Random是一種僞随機數類。這時候就有小夥伴問了,那有沒有真随機數類呢?
當然是有的!
SecureRandom就是一種真随機數!
從原理來看,SecureRandom内部使用了RNG (Random Number Generator,随機數生成)算法,來生成一個不可預測的安全随機數。但在JDK的底層,實際上SecureRandom也有多種不同的具體實作。有的是使用安全随機種子加上僞随機數算法來生成安全的随機數,有的是使用真正的随機數生成器來生成随機數。實際使用時,我們可以優先擷取高強度的安全随機數生成器;如果沒有提供,再使用普通等級的安全随機數生成器。但不管哪種情況,我們都無法指定種子。
因為這個種子是通過CPU的熱噪聲、讀寫磁盤的位元組、網絡流量等各種随機事件産生的“熵”,是以這個種子理論上是不可能會重複的。這也就保證了SecureRandom的安全性,是以最終生成的随機數就是安全的真随機數。
尤其是在密碼學中,安全的随機數非常重要。如果我們使用不安全的僞随機數,所有加密體系都将被攻破。是以,為了保證系統的安全,我們盡量使用SecureRandom來産生安全的随機數。
2. 基本使用
SecureRandom 給我們提供了 nextBoolean()、nextBytes()、nextDouble()、nextFloat()、nextInt() 等随機數生成方法,如下圖所示:
接下來我們就通過一個案例,來看看到底該如何生成一個安全的随機數。
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
public class Demo05 {
public static void main(String[] args) {
//SecureRandom真随機數的用法
SecureRandom sr = null;
try {
//擷取高強度安全随機數生成器執行個體對象
sr = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
//處理異常,擷取普通的安全随機數生成器
sr = new SecureRandom();
}
//生成16個随機數
byte[] buffer = new byte[16];
//用安全随機數填充buffer
sr.nextBytes(buffer);
System.out.println("随機數="+Arrays.toString(buffer));
//生成100以内的随機整數
int nextInt = sr.nextInt(100);
System.out.println("随機數="+nextInt);
}
}
四. 結語
至此,就把與系統類、僞随機數、真随機數等相關的類給大家介紹完了,這樣我們就把開發時的一些常見類介紹完畢了。今天的重點内容是:
● System:代表着目前Java程式的運作平台,系統級的很多屬性和控制方法都放在該類中;
● Random:生成僞随機數;
● SecureRandom:生成安全的真随機數。
往期精彩推薦:
MySQL資料庫連接配接查詢表關系、表連結查詢詳解
JDK8 新特性之新的日期&時間API,一篇講清楚!
MySQL常用函數詳解,内含示例
Java中時間格式化怎麼實作?
更多技術類幹貨/IT資訊、關注@千鋒教育