Android面試指南(八)

目錄

1、Java語言相關

1.1、String的intern方法

1.2、HashMap的擴容

1.3、Java數組不支持泛型

1.4、泛型類型保留到運行時

1.5、匿名內部類使用的外部變量需要加final

2、Kotlin語言相關

3、設計模式

1、Java語言相關

1.1、String的intern方法

    1)、String的存儲機制

    String內存模型的核心特點包括:

    • 不可變性:String實例一旦創建不可修改
    • 雙重存儲機制:實例可能存儲在堆或字符串常量池
    • intern方法作用:將字符串顯式存入字符串池中

    String類的特殊性體現在:

    • 不可變性:與基本數據類型封裝類相同
    • 聲明語法特殊:唯一可通過字面量創建的引用類型
    • 存儲位置特殊:實例可能存在于字符串常量池而非堆

    ①、String不可變性的實現機制:

    • final類聲明:禁止繼承
    • private final char[]存儲數據:外部無法修改
    • 方法設計原則:比如substring等操作均返回新實例

    ②、String實例不可變的表現:

    • 任何修改操作(如拼接、截取)均生成新實例
    • 原實例內容始終保持不變
    • 必須通過改變引用指向新實例實現"修改"效果

    2)、字符串常量池

    • 字符串池與常量池的區別:常量池存在于每個class文件的邏輯結構中,存儲以字面量方式聲明的字符串;運行時常量池是class文件常量池加載到內存后的形態。
    • 字符串池功能:全局存儲字符串(非每個類獨立),HotSpot虛擬機通過哈希表實現。
    • 關聯性:常量池中的string類型常量通過查詢字符串池解析,二者通過引用保持一致性,導致概念易混淆。

    字符串常量池的優化原理:

    • 相同字面量的多個String實例可共享
    • intern方法實現實例復用
    • 哈希值相同且equals為true的實例可合并

    內存優化示例:字面量均為"ABC"的name1和name2引用可通過intern指向同一實例。

    3)、總結

    string的不可變性使字符串池復用成為可能,JDK1.7+的字符串池存儲堆引用,相關面試題多圍繞內存模型展開,需理解存儲機制。

    • JDK 1.7以下(不包括1.7),字符串池在永久代,intern方法的含義是:
      • 如果字符串池中存在與當前字符串內容相同的緩存,則返回緩存實例;
      • 否則,在字符串池中創建相應實例,并返回。
    • JDK1.7及以上,字符串池在堆中,字符串池中,存儲的是字符串堆引用,intern方法的含義是:
      • 如果字符串池中存在與當前字符串內容相同的緩存,則返回緩存的引用;
      • 否則,在字符串池中存儲當前字符串的引用。

    1.2、HashMap的擴容

    HashMap容量選擇二的N次方的原因如下:

    • 計算數組下標時可通過位運算替代取余操作,從而提升運算性能
    • 擴容時無需重新計算所有節點位置,僅需檢查新參與運算的最高位即可

    1)哈希算法

    散列算法將任意長度輸入轉換為固定長度輸出,要求相同輸入必產生相同輸出。哈希碰撞指不同輸入產生相同輸出的情況。理想哈希算法應最大限度避免碰撞,簡單取余算法因碰撞概率高不適用于高性能場景。

    哈希碰撞:哈希表中元素位置通過哈希碼對容量取余確定。碰撞發生時元素會被放入相同桶中,該機制是哈希表定位元素的基礎算法。

    2)HashMap

    HashMap主體結構是初始長度16的數組,數組存儲Node類型元素。傳統桶結構采用鏈表實現,JDK1.8新增紅黑樹實現(TreeNode為Node子類)。數組與紅黑樹會根據元素數量動態轉換,紅黑樹在數據量大時具有性能優勢。

    ①、put方法

    put方法實際調用putVal實現存儲,過程中會通過hash()方法重新計算鍵的哈希碼。

    ②、putVal方法

    putVal方法執行流程如下:

    • 檢測數組是否為空,空則觸發resize擴容
    • 計算元素數組下標(非直接取余)
    • 下標為空時新建節點插入
    • 下標非空時判斷鍵是否相等,相等則覆蓋值
    • 不相等時根據節點類型(鏈表/紅黑樹)遍歷查找
    • 鏈表插入后檢查是否需轉為紅黑樹
    • 最終檢查是否觸發擴容

    計算元素在數組中的下標:下標計算采用(n-1)&hash替代取余操作,二者數學等價但位運算效率更高。以容量16為例:

    • 16-1=15(二進制1111)
    • 與哈希碼按位與操作可保留后四位
    • 該優化的前提是容量必須為2的n次冪,此為設計原因之一。

    ③、hash方法

    hash()方法通過擾動函數解決低位碰撞問題:

    • 將哈希碼無符號右移16位使高位參與運算
    • 與原值異或融合高位特征到低位
    • JDK 1.8的擾動邏輯較1.7簡化但原理一致,核心目標是提升低位隨機性。

    ④、resize方法

    擴容機制特性分析:

    維度

    JDK 1.7前

    JDK 1.8優化

    容量變化

    翻倍為2^n

    保持2^n特性

    重定位方式

    全量重新計算下標

    僅檢查新增最高位

    元素移動

    全部遷移

    原位置或原位置+舊容量

    優化依據:擴容后元素新位置僅取決于新增運算位(0保持原位,1偏移舊容量值)。此特性同樣依賴2^n容量設計。

    1.3、Java數組不支持泛型

    Java數組不支持泛型的說法需明確兩點:泛型僅在編譯期提供有限類型安全保證,且實際限制在于無法創建泛型類型數組。核心原因包括:

    • 類型擦除機制使運行時泛型信息丟失
    • 數組協變性與泛型設計理念沖突
    • Java泛型實現受歷史兼容性制約

    Java數組不支持泛型的原因在于數組與泛型在設計理念上存在根本性沖突。數組是JVM底層實現的特殊實例類型,自Java早期版本就已存在;而泛型在Java 1.5版本才引入。兩者核心矛盾在于:數組具有協變性(父類型數組引用可指向子類型數組實例),而泛型默認具有不變性(泛型類之間無繼承關系)。這種設計差異導致無法通過編譯期類型安全檢查創建泛型數組實例。

    1)、Java泛型的實現方式

    類型擦除機制特點:

    • 泛型類型參數僅在編譯期有效,字節碼中替換為原始類型
    • 生成橋接方法保證多態性
    • 歷史原因:保持與Java1.5前版本的二進制兼容性

    2)、泛型的類型擦除機制

    泛型類型擦除機制實現方式可通過反編譯字節碼觀察。new指令及構造方法調用均不包含泛型信息,創建的ArrayList實際為Object類型。繞過編譯器報錯可將任意類型元素放入ArrayList,此現象解釋了字符串元素存入非泛型集合的可能性。

    類型擦除:類定義的泛型經類型擦除后固化為Object。子類繼承父類時給定的泛型參數需具體化,例如實現change方法時參數與返回值被具體化為Apple類型。由于父類方法簽名中為Object,編譯器自動生成橋接方法以維持重寫關系。類型擦除導致運行時無法創建泛型數組,且泛型無法在運行時保證內存安全。總結:

    • 字節碼創建數組需明確類型
    • 類型擦除使泛型無法延續至運行時
    • Java泛型無法實現運行時類型安全檢查

    3)、Kotlin中的數組

    Kotlin數組支持泛型通過兩種實現方式:

    數組類型

    實現特性

    對應字節碼指令

    Java等效類型

    類集合語法數組

    泛型實現類似List,不具備協變性

    anewarray

    包裝類類型數組

    基本類型數組

    兼容Java基本數據類型

    newarray

    基本數據類型數組

    Kotlin通過IntArray等類封裝基本類型數組,反編譯顯示其字節碼同樣不包含泛型信息,證實Kotlin泛型基于類型擦除機制實現。

    4)、Kotlin為何支持創建泛型數組

    Kotlin雖采用類型擦除機制,但通過強制泛型類型聲明消除安全隱患。由于無需兼容歷史字節碼或源碼,集合與數組API設計均要求顯式指定泛型類型,此設計規避了Java中存在的類型安全問題。

    1.4、泛型類型保留到運行時

    1)、使用Class<T>

    <T> T create(Class<T> kind) {
    return new kind.newInstance();
    } // TODO catch
    

    通過Class<T>參數傳遞類型信息。該方案特點:

    • 支持反射創建實例
    • 局限性:
      • 反射效率低
      • 無法處理嵌套泛型(如List<String>.class非法)

    2)、通過子類把泛型類型具體化(reified)

    public class AppleBasket extends Basket<Apple>{
    ... // 這里Apple具體化
    }
    public class GenericsTypeToken<T> {
    public Type type = null;
    public GenericsTypeToken() {
    type =
    ((ParameterizedType)this.getClass().getGenericSuperclass())
    .getActualTypeArguments()[0];
    }
    }
    new GenericsTypeToken<Basket<Apple>>() {}.type;
    

    字節碼簽名保留泛型信息。實現步驟:

    • 繼承具體化泛型類
    • 通過getGenericSuperclass()獲取簽名屬性 - 解析Type接口獲取實際類型
    • Gson等庫采用類似TypeToken機制實現泛型反序列化。
    Type type = new TypeToken<List<User>>() {}.getType();
    List<User> list = new Gson().fromJson(userJson, userListType);

    1.5、匿名內部類使用的外部變量需要加final

    • 匿名內部類, 持有外部類的引用;
      • 以編譯器自動生成的成員變量的形式持有;
      • 通過編譯器自動生成的構造方法傳入。
      • 匿名內部類, 通過這個引用訪問外部類的成員變量和方法。
    • 匿名內部類, 訪問外部局部變量時, 其實是訪問自身的一個成員變量;
      • 這個成員變量, 是編譯器自動生成的(val$變量);
      • 這個成員變量, 由編譯器自動生成的構造方法初始化;
      • 為了保證這個成員變量和外部局部變量時刻保持一致性, 二者必須都是final的。

    2、Kotlin語言相關

    推薦閱讀:一文帶你快速掌握Kotlin核心技能

    3、設計模式

    設計模式:是前人通過試錯總結的最佳實踐,用于解決特定問題(如提高代碼復用性、可讀性、健壯性)。那我們遇到過哪些設計模式的使用案例呢?

    ①、模板方法模式

    • Android Activity生命周期:開發者通過重寫onCreate、onResume等方法響應狀態變更,無法干預狀態流轉邏輯。
    • 核心要點:
      • 父類定義算法框架,子類實現細節。
      • 決策權在高層模塊(如父類控制調用時機)。
      • 與策略模式區別:模板方法通過繼承封裝算法,策略模式通過組合封裝。

    ②、責任鏈模式

    責任鏈模式通過鏈式節點處理請求,經典案例有:

    • Android View事件分發:事件沿視圖層級傳遞直至被消費。
    • OkHttp攔截器:請求通過攔截器鏈逐層處理。

    責任鏈模式適用于多個處理者具備處理相同事件能力且需篩選最符合要求或優先級最高的場景。核心特征包括:

    • 職責差異化:責任鏈各節點具備不同職責
    • 順序依賴性:節點間存在明確先后順序
    • 擴展優勢:通過接口實現新責任并加入責任鏈即可完成功能擴展
    • 動態調整:支持運行時修改責任鏈節點構成

    ③、裝飾者模式

    裝飾者模式的核心在于動態擴展類的能力,通過組合而非繼承實現功能擴展。

    安卓平臺的ContextWrapper類采用裝飾者模式。通過包裝ContextImpl實現動態功能擴展,避免直接繼承帶來的局限性。

    ④、代理模式

    代理模式與裝飾者模式結構相似,均實現接口并持有接口引用。代理模式通過替身控制對象訪問,代理模式的要點包括遠程對象代理和虛擬代理。與裝飾者模式目的不同,前者控制訪問,后者擴展行為。

    典型場景:安卓框架層通過Binder跨進程實現代理模式。ActivityManager通過IActivityManager接口代理跨進程訪問。

    ⑤、Android中的其它設計模式

    安卓平臺常見設計模式包括:

    • 觀察者模式:廣播、Adapter的notifyDataSetChanged
    • 適配器模式:ListView的Adapter
    • 構建者模式:AlertDialog.Builder
    • 備忘模式:Activity的onSaveInstanceState
    • 迭代器模式:Cursor遍歷
    • 原型模式:Intent的clone方法
    • 享元模式:線程池、連接池
    • 命令模式:Handler消息循環

    OK,今天的內容就這么多了,下期再會!

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/bicheng/96428.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96428.shtml
    英文地址,請注明出處:http://en.pswp.cn/bicheng/96428.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    7、Matplotlib、Seaborn、Plotly數據可視化與探索性分析(探索性數據分析(EDA)方法論)

    學習目標&#xff1a;掌握數據可視化的原理和工具&#xff0c;培養通過圖表洞察數據規律的能力&#xff0c;建立數據驅動的分析思維數據可視化是數據科學的重要組成部分&#xff0c;它將抽象的數字轉化為直觀的圖形&#xff0c;讓我們能夠快速識別模式、趨勢和異常。從基礎的柱…

    Next系統學習(二)

    SSR生命周期與實現詳細解答 19. 如果不使用框架&#xff0c;如何從零用React/VueNode.js實現一個簡單的SSR應用? React Node.js SSR實現步驟&#xff1a; 項目結構搭建 /project/client - 客戶端代碼/server - 服務端代碼/shared - 共享代碼服務端基礎設置 // server/index…

    零代碼入侵:Kubernetes 部署時自動注入 kube-system UID 到 .NET 9 環境變量

    在現代化 .net9 應用部署階段&#xff0c;零代碼入侵模式&#xff0c;自動獲取 kubernetes 命名空間 kube-system 的 UID&#xff0c;并其作為變量配置到應用。 以下是幾種實現方式&#xff1a; 方法一&#xff1a;使用 InitContainer Downward API 您可以通過 Kubernetes 的 …

    基于Redis設計一個高可用的緩存

    本文為您介紹&#xff0c;如何逐步設計一個基于Redis的高可用緩存。 目錄 業務背景 步驟一&#xff1a;寫一個最簡單的緩存設計 存在的問題&#xff1a;大量冷數據占據Redis內存 解決思路&#xff1a;讓緩存自主釋放 步驟二&#xff1a;為緩存設置超時時間 存在的問題&a…

    從原理到實踐:LVS+Keepalived構建高可用負載均衡集群

    從原理到實踐&#xff1a;LVSKeepalived構建高可用負載均衡集群 文章目錄從原理到實踐&#xff1a;LVSKeepalived構建高可用負載均衡集群一、為什么需要LVSKeepalived&#xff1f;二、核心原理&#xff1a;Keepalived與VRRP協議1. VRRP的核心思想2. Keepalived的三大功能三、LV…

    iOS混淆工具實戰 在線教育直播類 App 的課程與互動安全防護

    近年來&#xff0c;在線教育直播類 App 已成為學生與培訓機構的重要工具。無論是 K12 教育、職業培訓&#xff0c;還是興趣學習&#xff0c;App 中承載的課程視頻、題庫與互動邏輯都是極高價值的內容資產。 然而&#xff0c;教育直播應用同樣面臨多重安全風險&#xff1a;課程視…

    第2節-過濾表中的行-BETWEEN

    摘要: 在本教程中&#xff0c;您將學習如何在 WHERE 子句中使用 PostgreSQL 的 BETWEEN 運算符來檢查某個值是否在兩個值之間。 PostgreSQL BETWEEN 運算符 BETWEEN運算符是一種比較運算符&#xff0c;如果某個值介于兩個值之間&#xff0c;則返回true。 以下是 BETWEEN 運算符…

    Windows 11 手動下載安裝配置 uv、配置國內源

    Windows 11 手動下載安裝配置 uv、配置國內源 本文對應的講解視頻鏈接&#xff1a;https://www.bilibili.com/video/BV1WnYTzZEpW 文章目錄Windows 11 手動下載安裝配置 uv、配置國內源1. 下載、安裝、配置 uv2. 參考信息重要聲明&#xff1a; uv 的安裝有很多種方式&#xff…

    平板熱點頻繁斷連?三步徹底解決

    平板反復斷開熱點連接是一個非常常見且令人煩惱的問題。這通常不是單一原因造成的&#xff0c;而是多種因素疊加的結果。 我們可以從熱點發射設備&#xff08;手機等&#xff09;、平板本身、以及環境因素三個方面來排查和解決。 一、 熱點發射端&#xff08;通常是手機&#x…

    Qt文件操作的學習(三)

    一、實現簡易文本編輯器 主要用到帶菜單欄的窗口&#xff0c;而非單一窗口。QT已經寫好相關操作&#xff0c;就不在重新造輪子了功能設計&#xff1a;新建文本文檔&#xff0c;打開文件&#xff0c;保存文件&#xff0c;另存為 這次不同于之前直接可以在控件上面右擊槽了&…

    ArcGIS學習-20 實戰-縣域水文分析

    水文分析任務提取區域內水流方向、匯流累積量、河網、流域、子流域前置操作環境更改加載數據檢查投影坐標系河網分析洼地填充限制默認為空&#xff0c;認為所有洼地都是需要填充的&#xff0c;這里更正一下Fill_DEM需要加上后綴.tif流向分析得到流量分析得到這里的黑色代表非河…

    本地 Docker 環境 Solr 配置 SSL 證書

    一、簡介 在本地開發環境中為 Solr 配置 SSL 證書,是提升開發與測試一致性的關鍵步驟。尤其是在涉及安全傳輸需求的場景中,本地環境的 HTTPS 配置能有效避免因環境差異導致的問題。本文將詳細介紹如何利用 Docker 容器,快速為 Solr 服務配置自簽名 SSL 證書,實現本地 HTTP…

    MacOS 運行CosyVoice

    CosyVoic主要特點&#xff1a;1、支持中文、英文、上海話、天津話、四川話等方言。語音非常自然。2、支持3秒語音零樣本克隆&#xff0c;效果非常好。3、克隆時間比較長&#xff08;取決于GPU性能&#xff0c;使用H20以滿足低延遲輸出&#xff09;&#xff0c;L4 克隆默認文本需…

    我不是掛王-用python實現燕雙鷹小游戲3

    在前兩個版本的更新后,越來越多內容,操作和運行也不方便,優化第三版本窗口可視化界面 本次版本更新使得可讀性和可操作性大幅度增加,前面2版本可分別參考 我不是掛王-用python實現燕雙鷹小游戲 和 我不是掛王-用python實現燕雙鷹小游戲2 一.燕雙鷹窗口可視化(燕雙鷹3.0) 新燕雙…

    裝飾(Decorator)模式可以在不修改對象外觀和功能的情況下添加或者刪除對象功能

    試題&#xff08;35&#xff09;、&#xff08;36&#xff09;某系統中的文本顯示類&#xff08;TextView&#xff09;和圖片顯示類&#xff08;PictureView&#xff09;都繼承了組件類&#xff08;Component&#xff09;&#xff0c;分別顯示文本和圖片內容&#xff0c;現需要…

    深度學習基礎概念【持續更新】

    1. 梯度消失如果網絡中某一層的激活函數&#xff08;如 sigmoid 或 tanh&#xff09;在輸入較大的情況下有很小的梯度&#xff08;比如接近零&#xff09;&#xff0c;那么當這些小的梯度通過多層反向傳播時&#xff0c;它們會逐漸變得更小。這意味著在深層網絡的前面幾層&…

    上下文工程:AI應用成功的關鍵架構與實踐指南

    在AI應用開發中&#xff0c;模型能力只決定性能上限&#xff0c;而上下文質量決定性能下限——上下文工程正是確保AI系統理解用戶意圖、生成準確響應的核心工程技術&#xff0c;已成為區分普通AI應用與卓越AI應用的關鍵因素。一、上下文工程&#xff1a;AI應用的新核心競爭力 1…

    數據傳輸優化-異步不阻塞處理增強首屏體驗

    背景&#xff1a;主 project 頁面中會將視頻存儲到云端后獲得 ID &#xff0c;然后用 ID 調用 后端API POST到數據庫后拿到掛載頁面URL&#xff0c;接著傳入視頻分享組件&#xff08;由于視頻分享子組件的目標是分享視頻掛載頁面&#xff0c;所以前置步驟不能少&#xff09;con…

    【芯片設計-信號完整性 SI 學習 1.0 -- SI 介紹】

    文章目錄一、SoC 設計驗證階段的 SI 測試主要工作舉例二、芯片 Bringup 階段的 SI 測試主要工作舉例三、SI-PI 聯合仿真主要內容舉例四、整體總結一、SoC 設計驗證階段的 SI 測試 在 前硅階段&#xff08;pre-silicon&#xff09;&#xff0c;設計團隊需要確保 SoC 與外設接口…

    C語言鏈表設計及應用

    鏈表鏈表節點設計鏈表項目鏈表中的傳址調用檢查申請空間鏈表尾插鏈表頭插鏈表尾部刪除鏈表頭部刪除鏈表的查找指定位置之前插入指定位置之后插入數據刪除指定位置&#xff08;節點&#xff09;數據刪除指定位置&#xff08;節點&#xff09;之后的數據鏈表的銷毀前面學習了順序…