面試時容易忽略的細(xì)節(jié)

  1. 熱更新原理
    客戶端向服務(wù)器請求時,在請求頭部帶上range: bytes=2000070-谴古,表示文件請求從2000070開始。服務(wù)端收到請求時怯屉,在響應(yīng)中帶上content-range=bytes 2000070-106786027/106786028抛猫,同時將return code從200改為206。
    而文件的續(xù)寫刃泡,可以使用io包中的RandomAccessFile巧娱。
Url url = new Url("http://www.jizhuomi.com/android/down.zip");  
Httpurlconnection httpconnection = (httpurlconnection)url.openconnection();  
//設(shè)置user-agent  
httpconnection.setrequestproperty("user-agent","netfox");  
//設(shè)置斷點續(xù)傳的開始位置  
httpconnection.setrequestproperty("range","bytes=2000070");  
//獲得輸入流  
Inputstream input = httpconnection.getinputstream(); 
//從輸入流中取出的字節(jié)流就是down.zip文件從2000070開始的字節(jié)流。

randomaccess osavedfile = new randomaccessfile("local_down.zip","rw");  
long npos = 2000070;  
//定位文件指針到npos位置  
osavedfile.seek(npos);  
byte[] b = new byte[1024];  
int nread;  
//從輸入流中讀入字節(jié)流烘贴,然后寫到文件中  
while((nread=input.read(b,0,1024)) > 0) {  
  osavedfile.write(b,0,nread);  
} 
  1. ANR
    anr最近三天的trace.txt會保存到/data/system/dropbox目錄下禁添。這是由DropBoxManager實現(xiàn)的,該類可以理解為一個持久化的logcat桨踪。讀源碼時發(fā)現(xiàn)老翘,anr的logcat是在ActivityManagerService的appNotResponding()輸出的,其中用到了一個很實用的工具類Os锻离,里面有個Os.chmod(path,mode)方法可以便利地設(shè)置文件權(quán)限铺峭。而trace.txt的寫入必須在20s內(nèi)完成,ActivityManagerService通過FileObserver實現(xiàn)對文件讀寫的監(jiān)聽汽纠。一旦文件有修改卫键,會觸發(fā)FileObserver.onEvent()通知監(jiān)聽者。

3.熱更新原理
Java運行時的類加載是通過抽象類ClassLoader實現(xiàn)的虱朵,而Android中其默認(rèn)實現(xiàn)是PathClassLoader莉炉。后者的父類是BaseDexClassLoader钓账。PathClassLoader只是簡單地從文件系統(tǒng)中加載類文件,而BaseDexClassLoader重寫了findClass()方法絮宁,并在其中委托DexPathList去調(diào)用它的findClass()梆暮。

public Class findClass(String name, List<Throwable> suppressed) {
    for (Element element : dexElements) {
        DexFile dex = element.dexFile;

        if (dex != null) {
            Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
    }
    if (dexElementsSuppressedExceptions != null) {
        suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
    }
    return null;
}

要實現(xiàn)熱更新,就需要我們在運行時去更改PathClassLoader.pathList.dexElements.并將我們的hotpacth dex文件出現(xiàn)在dexElements列表的前面羞福。

  1. 閱讀錯誤報告(bugreport)

  2. 今日頭條屏幕適配原理:屏幕寬度(px)/設(shè)計稿寬度(dp) = 目標(biāo)屏幕寬度(px)/目標(biāo)值(dp)惕蹄。利用的是動態(tài)修改屏幕密度,使得兩者屏幕密度相等(density = px / dp)治专。
    參考:
    Android 目前最穩(wěn)定和高效的UI適配方案
    Android屏幕適配方案(出自今日頭條)
    關(guān)于今日頭條的屏幕適配方案學(xué)習(xí)理解

  3. 顯示大圖卖陵,但是不能壓縮BitmapRegionDecoder

BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false);
bitmapRegionDecoder.decodeRegion(rect, options);

