天天看點

Java随機數之System/Random/SecureRandom詳解

作者:千鋒教育

本系列為:從零開始學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,獲得系統中對應的某些屬性值,系統中常見的屬性名及其屬性如下表所示:

Java随機數之System/Random/SecureRandom詳解
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方法供我們操作随機數:

Java随機數之System/Random/SecureRandom詳解

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() 等随機數生成方法,如下圖所示:

Java随機數之System/Random/SecureRandom詳解

接下來我們就通過一個案例,來看看到底該如何生成一個安全的随機數。

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資訊、關注@千鋒教育

繼續閱讀