Java中生成隨機(jī)數(shù)的實(shí)現(xiàn)方法總結(jié)
在實(shí)際開發(fā)工作中經(jīng)常需要用到隨機(jī)數(shù)。如有些系統(tǒng)中創(chuàng)建用戶后會給用戶一個(gè)隨機(jī)的初始化密碼。這個(gè)密碼由于是隨機(jī)的,為此往往只有用戶自己知道。他們獲取了這個(gè)隨機(jī)密碼之后,需要馬上去系統(tǒng)中更改。這就是利用隨機(jī)數(shù)的原理??傊S機(jī)數(shù)在日常開發(fā)工作中經(jīng)常用到。而不同的開發(fā)語言產(chǎn)生隨機(jī)數(shù)的方法以及技巧各不相同。筆者這里就以Java語言為例,談?wù)勲S機(jī)數(shù)生成的方法以及一些技巧。
一、利用random方法來生成隨機(jī)數(shù)。
在Java語言中生成隨機(jī)數(shù)相對來說比較簡單,因?yàn)橛幸粋€(gè)現(xiàn)成的方法可以使用。在Math類中,Java語言提供了一個(gè)叫做random的方法。通過這個(gè)方法可以讓系統(tǒng)產(chǎn)生隨機(jī)數(shù)。不過默認(rèn)情況下,其產(chǎn)生的隨機(jī)數(shù)范圍比較小,為大于等于0到小于1的double型隨機(jī)數(shù)。雖然其隨機(jī)數(shù)產(chǎn)生的范圍比較小,不能夠滿足日常的需求。如日常工作中可能需要產(chǎn)生整數(shù)的隨機(jī)數(shù)。其實(shí),只要對這個(gè)方法進(jìn)行一些靈活的處理,就可以獲取任意范圍的隨機(jī)數(shù)。
如我們可以先通過random方法生成一個(gè)隨機(jī)數(shù),然后將結(jié)果乘以10。此時(shí)產(chǎn)生的隨機(jī)數(shù)字即為大于等于0小于10的數(shù)字。然后再利用Int方法進(jìn)行轉(zhuǎn)換(它會去掉小數(shù)掉后面的數(shù)字,即只獲取整數(shù)部分,不是四舍五入)。最后即可獲取一個(gè)0到9的整數(shù)型隨機(jī)數(shù)字。其實(shí)現(xiàn)方法很簡單,就是對原有的random方法按照如下的格式進(jìn)行變型:(int)(Math.Random()*10)即可。其實(shí)我們還可以對這個(gè)方法進(jìn)行擴(kuò)展,讓其產(chǎn)生任意范圍內(nèi)的隨機(jī)數(shù)。至需要將這個(gè)10換成n即可,如改為(int)(Math.Random()*n)。此時(shí)應(yīng)用程序就會產(chǎn)生一個(gè)大于等于0小與n之間的隨機(jī)數(shù)。如將n設(shè)置為5,那么其就會產(chǎn)生一個(gè)0到5之間的整數(shù)型的隨機(jī)數(shù)。如果將這個(gè)寫成一個(gè)帶參數(shù)的方法,那么只要用戶輸入需要生成隨機(jī)數(shù)的最大值,就可以讓這個(gè)方法來生成制定范圍的隨機(jī)數(shù)。在Java中定義自己的工具庫
有時(shí)候程序員可能需要生成一個(gè)指定范圍內(nèi)的隨機(jī)偶數(shù)或者奇數(shù)。此時(shí)是否可以通過這個(gè)方法來實(shí)現(xiàn)呢?答案是肯定的。如現(xiàn)在程序要需要生成一個(gè)1-100范圍內(nèi)的偶數(shù)。此時(shí)該如何實(shí)現(xiàn)?首先,需要生成一個(gè)0到99之內(nèi)的隨機(jī)數(shù)(至于這里為什么是99,大家耐心看下去就知道原因了)。要實(shí)現(xiàn)這個(gè)需求,很簡單吧,只要通過如下語句就可以實(shí)現(xiàn): i=1+(int)(Math.Random()*100)。其中(int)(Math.Random()*99)產(chǎn)生0到99的整數(shù)型隨機(jī)數(shù)。然后再加上1就是產(chǎn)生1到100之間的隨機(jī)整數(shù)。然后將產(chǎn)生的隨機(jī)數(shù)賦值給變量i。但是此時(shí)其產(chǎn)生的隨機(jī)數(shù)即有偶數(shù),又有奇數(shù)。而現(xiàn)在程序員需要的是一個(gè)隨機(jī)的偶數(shù)。那么我們可以在后面加上一個(gè)if判斷語句。將這個(gè)隨機(jī)數(shù)除以2,如果沒有余數(shù)的話(或者余數(shù)為0)則表明這個(gè)隨機(jī)數(shù)是偶數(shù),直接返回即可。如果其返回的余數(shù)不為零,那么就表明其是奇數(shù),我們只要加上1就變?yōu)榱伺紨?shù),返回即可。注意,在上面的隨機(jī)數(shù)生成中,筆者采用的范圍是0到99,然后再加上1讓其變?yōu)?到100的隨機(jī)數(shù)。最后的結(jié)果就是生成1到100之間的隨機(jī)偶數(shù)。其實(shí),如果要范圍隨機(jī)奇數(shù)的話,至需要對上面的語句進(jìn)行稍微的修改即可。Java:改變你我的世界
假設(shè)現(xiàn)在用戶想生成一個(gè)任意范圍內(nèi)的奇數(shù)或者偶數(shù),能夠?qū)崿F(xiàn)嗎?假設(shè)現(xiàn)在用戶想實(shí)現(xiàn)一個(gè)m到n之間的任意偶數(shù)(其中m
可見雖然random方法其自身產(chǎn)生的隨機(jī)數(shù)有比較嚴(yán)格的范圍限制。但是只要對其進(jìn)行合理的轉(zhuǎn)換,程序員仍然可以采用這個(gè)方法產(chǎn)生用戶所需要的隨機(jī)數(shù)據(jù)。
二、通過Random類來生成隨機(jī)數(shù)。
在Java語言中,除了可以通過random 方法來產(chǎn)生隨機(jī)數(shù)之外,還可以通過一個(gè)random類來產(chǎn)生隨機(jī)數(shù)。程序開發(fā)人員可以通過實(shí)例化一個(gè)Random對象來創(chuàng)建一個(gè)隨機(jī)數(shù)的生成器。如Random i=new Random()。通過這條語句就利用了Random類創(chuàng)建了一個(gè)隨機(jī)數(shù)的生成器。不過以這種方法創(chuàng)建隨機(jī)數(shù)時(shí),與采用Random方法產(chǎn)生隨機(jī)數(shù)的機(jī)制不同。利用現(xiàn)在這種方式實(shí)例化對象時(shí),Java編譯器會以系統(tǒng)當(dāng)前的時(shí)間作為隨機(jī)數(shù)生成器的種子。由于時(shí)間時(shí)時(shí)刻刻在變化的。若以這個(gè)時(shí)間作為生成器的種子,就可以保證生成的隨機(jī)數(shù)真的是隨機(jī)的,其生成的隨機(jī)數(shù)重復(fù)率會大大的降低。
利用這種方法其比較方便。如可以利用提供的關(guān)鍵字,讓程序返回一個(gè)隨機(jī)的整數(shù)(采用int nextInt(10))等等。不過其返回控制要比Random方法困難一點(diǎn)。如現(xiàn)在需要系統(tǒng)提供一個(gè)10到50之間的隨機(jī)奇數(shù), 利用這個(gè)Random類就無法完成。也就是說,利用這個(gè)Random類來生成隨機(jī)數(shù),其只能夠控制上限,而不能夠控制下限。換一句話說,其可以指定最大的隨機(jī)數(shù)范圍,而不能夠指定最小的隨機(jī)數(shù)范圍。所以,在靈活性上,其比Random方法要稍微差一點(diǎn)。
另外利用這個(gè)方法來實(shí)現(xiàn)的話,必須先創(chuàng)建一個(gè)對象。也就是說利用Randow類來創(chuàng)建對象。這跟Randow方法不同。像上面舉的例子中,Randow方法本身就是一個(gè)math類中方法,可以直接調(diào)用,省去對象創(chuàng)建的方法。為此筆者建議各位讀者與程序開發(fā)人員,最好還是使用Random方法來創(chuàng)建隨機(jī)數(shù)。只有在生成一些比較特殊的隨機(jī)數(shù)時(shí)采用Random類。如現(xiàn)在需要生成一個(gè)概率密度為高斯分布的雙精度值隨機(jī)數(shù)時(shí),則通過采用Random類的方法來創(chuàng)建隨機(jī)數(shù)相對來說比較簡單一點(diǎn)。
三、產(chǎn)生隨機(jī)的字符。
上面介紹的兩種方法,產(chǎn)生的都是隨機(jī)的數(shù)值型數(shù)據(jù)。但是有時(shí)候用戶可能還需要產(chǎn)生隨機(jī)的字符。其實(shí)也可以利用random方法來產(chǎn)生隨機(jī)字符。如可以利用代碼生成一個(gè)隨機(jī)的小寫字符:(char)(‘a(chǎn)'+Math.random()*(‘z'-‘a(chǎn)'+1))。其實(shí)這跟生成任意兩個(gè)數(shù)之間的隨機(jī)數(shù)類似。通過以上的代碼就可以生成一個(gè)范圍之內(nèi)的任意隨機(jī)字符。通過對這個(gè)代碼進(jìn)行適當(dāng)?shù)男拚€可以生成任意兩個(gè)字符之間的隨機(jī)字符與任意大寫字符的隨機(jī)字符。其轉(zhuǎn)換的方式跟上面提到的任意范圍之內(nèi)的隨機(jī)數(shù)類似。各位讀者若感興趣的話,可以自己進(jìn)行測試一下。師傅領(lǐng)進(jìn)門,修行在自身。如果筆者在這里一股腦兒將所有的答案告訴大家,大家的印象不會很深。大家若回去自己動(dòng)手試試看,反而更容易記住。
筆者在這里給大家一個(gè)提示,只需要根據(jù)m+(int)(Math.Random()*(n-m))這條語句來調(diào)整(char)(‘a(chǎn)'+Math.random()*(‘z'-‘a(chǎn)'+1))這個(gè)代碼即可。
四、進(jìn)階
通過閱讀Math.random()的源碼,或者干脆利用IDE的自動(dòng)完成功能,開發(fā)人員可以很容易發(fā)現(xiàn),java.lang.Math.random()使用一個(gè)內(nèi)部的隨機(jī)生成對象 - 一個(gè)很強(qiáng)大的對象可以靈活的隨機(jī)產(chǎn)生:布爾值、所有數(shù)字類型,甚至是高斯分布。例如:
new java.util.Random().nextInt(10)
它有一個(gè)缺點(diǎn),就是它是一個(gè)對象。它的方法必須是通過一個(gè)實(shí)例來調(diào)用,這意味著必須先調(diào)用它的構(gòu)造函數(shù)。如果在內(nèi)存充足的情況下,像上面的表達(dá)式是可以接受的;但內(nèi)存不足時(shí),就會帶來問題。
一個(gè)簡單的解決方案,可以避免每次需要生成一個(gè)隨機(jī)數(shù)時(shí)創(chuàng)建一個(gè)新實(shí)例,那就是使用一個(gè)靜態(tài)類。猜你可能想到了java.lang.Math,很好,我們就是改良java.lang.Math的初始化。雖然這個(gè)工程量低,但你也要做一些簡單的單元測試來確保其不會出錯(cuò)。
假設(shè)程序需要生成一個(gè)隨機(jī)數(shù)來存儲,問題就又來了。比如有時(shí)需要操作或保護(hù)種子(seed),一個(gè)內(nèi)部數(shù)用來存儲狀態(tài)和計(jì)算下一個(gè)隨機(jī)數(shù)。在這些特殊情況下,共用隨機(jī)生成對象是不合適的。
并發(fā)
在Java EE多線程應(yīng)用程序的環(huán)境中,隨機(jī)生成實(shí)例對象仍然可以被存儲在類或其他實(shí)現(xiàn)類,作為一個(gè)靜態(tài)屬性。幸運(yùn)的是,java.util.Random是線程安全的,所以不存在多個(gè)線程調(diào)用會破壞種子(seed)的風(fēng)險(xiǎn)。
另一個(gè)值得考慮的是多線程java.lang.ThreadLocal的實(shí)例。偷懶的做法是通過Java本身API實(shí)現(xiàn)單一實(shí)例,當(dāng)然你也可以確保每一個(gè)線程都有自己的一個(gè)實(shí)例對象。
雖然Java沒有提供一個(gè)很好的方法來管理java.util.Random的單一實(shí)例。但是,期待已久的Java 7提供了一種新的方式來產(chǎn)生隨機(jī)數(shù):
java.util.concurrent.ThreadLocalRandom.current().nextInt(10)
這個(gè)新的API綜合了其他兩種方法的優(yōu)點(diǎn):單一實(shí)例/靜態(tài)訪問,就像Math.random()一樣靈活。ThreadLocalRandom也比其他任何處理高并發(fā)的方法要更快。
經(jīng)驗(yàn)
Chris Marasti-Georg 指出:
Math.round(Math.random() * 10)
使分布不平衡,例如:0.0 - 0.499999將四舍五入為0,而0.5至1.499999將四舍五入為1。那么如何使用舊式語法來實(shí)現(xiàn)正確的均衡分布,如下:
Math.floor(Math.random() * 11)
幸運(yùn)的是,如果我們使用java.util.Random或java.util.concurrent.ThreadLocalRandom就不用擔(dān)心上述問題了。
Java實(shí)戰(zhàn)項(xiàng)目里面介紹了一些不正確使用java.util.Random API的危害。這個(gè)教訓(xùn)告訴我們不要使用:
Math.abs(rnd.nextInt())%n
而使用:
rnd.nextInt(n)
- 如何用java生成指定范圍的隨機(jī)數(shù)
- Java生成隨機(jī)數(shù)的2種示例方法代碼
- 史上最全的java隨機(jī)數(shù)生成算法分享
- java生成指定范圍隨機(jī)數(shù)的多種代碼
- Java實(shí)現(xiàn)生成n個(gè)不重復(fù)的隨機(jī)數(shù)
- Java編程實(shí)現(xiàn)生成給定范圍內(nèi)不重復(fù)隨機(jī)數(shù)的方法小結(jié)
- Java編程中隨機(jī)數(shù)的生成方式總結(jié)
- java生成隨機(jī)數(shù)(字符串)示例分享
- Java中隨機(jī)數(shù)生成常見的幾種方式及適用場景
相關(guān)文章
Mybatis注解實(shí)現(xiàn)多數(shù)據(jù)源讀寫分離詳解
這篇文章主要給大家介紹了關(guān)于Mybatis注解實(shí)現(xiàn)多數(shù)據(jù)源讀寫分離的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09jdk8的datetime時(shí)間函數(shù)使用示例
這篇文章主要介紹了jdk8的datetime時(shí)間函數(shù)使用示例,需要的朋友可以參考下2014-03-03IDEA集成DeepSeek通過離線安裝解決無法安裝Proxy?AI插件問題(最新推薦)
許多開發(fā)者嘗試通過安裝Proxy?AI等插件將AI能力引入IDEA,但在實(shí)際使用中常遭遇插件安裝失敗、網(wǎng)絡(luò)連接不穩(wěn)定或兼容性沖突等問題,本文給大家介紹IDEA集成DeepSeek通過離線安裝解決無法安裝Proxy?AI插件問題,感興趣的朋友一起看看吧2019-12-12feign參數(shù)過多導(dǎo)致調(diào)用失敗的解決方案
這篇文章主要介紹了feign參數(shù)過多導(dǎo)致調(diào)用失敗的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03使用Spring Data Jpa的CriteriaQuery一個(gè)陷阱
使用Spring Data Jpa的CriteriaQuery進(jìn)行動(dòng)態(tài)條件查詢時(shí),可能會遇到一個(gè)陷阱,當(dāng)條件為空時(shí),查詢不到任何結(jié)果,并不是期望的返回所有結(jié)果。這是為什么呢?2020-11-11接口隔離原則_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了接口隔離原則,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08