7.本地緩存DiskLruCache
主要記住有一個journal.temp文件去保存每次緩存讀寫狀態(tài):DIRTY(寫入緩存,但是沒有commit),CLEAN(緩存已被commit),REMOVE,READ张峰。同時內(nèi)部LRU邏輯是通過LikedHashMap來實現(xiàn)泪蔫,trimToSize()觸發(fā)回收。

  1. 幾個重要的自定義View用法
  • 渲染:Paint.setShader(Shader shader)喘批。常用的shader:BitmapShader位圖圖像渲染實例撩荣、LinearGradient線性渲染、RadialGradient環(huán)形渲染饶深、SweepGradient掃描漸變渲染/梯度渲染餐曹、ComposeShader組合渲染.

  • 圖像相交 paint.setXfermode(Xfermode xfermode)。 常用的是XfermodePorterDuffXfermode子類

    PorterDuffXfermode效果

  • Alpha濾鏡:setMaskFilter(MaskFilter maskfilter)敌厘。常用的是模糊濾鏡BlurMaskFilter,浮雕濾鏡EmbossMaskFilter

  • 繪制路徑效果:Paint.setPathEffect(PathEffect effect)

    PathEffect

  • 顏色過濾:Paint.setColorFilter(ColorFilter filter)台猴,主要對RGB(A)進行過濾。

    ColorFilter

  • 曝光顏色過濾:Paint.setColorFilter(new LightingColorFilter(int mul, int add))俱两。實質(zhì)計算方式就是(mul * 原色值 + add)% 255饱狂,不過一定要注意,該過濾器是不處理Alpha的宪彩,也就是說只對圖片里的RGB有效休讳,A無效

  • 圖層混合顏色過濾:PorterDuffColorFilter(int color, PorterDuff.Mode mode)

  1. 兩個Activity跳轉(zhuǎn),必然會執(zhí)行什么方法尿孔?
    一般地俊柔,Activity A 跳轉(zhuǎn)到Activity B,A會先調(diào)用onPause()活合,然后B會調(diào)用onCreate()雏婶,onStart(),onResume()芜辕。
    如果此時B已經(jīng)完全遮擋A尚骄,A會調(diào)用onStop()块差;否則侵续,如果B是個透明窗口倔丈,或者是對話框主題,則A不會調(diào)用onPause()状蜗。
    如果B已經(jīng)存在于Activity棧中需五,則不會調(diào)用onCreate()。

  2. 如果同時使用startService 與bindService 方法啟動Service轧坎,需要終止該Service時宏邮,要調(diào)用stopService 和unbindService 方法(unbindService 依附于啟動它的Context,startServicec 并不依附于啟動它的Context缸血。如果先調(diào)用unbindService 蜜氨,這時服務(wù)并不會被終止,當(dāng)調(diào)用stopService 后捎泻,服務(wù)才會被終止飒炎;如果先調(diào)用stopService ,服務(wù)也不會被終止笆豁,當(dāng)調(diào)用unbindService 或者之前調(diào)用bindService 的Context不存在了(如Activity被finish掉了)服務(wù)才會自動停止)

  3. 屬性動畫原理:屬性動畫的運行機制是通過不斷地對值進行操作來實現(xiàn)的郎汪,而初始值和結(jié)束值之間的過渡則是通過ValueAnimator來負(fù)責(zé)計算。其中TypeEvaluator決定了初始值過渡到結(jié)束值的計算算法(y = sin(x))闯狱,TimeInterpolator決定了初始值過渡到結(jié)束值的節(jié)奏煞赢。

  4. SharedPreferences是線程安全的,但不是進程安全的哄孤。
    第一次getSharedPreferences()會開啟一個單線程池去異步加載照筑。讀取磁盤文件,get/set之前有awaitLoadedLocked()同步操作录豺,在磁盤文件加載完成前會卡住調(diào)用線程朦肘。加載完成之后會從內(nèi)存中讀取。
    apply是內(nèi)存同步操作双饥,但是會開啟一個異步任務(wù)放到單線程隊列中媒抠,更新磁盤緩存。commit同apply類似咏花,但是會等磁盤任務(wù)完成才返回趴生,會有boolean結(jié)果返回。每次 apply / commit 都會把全部的數(shù)據(jù)一次性寫入磁盤, 所以單個的配置文件不應(yīng)該過大, 影響整體性能昏翰。

  5. 在瀏覽器中輸入一個網(wǎng)址苍匆,并得到網(wǎng)頁呈現(xiàn)結(jié)果。這個過程中經(jīng)歷了什么棚菊?
    DNS域名解析->TCP三次握手->TCP建立并發(fā)送HTTP請求->服務(wù)器響應(yīng)HTTP請求->瀏覽器解析HTTP代碼浸踩,同時獲取css,js统求,圖片等資源->瀏覽器渲染頁面并呈現(xiàn)結(jié)果

  6. 為什么是三次握手检碗,四次揮手据块?
    關(guān)閉連接時,當(dāng)Server端收到FIN報文時折剃,很可能數(shù)據(jù)信息沒有傳完并不會立即關(guān)閉連接另假,所以只能先回復(fù)一個ACK報文(告訴Client端,"你發(fā)的FIN報文我收到了")怕犁。只有等到Server端所有的報文都發(fā)送完了边篮,我才能發(fā)送FIN報文,因此不能一起發(fā)送奏甫。故需要四步揮手戈轿。

  7. Webview與js交互總結(jié)

