接上篇
威寧ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書(shū)銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書(shū)合作)期待與您的合作!在很多場(chǎng)合下,都需要給字符串進(jìn)行加密,使字符串由”明文”變成”密文”。對(duì)字符串加密有很多種算法,其實(shí)我們利用位運(yùn)算也可以實(shí)現(xiàn)簡(jiǎn)單的加密效果。用位運(yùn)算實(shí)現(xiàn)加密的原理很簡(jiǎn)單,這里為大家講解一下。假設(shè)有兩個(gè)整數(shù)a和b ,a^b的結(jié)果為c。我們可以認(rèn)為a就是原始數(shù)據(jù),a與b進(jìn)行異或運(yùn)算所得到的c就是加密后的數(shù)據(jù),b在加密過(guò)程中扮演著”密鑰”的角色。在不知道b值的情況下,如果只是知道c的值,任何人無(wú)法僅僅根據(jù)c的值反推出a的值,也就是說(shuō),如果我們只知道加密后的數(shù)據(jù),而不知道密鑰,根本無(wú)法確切得知原始數(shù)據(jù)a的值到底是多少。如果想根據(jù)加密后的數(shù)據(jù)c來(lái)還原初始數(shù)據(jù)a,就必須用密鑰b來(lái)解密。解密的方法也很簡(jiǎn)單,只要進(jìn)行c^b的操作就可以了。其原理就是”a^b^b=a”,在這個(gè)等式中,”a^b”的結(jié)果就是c,所以”c^b=a”。
理解了加密和解密的最基本原理之后,我們?cè)賮?lái)說(shuō)說(shuō)如何具體對(duì)字符串實(shí)施加密操作。我們知道,位運(yùn)算符只能對(duì)byte、short、int、long和char這幾種基礎(chǔ)類型的數(shù)據(jù)進(jìn)行運(yùn)算,對(duì)字符串這種引用類型的數(shù)據(jù)并不適用。既然字符串無(wú)法進(jìn)行位運(yùn)算,那么該如何對(duì)字符串進(jìn)行加密呢?我們知道,無(wú)論是圖片還是文本,在計(jì)算機(jī)當(dāng)中都是以二進(jìn)制數(shù)的形式進(jìn)行存儲(chǔ)的。既然是二進(jìn)制數(shù),那么每8位的二進(jìn)制數(shù),都可以轉(zhuǎn)換成一個(gè)byte類型的數(shù)據(jù)。而N個(gè)8位二進(jìn)制,就可以轉(zhuǎn)換成一個(gè)byte數(shù)組。概括成一句話就是:任何形式的信息,在計(jì)算機(jī)當(dāng)中都可以用byte數(shù)組來(lái)存儲(chǔ)和表示。
我們現(xiàn)在要對(duì)字符串進(jìn)行加密,表示字符串的String類提供了一個(gè)叫做getBytes的方法,這個(gè)方法可以把字符串轉(zhuǎn)換成一個(gè)byte數(shù)組。我們讓數(shù)組中的每一個(gè)元素都與某個(gè)數(shù)key進(jìn)行異或運(yùn)算,就能得到一個(gè)全新的byte數(shù)組,這個(gè)全新的byte數(shù)組本質(zhì)上就是加密后的字符串,而那個(gè)數(shù)字key,其實(shí)就是加密過(guò)程中的”密鑰”,如果我們想要還原字符串,根據(jù)之前講過(guò)的”c^b=a”這個(gè)等式,我們可以再次用key這個(gè)數(shù)字與那個(gè)全新的byte數(shù)組的每一個(gè)元素做一次異或運(yùn)算就可以。字符串加密的完整代碼如下:
public static void main(String[] args) {
String initString = "你好";//原始字符串
byte[] bytes = initString.getBytes();
byte[] tranCodes = new byte[bytes.length];//用于保存每個(gè)加密后的字節(jié)
byte key = 111;//密鑰
System.out.println("原始字符串為:"+initString);
//加密過(guò)程
for (int i = 0; i < bytes.length; i++) {
tranCodes[i] = (byte)(bytes[i] ^ key);// 對(duì)每個(gè)字節(jié)進(jìn)行加密
}
String encode = new String(tranCodes);//用加密后的字節(jié)數(shù)組創(chuàng)建字符串
System.out.println("加密后的字符串:"+encode);//輸出加密后的字符串
//解密過(guò)程
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte)(tranCodes[i] ^ key);//對(duì)每個(gè)字節(jié)完成解密
}
String decode = new String(bytes);
System.out.println("解密后的字符串:"+decode);//輸出解密后的字符串
}
如果密鑰key的值為111,程序運(yùn)行效果如下圖
如果密鑰key的值為121,程序運(yùn)行效果如下圖
我們知道,一個(gè)二進(jìn)制數(shù),每個(gè)位上只能有0和1這兩種情況。如果我們想計(jì)算出一個(gè)N位的二進(jìn)制數(shù),總共有多少個(gè)位上是1,該如何計(jì)算呢?我們可以把這個(gè)二進(jìn)制數(shù)進(jìn)行右移1位,然后再左移1位,如果經(jīng)過(guò)兩次位移運(yùn)算,這個(gè)二進(jìn)制數(shù)仍然保持不變,那么說(shuō)明這個(gè)二進(jìn)制數(shù)的最低位(也就是最右邊那1位)上的數(shù)字為0,否則說(shuō)明最低位為1。有的小伙伴可能沒(méi)有弄明白這個(gè)原理,我們以一個(gè)8位的二進(jìn)制數(shù)”00000101”作為例子來(lái)說(shuō)明。我們把該二進(jìn)制數(shù)稱為a。我們可以看到:a的最低位為1。如果a右移1位,將得到” 00000010”,然后再把” 00000010”左移1位,按照”左移操作最右邊補(bǔ)0”的運(yùn)算規(guī)則,可以得到運(yùn)算結(jié)果為” 00000100”,我們把這個(gè)運(yùn)算結(jié)果稱為b。可以看出,a與b并不相等。然而,假如a的值為” 00000100”的話,也就是說(shuō),a的最低位為0,那么經(jīng)過(guò)一次”右移再左移”,所得到的運(yùn)算結(jié)果b仍然是” 00000100”。因此,一個(gè)二進(jìn)制數(shù)經(jīng)過(guò)一次”右移再左移”的操作,如果仍然能夠和原來(lái)的值相同,那么說(shuō)明這個(gè)二進(jìn)制數(shù)的最低位為0,否則最低位為1。
現(xiàn)在的題目要求我們計(jì)算一個(gè)二進(jìn)制數(shù)的各位總共有多少個(gè)1,而以上算法僅能判斷最低位是否為1,那么應(yīng)該怎樣把一個(gè)二進(jìn)制數(shù)上所有的1都統(tǒng)計(jì)一遍呢?還拿剛才舉例所用的二進(jìn)制數(shù)a來(lái)講解。我們可以首先定義一個(gè)計(jì)數(shù)器,命名為count,并設(shè)count的初始值為0。當(dāng)我們把a(bǔ)進(jìn)行一次”右移再左移”的操作之后,發(fā)現(xiàn)原始數(shù)字a和運(yùn)算結(jié)果b并不相同,這說(shuō)明a的最低位是1,而我們要做的事情正是計(jì)算a當(dāng)中總共有多少個(gè)位上是1,于是我們就可以把計(jì)數(shù)器count加1。之后,我們?cè)侔補(bǔ)做一次無(wú)符號(hào)右移并賦值給a自身。這里有兩個(gè)需要注意的細(xì)節(jié)。首先,無(wú)符號(hào)右移結(jié)束之后,有一個(gè)非常關(guān)鍵的操作”賦值給a自身”,這使得a會(huì)被重新賦值,從而a的值就變成了”00000010”。其次,我們對(duì)a進(jìn)行賦值之前進(jìn)行的那個(gè)右移操作是”無(wú)符號(hào)右移”,也就是給a的最左邊補(bǔ)的數(shù)是0。如果我們不斷的重復(fù)這個(gè)過(guò)程,直到a的值變?yōu)椤?0000000”才停下來(lái)。在這個(gè)過(guò)程中,每次遇到最低位為1的情況,就使計(jì)數(shù)器count的值加1。當(dāng)運(yùn)算徹底停止之后,通過(guò)count的值就可以得知a的各個(gè)位總共有多少個(gè)1。計(jì)算二進(jìn)制數(shù)中各個(gè)位總共有多少個(gè)1的完整代碼如下:
public static void main(String[] args) {
int a = 7;
int count=0;
while(a!=0)
{
if((a>>1)<<1!=a) //對(duì)a進(jìn)行"右移再左移",判斷其結(jié)果是否等于原來(lái)的a
{
++count;
}
a = a>>>1;//完成1次判斷,對(duì)a進(jìn)行無(wú)符號(hào)右移并把運(yùn)算結(jié)果賦值給a自身
}
System.out.println("a轉(zhuǎn)換為二進(jìn)制數(shù)后,有"+count+"個(gè)1");
}
(未完待續(xù)...)
如想系統(tǒng)學(xué)習(xí)Java編程,歡迎觀看我在本站的視頻課程。
網(wǎng)頁(yè)題目:Java千問(wèn):Java位運(yùn)算經(jīng)典應(yīng)用(三)-創(chuàng)新互聯(lián)
網(wǎng)頁(yè)地址:http://aaarwkj.com/article22/ccjpcc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、企業(yè)建站、靜態(tài)網(wǎng)站、標(biāo)簽優(yōu)化、網(wǎng)站制作、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容