<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          初看一臉懵逼,看懂直接跪下!

          共 3234字,需瀏覽 7分鐘

           ·

          2022-04-13 18:32

          你好呀,我是歪歪。

          我最近在 stackoverflow 上看到一段代碼,怎么說呢。

          就是初看一臉懵逼,看懂直接跪下!

          f2962047a67e9e0c6b8237771a21463c.webp

          我先帶你看看 stackoverflow 上的這個問題是啥,然后引出這段代碼:

          https://stackoverflow.com/questions/15182496/why-does-this-code-using-random-strings-print-hello-world

          問題特別簡單,就一句話:

          誰能給我解釋一下:為什么這段代碼使用隨機字符串打印出了 hello world?

          b84eeb57c98e8562177440cd2c4d1806.webp

          代碼也很簡單,我把它拿出來給你跑一下:

          public?class?MainTest?{

          ????public?static?void?main(String[]?args)?{
          ????????System.out.println(randomString(-229985452)?+?"?"?+?randomString(-147909649));
          ????}

          ????public?static?String?randomString(int?i)?{
          ????????Random?ran?=?new?Random(i);
          ????????StringBuilder?sb?=?new?StringBuilder();
          ????????while?(true)?{
          ????????????int?k?=?ran.nextInt(27);
          ????????????if?(k?==?0)
          ????????????????break;

          ????????????sb.append((char)?('`'?+?k));
          ????????}
          ????????return?sb.toString();
          ????}
          }

          上面的代碼你也可以直接粘貼到你的運行環(huán)境中跑一下,看看是不是也輸出的 hello world:

          9763331c688d4110a8b86747091c06ec.webp

          我就問你:即使代碼都給你了,第一眼看到 hello world 的時候你懵不懵逼?

          c8093b656544f12b354e902285c54afa.webp

          高贊回答

          51df496609d6a3fe1b0e3a5d1f6b3f8e.webp

          高贊回答也特別簡單,就這么兩句話。

          我給你翻譯一下,這個哥們說:

          當我們調(diào)用 Random 的構(gòu)造方法時,給定了一個“種子”(seed)參數(shù)。比如本例子中的:-229985452 或 -147909649。

          那么 Random 將從指定的種子值開始生成隨機數(shù)。

          而每個用相同的種子構(gòu)造的 Random 對象,都會按照產(chǎn)生相同的模式產(chǎn)生數(shù)字。

          沒看的太明白,對不對?

          沒關(guān)系,我給你上一段代碼,你就能恍然大悟上面這一段說的是啥事:

          public?static?void?main(String[]?args)?{

          ????randomString(-229985452);
          ????System.out.println("------------");
          ????randomString(-229985452);

          }

          private?static?void?randomString(int?i)?{
          ????Random?ran?=?new?Random(i);
          ????System.out.println(ran.nextInt());
          ????System.out.println(ran.nextInt());
          ????System.out.println(ran.nextInt());
          ????System.out.println(ran.nextInt());
          ????System.out.println(ran.nextInt());

          }

          這段代碼,在我的機器上運行結(jié)果是這樣的:

          73bb4da37cbf6ebfbde289d02f212e91.webp

          你拿過去跑,你的運行結(jié)果也一定是這樣的。

          這是為什么呢?

          答案就在 Javadoc 上寫著的:

          6ee55c825cfdb8d3a108c07a874bacb5.webp

          如果用相同的種子創(chuàng)建了兩個 Random 的實例,并且對每個實例進行了相同的方法調(diào)用序列,那么它們將生成并返回相同的數(shù)字序列。

          在上面的代碼中兩個 -229985452 就是相同的種子,而三次 nextInt() 調(diào)用,就是相同的調(diào)用序列。

          所以,他們生成并返回相同的、看起來是隨機的數(shù)字。

          88b32d1c390506c3f93e63b124e8891f.webp

          而我們正常在程序里面的用法應該是這樣的:

          522c953a3f97f2cc84458c597590eecb.webp

          在 new Random() 的時候,不會去指定一個值。

          我們都知道 Random 是一個偽隨機算法,而構(gòu)建的時候指定了 seed 參數(shù)的就是一個更加偽的偽隨機算法了。

          因為如果我可以推測出你的 seed 的話,或者你的 seed 泄露了,那么理論上我就可以推測出你隨機數(shù)生成序列。

          這個我已經(jīng)在前面的代碼中演示了。

          再看看問題

          在前面稍微解釋了 “seed” 的關(guān)鍵之處之后,我們再回過頭去品一品這個問題,大概就能看出點端倪了。

          b37402e6b05cc6e9830b4442ca574536.webp

          主要看這個循環(huán)里面的代碼。

          首先 nextInt(27) 就限定了,當前返回的數(shù) k 一定是在 [0,27) 之間的一個數(shù)字。

          如果返回 0,那么循環(huán)結(jié)束,如果不為零。則做一個類型轉(zhuǎn)換。

          接下來就是一個 char 類型的強制轉(zhuǎn)換。

          看到數(shù)字轉(zhuǎn) char 類型,就應該條件反射的想到 ascii 碼:

          c3cb281817327f317bc13206efa3c352.webp

          從 ascii 碼 表中,我們可以到 “96” 就是這里的這個符號:

          b612bd108ebbcf582c5d1c6778a826a6.webp

          所以,下面這個代碼的范圍就是 [96+1,96+26]:

          '`' + k

          也就是 [97,122],即對應 ascii 碼的 a-z。

          所以,我?guī)阍侔焉厦娴难菔敬a拆解一下。

          首先 new Random(-229985452).nextInt(27) 的前五個返回是這樣的:

          a0727a0c6016cc8aff5f357611d04942.webp

          而 new Random(-147909649).nextInt(27) 的前五個返回是這樣的:

          21e7ef7e28bddd493bc491678ac80366.webp

          所以,對照著 ascii 碼表看,就能看出其對應的字母了:

          8 ?+ 96 = 104 --> h
          5 ?+ 96 = 101 --> e
          12 + 96 = 108 --> l
          12 + 96 = 108 --> l
          15 + 96 = 111 --> o

          23 + 96 = 119 --> w
          15 + 96 = 111 --> o
          18 + 96 = 114 --> r
          12 + 96 = 108 --> l
          4 ?+ 96 = 100 --> d

          現(xiàn)在,對于這一段謎一樣的代碼為什么輸出了 “hello world” 的原因,心里是不是撥開云霧見青天,心里跟明鏡兒似的。

          看穿了,也就是一個小把戲而已。

          84fa60d75e816c77369b0c54202f901e.webp

          然后這個問題下面還有個評論,讓我看到了另外一種打開方式:

          ddcc5676bf10853142272d9d78d49809.webp

          你能指定打印出 hello world,那么理論上我也能指定打出其他的單詞。

          比如這個老哥就打了一個短語:the quick browny fox jumps over a lazy dog.

          如果從字面上直譯過來,那么就是“敏捷的棕色狐貍跨過懶狗”,好像也是狗屁不通的樣子。

          但是,你知道的,我的 English 水平是比較 high 的,一眼就看出這個短語在這里肯定不簡單。

          于是查了一下:

          8b35c3bcce63a9b8baa52c7111de90e9.webp

          果然是有點故事的,屬于 tricks in tricks。

          be5ed0d53893607aa1dff6c0e8dfb618.webp

          你看學沙雕技術(shù)的時候還順便豐富了自己的英語技能,一舉多得,這一會看完了還不得在文末給我點個贊、點個“在看”啥的?

          看完這個老哥的 quick brown fox 示例之后,我又有一點新想法了。

          既然它能把所有的字母都打出來,那我是不是也能把我想要的特定的短語也打出來呢?

          比如 i am fine thank you and you 這樣的東西。

          而查找指定單詞對應的 seed 這樣的功能的代碼,在這個問題的回答中,已經(jīng)有“好事之人”幫我們寫出來了。

          我就直接粘過來,你也可以直接拿去就用:

          public?static?long?generateSeed(String?goal,?long?start,?long?finish)?{
          ????char[]?input?=?goal.toCharArray();
          ????char[]?pool?=?new?char[input.length];
          ????label:
          ????for?(long?seed?=?start;?seed?????????Random?random?=?new?Random(seed);

          ????????for?(int?i?=?0;?i?????????????pool[i]?=?(char)?(random.nextInt(27)?+?'`');

          ????????if?(random.nextInt(27)?==?0)?{
          ????????????for?(int?i?=?0;?i?????????????????if?(input[i]?!=?pool[i])
          ????????????????????continue?label;
          ????????????}
          ????????????return?seed;
          ????????}
          ????}
          ????throw?new?NoSuchElementException("Sorry?:/");
          }

          那么我要找前面提到的短語,就很簡單了:

          377b53feffed93eddea04a4141129378.webp

          而且運行的時候我明顯感覺到,在搜索“thank”這個單詞的時候,花了很多時間。

          為什么?

          我給你講一個故事啊,只有一句話,你肯定聽過:

          只要時間足夠漫長,猴子都能敲出一部《莎士比亞》。

          我們這里 generateSeed 方法,就相當于這個猴子。而 thank 這個單詞,就是《莎士比亞》。

          在 generateSeed 方法里面,通過 26 個字母不斷的排列組合,總是能排列出 “thank” 的,只是時間長短而已。

          單詞越長,需要的時間就越長。

          比如我來個 congratulations,這么長的單詞。你猜要跑多久?

          本來這篇文章是周一發(fā)的,但是周一發(fā)的時候忘記標注原創(chuàng)了,所以我發(fā)了之后立刻刪除了文章。

          剛好這個單詞我就可以多跑兩天時間。

          我看了一下,從 4 月 10 號 00:05 分,跑到 4 月12 號 22 點,70?個小時了都還沒跑出來:

          6116d772263b1f2e694279bb93243bcf.webp

          控制臺空空蕩蕩,我甚至懷疑是不是程序停了。于是還看了一下線程堆棧,確認了程序確實是在跑:

          7a8b5b3eedc2e51884309bbd29e2f4db.webp

          但是理論上來講只要有足夠長的時間,這個 seed 一定會被找到。

          至此,你應該完全明白了為什么前面提到的那段代碼,使用隨機字符串的方式打印出了 hello world。

          3409405a31a2080d0cfbb13f8f3c2c66.webp

          源碼

          你以為我要帶你讀源碼?

          不是的,我主要帶你吃瓜。

          首先,看一下的 Random 無參構(gòu)造函數(shù):

          3b48d76b68e3b1fd5b1dff8ff8b67bc3.webp

          好家伙,原來也是套個了個“無參”的殼而已,實際上還是自己搞了一個 seed,然后調(diào)用了有參構(gòu)造方法。

          只是它構(gòu)建的時候加入了“System.nanoTime()”這個變量,讓 seed 看起來隨機了一點而已。

          等等,前面不是還有一個“seedUniquifier”方法嗎?

          這個方法是這樣的:

          8633ec913d09ad6f975872f0a6fb909b.webp

          好家伙,看到第一眼的時候我頭都大了,這里面有兩個“魔法數(shù)”?。?/p>

          181783497276652981L
          8682522807148012L

          這玩意也看不懂啊?

          遇事不決,stackoverflow。

          一搜就能找到這個地方:

          https://stackoverflow.com/questions/18092160/whats-with-181783497276652981-and-8682522807148012-in-random-java-7

          a98f7899585cecb16071039e31d3bc39.webp

          在這個問題里面,他說他對這兩個數(shù)字也感到很懵逼,網(wǎng)上找了一圈,相關(guān)的資料非常的少。但是找到一個論文,里面提到了其中一個很接近的“魔數(shù)”:

          4dda7eeb472a17265c008d83542e249d.webp

          論文中提到的數(shù)是這樣的:

          3d7ba647962ebb0f0baf6b04ee2671b7.webp

          看到?jīng)]有?

          這 Java 源碼中的數(shù)字前面少了一個“1”呀,咋回事呢,該不會是拷貝的時候弄錯了吧?

          下面的一個高贊回答是這樣的:

          0da5d4ebd32eb6802998506103758fb5.webp

          “看起來確實像是拷錯了?!?/p>

          有點意思,你要說這是寫 Java 源碼的老哥 copy 代碼的時候手抖了,我就來勁了。

          da36804a676b178c91e4742c66c8244c.webp

          馬上去 Java Bug 的頁面上拿著那串數(shù)字搜一下,還真有意外收獲:

          https://bugs.openjdk.java.net/browse/JDK-8201634

          3a2d3be0a30548f3c7ccf974ddc9cc1f.webp

          在這個 bug 的描述里面,他讓我注意到了源碼的這個地方:

          09d091168ad2bbb3d685287a0324b612.webp

          原來這個地方的注釋代表著一個論文呀,那么這個論文里面肯定就藏著這個數(shù)的來源。

          等等,我怎么感覺這個論文的名字有點像眼熟啊?

          前面 stackoverflow 中提到的這個鏈接,點進去就是一個論文地址:

          daa71dc7b81dabbd51a859cbae508ecf.webp

          你看看這個論文的名稱和 Java 這里的注釋是不是說的一回事呀:

          c3d6e269515945acdf5414269974dc61.webp

          那必須是一回事啊,只是一個小寫一個大寫而已。

          所以,到這里實錘了,確實是最開始寫 Java 這塊源碼的老哥 copy 數(shù)字的時候手抖了,少 copy 了一個 “1”。

          而且我甚至都能想象到當時寫這部分源碼的時候,那個老哥把“1181783497276652981”這個數(shù)字粘過來,發(fā)現(xiàn):哎,這前面怎么有兩個 1 啊,整重復了,刪除了吧。

          至于把這個“1”刪除了之后,會帶來什么問題呢?

          d5ecaf94210533c41eaf80a9d7cca4bb.webp

          反正這里關(guān)聯(lián)了一個問題,說的是:并發(fā)調(diào)用 new Random() 的隨機性不夠大。

          這我就沒去研究了,有興趣可以去看看,我只負責帶你吃瓜。

          所以,基于這個“瓜”,官方修改了一次這個代碼:

          135b9b70318f8f629d90d6497d546487.webp

          剛好我這里有 JDK 15 和 JDK 8 版本的代碼,我去看了一下,還真是差了一個 “1” :

          018c4901d3b8be900b0b7710295b455f.webp

          而且關(guān)于隨機數(shù),現(xiàn)在一般很少用 Random 了吧。

          直接就是上 ThreadLocalRandom 了,它不香嗎?

          什么,你說不會?

          379e242e88d973b4ab2b2478d10dba40.webp

          好了,那本文的技術(shù)部分就到這里啦。

          下面這個環(huán)節(jié)叫做[荒腔走板],技術(shù)文章后面我偶爾會記錄、分享點生活相關(guān)的事情,和技術(shù)毫無關(guān)系。我知道看起來很突兀,但是我喜歡,因為這是一個普通博主的生活氣息。

          你要不喜歡,退出之前記得文末點個“在看”哦。

          荒腔走板

          0158a65fa4ad5c3e7bec5fc94168610c.webp

          上個周末,成都兩天都是大太陽。

          周六的時候我們一起去菜市場買菜,發(fā)現(xiàn)水果那一個片區(qū)里面都已經(jīng)開始賣西瓜了。

          看到切開的大西瓜那紅紅的瓜瓤,我想:應該是夏天已經(jīng)來了。

          我覺得成都其實一年只有兩季,夏季和冬季。春季往往就那么十來天的時候,而秋季總是在幾場大風之后就迅速的結(jié)束了。

          我還是比較喜歡夏天的,至少不必把自己裹起來,可以更方便的活動筋骨。我在夏天跑步會比較頻繁一點。

          我更喜歡在夏天的晚上跑步,伴隨著靜謐、涼爽、蟲鳴和心跳。但是夏天,在成都夜跑也是一件非?!拔kU”的事情。

          畢竟路邊燒烤攤,常常出現(xiàn)在街頭拐角的地方。而燒烤攤常常不是一家家的出現(xiàn),而是一片片的出現(xiàn)。那是一種我只要遇到了就很難抵擋的場面和味道。

          這個時候,我腦海里面就出現(xiàn)了兩個小人。

          一個說:算了,遇都遇到了,說明緣分到了,跑步每天都可以跑,流動燒烤攤可不一定每天都有。

          另外一個小人說:對呀對呀,吃一個至少吃一個烤苕皮吧,烤的時候記得讓老板多烤一小會,讓兩面表皮稍微有一點點焦,但是整體又偏向松軟。然后里面多加點折耳根和辣豇豆,最后撒上蔥花和辣椒粉。咬了第一口,先是引爆自己的味蕾,然后一絲絲辣意直沖天靈蓋,讓你趕緊想吃第二口。哦,對了,順便來一瓶勇闖天涯吧。

          于是,我本來是出來跑步的,但是,燒烤攤上卻多了一個顧客。

          最后說一句

          好了,看到了這里了, 轉(zhuǎn)發(fā)、在看、點贊 隨便安排一個吧,要是你都安排上我也不介意。寫文章很累的,需要一點正反饋。

          給各位讀者朋友們磕一個了:74da4bbecbeba2ca0822b9981424000a.webp

          推薦???:這個人,該火!

          推薦???:一不小心節(jié)約了 591 臺機器!

          推薦???:我復現(xiàn)了Spring的漏洞,害怕!

          推薦???:當Synchronized遇到這玩意兒,有個大坑,要注意!

          推薦???:2021,我這一年。

          ··································

          你好呀,我是歪歪。一個主要敲代碼,經(jīng)常懟文章,偶爾拍視頻的成都人。

          我沒進過一線大廠,沒創(chuàng)過業(yè),也沒寫過書,更不是技術(shù)專家,所以也沒有什么亮眼的title。

          當年以超過二本線 13 分的“優(yōu)異成績順利進入某二本院校計算機專業(yè),誤打誤撞,進入了程序員的行列,開始了運氣爆棚的程序員之路。

          說起程序員之路還是有點意思,可以看看。點擊藍字,查看我的程序員之路

          瀏覽 59
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本男女拍拍视频 | 在线免费观看三级成人片 | 秋霞影院一区二区三区 | 成人亚洲精品一区二区三区嫩花 | 91麻豆精产国品 |