類型 調(diào)用方式 優(yōu)點 缺點 使用場景
Android調(diào)用js WebView.loadUrl("javascript:jsMethod()") 簡潔方便 效率低,獲取返回值麻煩 不需要返回值阵子,對性能要求不高
Android調(diào)用js WebView.evaluateJavascript() 效率高 只兼容Android4.4以上 Android4.4以上
js調(diào)用Android WebView.addJavascriptInterface(new Object(), "objectName") 簡潔方便 Android4.2以下存在安全漏洞 Android4.2以上相對簡單的互調(diào)
js調(diào)用Android WebViewClient.shouldOverrideUrlLoading()回調(diào)攔截 url 不存在安全漏洞 使用復(fù)雜凶杖,需要進行協(xié)議約定;從Native層往Webview傳值比較繁瑣 不需要返回值的互調(diào)(IOS主要使用該方式)
js調(diào)用Android WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調(diào)攔截JS對話框alert()催训、confirm()窖梁、prompt() 消息回調(diào)攔截 url 不存在安全漏洞 使用復(fù)雜,需要進行協(xié)議約定 滿足大多數(shù)情況下的互調(diào)

16.進程保活

  • 黑色保活:不同APP之間相互配合,互相喚醒漆撞;利用系統(tǒng)廣播喚醒,包括ACTION_NEW_PICTURE(拍照)于宙,ACTION_NEW_VIDEO(拍視頻)浮驳,CONNECTIVITY_ACTION(網(wǎng)絡(luò)切換)等;
  • 白色崩炭活:啟動前臺service
  • 灰色敝粱幔活:利用系統(tǒng)的漏洞啟動前臺Service
  • Native進程:利用 Linux 中的 fork 機制創(chuàng)建 Native 進程,在 Native 進程中監(jiān)控主進程的存活谱俭,當(dāng)主進程掛掉后奉件,在 Native 進程中立即對主進程進行拉活
  • JobScheduler:系統(tǒng)會定時調(diào)用該進程以使應(yīng)用進行一些邏輯操作
  • 廠商白名單
    總結(jié):進程保活本就是個偽命題昆著,不存在不死的方法县貌。只能從提升和優(yōu)化自身應(yīng)用的性能,降低進程的oom_adj凑懂。同時不同廠商從系統(tǒng)層對APP進行優(yōu)待處理煤痕。
  1. notify和notifyAll的區(qū)別
    首先區(qū)分兩個概念,鎖池和等待池:
    鎖池:等待當(dāng)前鎖的擁有者線程釋放鎖,以便執(zhí)行該對象的synchronized方法的線程隊列摆碉。
    等待池:線程調(diào)用wait方法釋放鎖祟敛,就會進入等待池。等待池中的線程不會去競爭該對象的鎖兆解。
    當(dāng)擁有鎖的線程調(diào)用notify時,會從等待池中隨機將某一條線程移動到鎖池中跑揉,去競爭鎖的擁有權(quán)锅睛。而調(diào)用notifyAll,所有等待池中的線程都會被移動到鎖池中競爭鎖历谍。優(yōu)先級高的線程競爭到對象鎖的概率大现拒,假若某線程沒有競爭到該對象鎖,它還會留在鎖池中望侈,唯有線程再次調(diào)用 wait()方法印蔬,它才會重新回到等待池中。而競爭到對象鎖的線程則繼續(xù)往下執(zhí)行脱衙,直到執(zhí)行完了 synchronized 代碼塊侥猬,它會釋放掉該對象鎖,這時鎖池中的線程會繼續(xù)競爭該對象鎖捐韩。

  2. 屏幕適配
    dp(dip,也就是密度無關(guān)像素)解決了同一控件數(shù)值在不同分辨率中展示相同大小的問題(也就是屏幕像素密度匹配退唠,dpi),但是沒法解決屏幕尺寸大小帶來的匹配問題(也就是屏幕尺寸匹配)荤胁。

Nexus5的總寬度為360dp瞧预,我們現(xiàn)在在水平方向上放置兩個按鈕,一個是150dp左對齊仅政,另外一個是200dp右對齊垢油,那么中間留有10dp間隔;
但假如同樣地設(shè)置在Nexus S(屏幕寬度是320dp)圆丹,會發(fā)現(xiàn)滩愁,兩個按鈕會重疊,因為320dp<200+150dp

本質(zhì)上是希望使得布局組件在不同屏幕密度上顯示相同的像素效果辫封,對于屏幕尺寸匹配惊楼,可以考慮百分比匹配

  1. Android動態(tài)加載ClassLoader


    JVM的ClassLoader體系

Android平臺的ClassLoader

ClassLoader使用雙親委托機制來實現(xiàn)秸讹。其中熱修復(fù)基本都是利用DexClassLoader來實現(xiàn)檀咙;而PatheClassLoader為Android用來加載應(yīng)用類以及系統(tǒng)類,不推薦開發(fā)者使用璃诀。其父加載器為BootClassLoader弧可。
參考:Android動態(tài)加載ClassLoader熱修復(fù)入門

  1. 樂觀鎖和悲觀鎖
    樂觀鎖:不加鎖劣欢,使用CAS和版本號機制實現(xiàn)棕诵。
    悲觀鎖:加鎖裁良,Java中使用synchronzied關(guān)鍵字實現(xiàn)。
    CAS校套,在Java中使用Unsafe對象實現(xiàn)价脾,它只能保證單個變量的原子性,需要與volatile來保證線程安全笛匙。同時侨把,它還存在ABA問題:
    假設(shè)有兩個線程——線程1和線程2,兩個 線程按照順序進行以下操作:
  • 線程1讀取內(nèi)存中數(shù)據(jù)為A妹孙;
  • 線程2將該數(shù)據(jù)修改為B秋柄;
  • 線程2將該數(shù)據(jù)修改為A;
  • 線程1對數(shù)據(jù)進行CAS操作
    在第(4)步中蠢正,由于內(nèi)存中數(shù)據(jù)仍然為A骇笔,因此CAS操作成功,但實際上該數(shù)據(jù)已經(jīng)被線程2修改過了嚣崭。這就是ABA問題笨触。
    在AtomicInteger的例子中,ABA似乎沒有什么危害雹舀。但是在某些場景下旭旭,ABA卻會帶來隱患,例如棧頂問題:一個棧的棧頂經(jīng)過兩次(或多次)變化又恢復(fù)了原值葱跋,但是棾旨模可能已發(fā)生了變化。
    解決這個問題可以使用AtomicStampedReference娱俺。
    同時稍味,在高并發(fā)沖突下的失敗重試,也會給CPU帶來很大的開銷荠卷。

因此總結(jié)使用場景:

  • 當(dāng)競爭不激烈 (出現(xiàn)并發(fā)沖突的概率小)時模庐,樂觀鎖更有優(yōu)勢,因為悲觀鎖會鎖住代碼塊或數(shù)據(jù)油宜,其他線程無法同時訪問掂碱,影響并發(fā),而且加鎖和釋放鎖都需要消耗額外的資源慎冤。
  • 當(dāng)競爭激烈(出現(xiàn)并發(fā)沖突的概率大)時疼燥,悲觀鎖更有優(yōu)勢,因為樂觀鎖在執(zhí)行更新時頻繁失敗蚁堤,需要不斷重試醉者,浪費CPU資源。
  1. 網(wǎng)絡(luò)安全
  • 消息摘要&數(shù)字簽名
    消息摘要:唯一一個對應(yīng)一段文本的固定長度的值,由單向hash加密函數(shù)對消息進行運算生成撬即。由于其唯一性立磁,不可逆,可用于校驗文本或文件是否篡改剥槐。不需要密鑰唱歧。常用算法有MD(Message Digest,消息摘要算法)和SHA(Secure Hash Algorithm粒竖,安全散列算法)颅崩,最具代表性對分別是MD5,SHA1。
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
        // 更新要計算的內(nèi)容
        md5Digest.update(msg.getBytes());
        // 完成哈希計算温圆,得到摘要
        byte[] md5Encoded = md5Digest.digest();

        MessageDigest shaDigest = MessageDigest.getInstance("SHA");
        // 更新要計算的內(nèi)容
        shaDigest.update(msg.getBytes());
        // 完成哈希計算,得到摘要
        byte[] shaEncoded = shaDigest.digest()
  • 數(shù)字簽名:數(shù)字簽名算法可以看做是一種帶有密鑰的消息摘要算法孩革,并且這種密鑰包含了公鑰和私鑰岁歉。也就是說,數(shù)字簽名算法是非對稱加密算法和消息摘要算法的結(jié)合體膝蜈。要求能夠驗證數(shù)據(jù)完整性锅移、認(rèn)證數(shù)據(jù)來源,并起到抗否認(rèn)的作用饱搏。其原理是利用私鑰簽名非剃,公鑰驗簽,其核心算法是消息摘要算法推沸。最主要對算法有RAS备绽,DSA。總結(jié):公鑰加密鬓催、私鑰解密肺素、私鑰簽名、公鑰驗簽
      /**
       * 獲取私鑰
       * 
      * @param privateKey 私鑰字符串
      * @return
      */
      public static PrivateKey getPrivateKey(String privateKey) throws Exception {
          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
          byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
          PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
         return keyFactory.generatePrivate(keySpec);
     }
 
     /**
      * 獲取公鑰
      * 
      * @param publicKey 公鑰字符串
      * @return
      */
     public static PublicKey getPublicKey(String publicKey) throws Exception {
         KeyFactory keyFactory = KeyFactory.getInstance("RSA");
         byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
         return keyFactory.generatePublic(keySpec);
     }

    /**
     * <p>
     * 用私鑰對信息生成數(shù)字簽名
     * </p>
     *
     * @param data       已加密數(shù)據(jù)
     * @param privateKey 私鑰(BASE64編碼)
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64Utils.encode(signature.sign());
    }
       /**
     * <p>
     * 用公鑰校驗數(shù)字簽名
     * </p>
     *
     * @param data      已加密數(shù)據(jù)
     * @param publicKey 公鑰(BASE64編碼)
     * @param sign      數(shù)字簽名
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64Utils.decode(sign));
    }
    
    /**
     * <p>
     * 公鑰加密
     * </p>
     *
     * @param data      源數(shù)據(jù)
     * @param publicKey 公鑰(BASE64編碼)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 對數(shù)據(jù)加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }
    
    /**
     * <p>
     * 公鑰解密
     * </p>
     *
     * @param encryptedData 已加密數(shù)據(jù)
     * @param publicKey     公鑰(BASE64編碼)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }
    
/**
     * <p>
     * 私鑰加密
     * </p>
     *
     * @param data       源數(shù)據(jù)
     * @param privateKey 私鑰(BASE64編碼)
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }


    /**
     * <P>
     * 私鑰解密
     * </p>
     *
     * @param encryptedData 已加密數(shù)據(jù)
     * @param privateKey    私鑰(BASE64編碼)
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
            throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 對數(shù)據(jù)分段解密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宇驾,一起剝皮案震驚了整個濱河市倍靡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌课舍,老刑警劉巖塌西,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異筝尾,居然都是意外死亡捡需,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門筹淫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栖忠,“玉大人,你說我怎么就攤上這事♀帜” “怎么了狸相?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捐川。 經(jīng)常有香客問我脓鹃,道長,這世上最難降的妖魔是什么古沥? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任瘸右,我火速辦了婚禮,結(jié)果婚禮上岩齿,老公的妹妹穿的比我還像新娘太颤。我一直安慰自己,他們只是感情好盹沈,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布龄章。 她就那樣靜靜地躺著,像睡著了一般乞封。 火紅的嫁衣襯著肌膚如雪做裙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天肃晚,我揣著相機與錄音锚贱,去河邊找鬼。 笑死关串,一個胖子當(dāng)著我的面吹牛拧廊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晋修,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼卦绣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了飞蚓?” 一聲冷哼從身側(cè)響起滤港,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎趴拧,沒想到半個月后溅漾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡著榴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年添履,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脑又。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡暮胧,死狀恐怖锐借,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情往衷,我是刑警寧澤钞翔,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站席舍,受9級特大地震影響布轿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜来颤,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一汰扭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧福铅,春花似錦萝毛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拷沸,卻和暖如春色查,著一層夾襖步出監(jiān)牢的瞬間薯演,已是汗流浹背撞芍。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留跨扮,地道東北人序无。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像衡创,于是被迫代替她去往敵國和親帝嗡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 別人的總結(jié)不一定適合自己璃氢,所以盡量多做一些自己的總結(jié)哟玷,針對自己的薄弱點重點說明,適當(dāng)?shù)慕梃b別人一也,少走一些彎路巢寡。最重...
    renkuo閱讀 7,413評論 2 48
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,104評論 1 32
  • 在一個方法內(nèi)部定義的變量都存儲在棧中,當(dāng)這個函數(shù)運行結(jié)束后椰苟,其對應(yīng)的棧就會被回收抑月,此時,在其方法體中定義的變量將不...
    Y了個J閱讀 4,418評論 1 14
  • 記錄關(guān)于我和路過的狗狗們互動舆蝴!
    鄭靈悅閱讀 257評論 16 3
  • 雖然有點力不從心谦絮,但蒲公英可不想放棄信念题诵,以前他看到過媽媽在風(fēng)雨中的倔犟。那時他還不懂生活的考驗這么殘酷〔阒澹現(xiàn)在他要...
    小緣小愿閱讀 198評論 1 3