3、Java的異常體系
https://www.jianshu.com/p/49d2c3975c56
4、Java中實現多態的機制是什麼?
多態就是指一個引用變量倒底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。
因爲在程序運行時才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實現上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態,這就是多態性。
特點:
- 指向子類的父類引用由於向上轉型了,它只能訪問父類中擁有的方法和屬性,而對於子類中存在而父類中不存在的方法,該引用是不能使用的,儘管是重載該方法。
- 若子類重寫了父類中的某些方法,在調用該些方法的時候,必定是使用子類中定義的這些方法(動態連接、動態調用)。
Java實現多態有三個必要條件:繼承、重寫、向上轉型。
調用的優先級方法,該優先級爲:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
多態的實現原理
對象方法的調用是依靠類信息裏的方法表實現的。
總體而言,當調用對象某個方法時,JVM查找該對象類的方法表以確定該方法的直接引用地址,有了地址後才真正調用該方法。
超類繼承父類的方法,如果不Overriding該方法,那麼調用時會指向父類的方法。如果Overrding該方法,那麼指向該類的代碼區。
但是超類會存有父類的方法表。
我們知道java程序運行時,類的相關信息放在方法區,在這些信息中有個叫方法表的區域,該表包含有該類型所定義的所有方法的信息和指向這些方法實際代碼的指針
當Bird、Cock、Parrot和CrazyParrot這四個類被加載到 Java 虛擬機之方法區後,方法區中就包含了這四個類的信息,下圖示例了各個類的方法表。
從圖我們可以看到Cock、Parrot和CrazyParrot的類信息方法表包含了繼承自Bird的方法。CrazyParrot的方法表包含了繼承自Parrot的方法。此外各個類也有自己的方法。
注意看,方法表條目指向的具體方法代碼區。對於多態Overriding的方法courtship(),雖然Cock、Parrot和CrazyParrot的方法表裏的courtship()條目所在位置是屬於繼承自Bird方法表的部分,但指向不同的方法代碼區了。
5、說說你對Java反射的理解
什麼是java的反射機制?
反射(Reflection)機制:其實就是程序在運行的時候可以獲取任意一個類的內部信息,也可以說是動態獲取吧。
那麼我們怎麼利用反射(Reflection)去獲取類的相關信息呢?
首先我們必須要了解什麼是靜態加載類,什麼是動態加載類?
靜態加載類:其實說的通俗一點的話,就是程序編譯的的過程,這就是靜態加載類。
動態加載類:其實說的就是程序運行的時候,可以說動態加載。
簡單一點的說法就是:編譯--------靜態 運行---------動態
我們在控制檯運行java程序的時候是不是要執行一下:javac *.java(其實這個時候會生成一個該類的.class文件) 然後再java *(這個時候其實運行加載的就是這個.class文件),而所謂的動態加載,就是繞過編譯,在調用的時候就運行。下面通過一個簡單的例子來說明一下:
比如我新建一個類:
- package com.mytest01;
- public class showObj {
- public void showObject(){
- Person p = new person();
- system.out.println(p);
- }
還沒有運行的時候在eclispe等軟件是不是會提示報錯?然後你在控制檯中編譯是不是不通過?說找不到這個Person這個類?
那麼我們稍微改一下代碼看看是否還會出錯:
package com.mytest01;
public class showObj {
public void showObject(){
Class p = person.class;
System.out.println(p);
}
class person{
}
}
看編譯的時候還會不會出錯?
下面我們再來談一下我們到底應該怎麼去獲取類的內部信息呢?
在獲取類的內部信息之前,我想說的是一點點面向對象的思想。首先什麼是對象?我們常說一個實體就是一個對象,那麼我們在想想java裏面我們新建的類是不是一個對象呢?你可能會有疑問?對象不就還是類的實例化嗎?爲什麼說類也是一個對象?其實也不難理解,因爲我們所有新建的類其實都是java裏面java.lang.Class的實例對象來的,新建一個類,其實就是實例化java.lang.Class類;
明白了這一點,我們就可以繼續的往下走了,下面我們就來談談怎麼去獲取一個類的內部信息:
第一步:獲取該類的類類型(這一步非常關鍵)
那麼我們怎麼去獲取呢:
其實很簡答,一共有三種方法:
1.利用Class c = Class.forName("")----------傳就來要獲取類的路徑,會出現異常。
2.利用Class c = A.class ---------------------A代表該類的類名
3.利用Class c = a.getClass();---------------a代表的就是該類的實例化對象,也就是 A a = new A();這一步
通過上面的方法我們就獲取了該類的一個實例對象,那麼我們怎麼調用類裏面的成員函數,成員變量呢?(注意都是public的)如果要訪問私有的要在你要獲取的變量後加上setAccessible(true);例如 Filed[] filed = c.getFields(); field.setAccessible(true);
其實還是很簡單:
1.c.getName()-------------------獲取該類的類名;返回String類型的值
2.c.getFileds()------------------------獲取該類的所有成員變量 c.getDeclaredFields()--------自己聲明的類的成員變量;
3.c.getType()---------------------------獲取該類的類型
4.c.getMethods()----------------------獲取所有的方法 c.getDeclaredMethod()-----------所有聲明過的方法。
.......
.....
..
還有很多可以去查閱官方的文檔。
那麼我們怎麼反向的去執行方法呢?
分爲三步:
第一:獲取類的;類類型
Class c = a.getClass();
第二步:獲取類的方法
Method m = c.getMethod("方法的名稱",參數的類類型new Class[]{...,.....});
第三部:傳入參數,利用invoke()函數
Object o = m.invoke(a(實例化對象),執行函數要傳進來的參數);
6、說說你對Java註解的理解
註解,也叫元數據。一種代碼級別的說明,在JDK1.5之後引入的特性,與類、接口、枚舉同一層次。可以聲明在包、類、字段、方法、局部變量、方法參數等前面,來對這些元素進行說明,註釋等。
作用分類:
1)編寫文檔:通過代碼裏的標識的元數據生成文檔【生成文檔doc文檔】
2)代碼分析:通過代碼裏的標識的元數據對代碼進行分析【使用反射】
3)編譯檢查:通過代碼裏的標識的元數據讓編譯器能過實現基本的編譯檢查【Override】
元註解:
java提供了四個元註解,所謂元註解就是負責註解其他註解。
1.@Target :規定註解所修飾的對象範圍。
1)ElementType.CONSTRUCTIR; 構造器聲明
2)ElementType.FIELD; 成員變量,對象,屬性(包括enum實例)
3)ElementType.LOCAL_VARIABLE; 局部變量聲明
4)ElementType.METHOD ; 方法聲明
5)ElementType.PACKAGE; 包聲明
6)ElementType.PARAMETER;參數聲明
7)ElementType.TYPE; 類、接口(包括註解類型)或enum聲明
2.@Retention : 表示註解的生命週期
1)RetentionPolicy.SOUREC: 在源文件中有效
2)RetentionPolicy.CLASS; 在class文件中有效
3)RetentionPolicy.RUNTIME;在運行時有效
3.@Inherited : 標記註解,主要說明了一種繼承性,意思是子類可以繼承父類中的該註解(注意:只有當被貼上@Inherited標籤的註解被用在類上的時候子類才能獲得這個註解)。
3.@Documented : 用於描述其它類型的annotation應該被作爲被標註的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。
7、java 控制反轉和依賴注入的理解
控制反轉(IOC)是Spring框架的核心思想,用我自己的話說,就是你要做一件事,別自己可勁new了,你就說你要幹啥,然後外包出去就好~
依賴注入(DI) 在我淺薄的想法中,就是通過接口的引用和構造方法的表達,將一些事情整好了反過來傳給需要用到的地方~
這樣做得好處:做到了單一職責,並且提高了複用性,解耦了之後,任你如何實現,使用接口的引用調用的方法,永遠不需要改變
舉一個栗子:
寫個接口,說咱們購物去~
public interface IShopping { void drive(); String Money(); }
在實現它兩下:有錢人購物,沒錢人購物 - -!這栗子舉的
public class RichMan implements IShopping{
@Override
public void drive() {
System.out.println("Drive By Benz");
}
@Override
public String Money() {
System.out.println("lot`s of money");
return "10000";
}
}
然後我們出去玩,順便shopping一下吧~
public class Play { private IShopping shoppingSomething;
//使用構造方法,將實現傳入 public Play(IShopping shoppingSomething){ this.shoppingSomething = shoppingSomething; } public void withgirlFriend(){ shoppingSomething.drive(); shoppingSomething.Money(); } }
將想用的實現方式,用容器注入進來,這裏就模擬下下怎麼注入:
public class Containner { public Play getShopping(){ return new Play(new RichMan()); } }
8、說一下泛型原理,並舉例說明
https://www.cnblogs.com/xunzhi/p/5683709.html
9、String爲什麼要設計成不可變的?
- 字符串常量池的需要
字符串常量池(String pool, String intern pool, String保留池) 是Java堆內存中一個特殊的存儲區域, 當創建一個String對象時,假如此字符串值已經存在於常量池中,則不會創建一個新的對象,而是引用已經存在的對象。
如下面的代碼所示,將會在堆內存中只創建一個實際String對象.
String s1 = "abcd";
String s2 = "abcd";
示意圖如下所示:
假若字符串對象允許改變,那麼將會導致各種邏輯錯誤,比如改變一個對象會影響到另一個獨立對象. 嚴格來說,這種常量池的思想,是一種優化手段.
請思考: 假若代碼如下所示,s1和s2還會指向同一個實際的String對象嗎?
String s1= "ab" + "cd";
String s2= "abc" + "d";
也許這個問題違反新手的直覺, 但是考慮到現代編譯器會進行常規的優化, 所以他們都會指向常量池中的同一個對象. 或者,你可以用 jd-gui 之類的工具查看一下編譯後的class文件.
- 允許String對象緩存HashCode
Java中String對象的哈希碼被頻繁地使用, 比如在hashMap 等容器中。
字符串不變性保證了hash碼的唯一性,因此可以放心地進行緩存.這也是一種性能優化手段,意味着不必每次都去計算新的哈希碼. 在String類的定義中有如下代碼:
private int hash;//用來緩存HashCode
- . 安全性
String被許多的Java類(庫)用來當做參數,例如 網絡連接地址URL,文件路徑path,還有反射機制所需要的String參數等, 假若String不是固定不變的,將會引起各種安全隱患。
假如有如下的代碼:
boolean connect(string s){
- if (!isSecure(s)) {
- throw new SecurityException();
- }
- // 如果在其他地方可以修改String,那麼此處就會引起各種預料不到的問題/錯誤
- causeProblem(s);
- }
10、Object類的equal和hashCode方法重寫,爲什麼?
https://blog.csdn.net/m0_37462976/article/details/77866572
(三) 數據結構
1、常用數據結構簡介
數據結構(也稱爲集合類)大致分類如下:
Map圖接口(包含HashMap和TreeMap);
Collection集合接口(包含List接口和Set接口):
List線性表接口(包含ArrayList和LinkedList);
Set集合接口(包含HashSet和TreeSet);
2、併發集合瞭解哪些?
非阻塞式列表對應的實現類:ConcurrentLinkedDeque
阻塞式列表對應的實現類:LinkedBlockingDeque
用於數據生成或者消費的阻塞式列表對應的實現類:LinkedTransferQueue
按優先級排序列表元素的阻塞式列表對應的實現類:PriorityBlockingQueue
帶有延遲列表元素的阻塞式列表對應的實現類:DelayQueue
非阻塞式列表可遍歷映射對應的餓實現類:ConcurrentSkipListMap
隨機數字對應的實現類:ThreadLockRandom
原子變量對應的實現類:AtomicLong和AtomicIntegerArray
3、列舉java的集合以及集合之間的繼承關係
集合類存放的都是對象的引用,而非對象本身,出於表達上的便利,我們稱集合中的對象就是指集合中對象的引用(reference)。集合類型主要有3種:set(集)、list(列表)和map(映射)。
Collection和Map最大的區別就是Collection存儲的是一組對象;Map是以“鍵值對”的形式對對象進行的管理。
Iterator是迭代器,Iterable是接口。很多類,像List、Set、HashMap不直接實現迭代器接口Iterator,而是去實現Iterable接口。
Collection是一個集合接口。它提供了對集合對象進行進本操作的通用接口方法。
Collections是一個工具類。內有多個對集合對象進行操作的靜態方法,不能實例化。
4、集合類以及集合框架
集合是一組複合元素的容器,用來存儲,檢索,控制聚合數據並提供它們之間的通信方法。
java的集合框架提供了表示和操控集合的統一架構。所有的集合框架都包含下面三個方面:
接口:即集合的抽象數據結構。接口允許我們獨立地操縱集合而不用考慮集合的具體實現
實現:即接口的具體實現類。從本質上來講,它們是可重用的數據結構
算法:即在實現了集合接口的對象上執行有用的計算,比如排序和搜索,的方法。算法是多態的:同名的方法可以被任何合適的接口實現類調用,從本質上來講,算法是可重用的功能
核心集合接口封裝了不同類型的集合,它們是java集合框架的基礎,形成了下圖所示的層級結構
從上圖中可以看到,Set是一種特殊的Collection,而SortedSet是一種特殊的Set……諸如此類。
需要注意,上圖中有兩個不同的樹,Map並不是Collection的子接口,而是一個獨立的接口
所有的集合接口都是泛化的。比如下面是Collection接口的聲明:
public interface Collection<E>...
“<E>”表示該接口是通用的。當我們聲明一個Collection接口時,最好指定該接口包含的對象類型,以便讓編譯器在編譯時檢驗輸入的對象是否正確,從而減少運行時拋出的錯誤。
對於接口中的方法,有很多是可選擇實現的,就是說,它的實現類可以實現該方法,也可以不實現,根據具體需要來決定
我們先來看一下核心的集合接口,對它們有一個整體的感性認識:
Collection接口:集合框架的根接口。它是集合類框架中最具一般性的頂層接口。Java平臺沒有提供任何該接口的直接具體實現類,但是提供了具有各種不同特性的子接口
Set接口:不允許包含重複值的集合
List接口:可索引的集合,可以包含重複值。使用該接口時我們通過索引對元素進行精準的插入和查找
Queue接口:該集合適用於組織一個隊列,隊列中的元素按照優先級進行處理。除了繼承自Collection接口的方法,該接口還提供了另外的插入、提取和檢驗方法。典型的隊列是符合“先進先出”(FIFO:First In,First Out)原則的,優先級隊列是一種例外,它按照元素的優先級順序排列元素。無論按照什麼原則排序,隊頭元素總是首先被檢出。每個Queue接口的實現類必須指定它的排序原則
Deque接口:與Queue的不同之處在於它是一個雙端隊列,在兩端都能插入和移除元素,它繼承並擴展了Queue接口
Map接口:提供了鍵值對(key/value)的映射關係的集合。關鍵字不能有重複值,每個關鍵字至多可映射一個值
SortedSet接口:以升序的原則維持着集合中的元素順序。
SortedMap接口:以關鍵字升序的原則維持着集合中的元素順序
以上接口的通用實現類(這裏的通用實現類一般是指適用於單線程環境下的實現類,在JDK中有針對多線程併發環境下的特殊實現類)總結如下
可以發現,LinkedList同時實現了List、Queue、Deque三個接口。
SortedSet接口和SortedMap接口沒有在上表中列出,在上面的層次結構圖中可以看到,它們分別是Set和Map的子接口,TreeSet和TreeMap就是它們的實現類
以上提到的所有通用實現類都支持爲null的元素(或者鍵/值),不過有的只能包含一個null,有的可以包含多個null;所有通用實現類都實現了Serializable,是可序列化的對象;所有通用實現類都提供了一個clone方法用於複製對象;所有通用實現類都是線程不安全的(即是不同步的);所有通用實現類都提供了”fail-fast”機制的迭代器
關於“fail-fast”機制,來看一個實例:
Map<String,String> map = new HashMap<String,String>();
map.put("first", "Jay");
map.put("second","Jack");
map.put("third", "Jim");
Iterator<String> it= map.keySet().iterator();
while(it.hasNext()){
System.out.println(map.get(it.next()));
if(map.containsKey("second")){
map.remove("second");
}
}
以上代碼試圖使用Iterator迭代Map裏的鍵值,如果鍵值爲“second”則刪除Map中的該元素。運行一下可以發現,執行刪除操作時會報java.util.ConcurrentModificationException異常,即便這是單線程。
Iterator 是工作在一個獨立的線程中,並且擁有一個 mutex 鎖。 Iterator 被創建之後會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往後移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出 java.util.ConcurrentModificationException 異常。
如果想要成功的執行刪除操作,就需要先對Iterator進行對應的刪除操作
Map<String,String> map = new HashMap<String,String>();
map.put("first","Jay");
map.put("second","Jack");
map.put("third","Jim");
Iterator<String> it= map.keySet().iterator();
while(it.hasNext()){
System.out.println(map.get(it.next()));
if(map.containsKey("second")){
it.remove(); //先對Iterator進行刪除
map.remove("second");
}
}
5、容器類介紹以及之間的區別
容器類估計很多人沒聽這個詞,Java容器主要可以劃分爲4個部分:List列表、Set集合、Map映射、工具類(Iterator迭代器、Enumeration枚舉類、Arrays和Collections)
Collection是List和Set兩個接口的基接口
List在Collection之上增加了"有序"
Set在Collection之上增加了"唯一"
ArrayList是實現List的類...所以他是有序的。它裏邊存放的元素在排列上存在一定的先後順序,是採用數組存放元素 。
List LinkedList採用的則是鏈表。
Collection和Map接口之間的主要區別在於:
Collection中存儲了一組對象,而Map存儲關鍵字/值對(在Map對象中,每一個關鍵字最多有一個關聯的值)。
Map:不能包括兩個相同的鍵,一個鍵最多能綁定一個值。null可以作爲鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的 值爲null。當get()方法返回null值時,即可以表示Map中沒有該鍵,也可以表示該鍵所對應的值爲null。因此,在Map中不能由get()方法來判斷Map中是否存在某個鍵,而應該用containsKey()方法來判斷。
繼承Map的類有:HashMap,HashTable
HashMap:Map的實現類,缺省情況下是非同步的,可以通過Map Collections.synchronizedMap(Map m)來達到線程同步
HashTable:Dictionary的子類,確省是線程同步的。不允許關鍵字或值爲null
6、List,Set,Map的區別
- list和set是繼承了collection接口,而map不是
- list可以存放有序重複元素
- set可以存放無序不重複元素
- map可以存放鍵值對
7、List和Map的實現方式以及存儲方式
List:
常用實現方式有:ArrayList和LinkedList
ArrayList 的存儲方式:數組,查詢快
LinkedList的存儲方式:鏈表,插入,刪除快
Set:
常用實現方式有:HashSet和TreeSet
HashSet的存儲方式:哈希碼算法,加入的對象需要實現hashcode()方法,快速查找元素
TreeSet的存儲方式:按序存放,想要有序就要實現Comparable接口
附加:
集合框架提供了2個實用類:collections(排序,複製、查找)和Arrays對數組進行(排序,複製、查找)
Map:
常用實現方式有:HashMap和TreeMap
HashMap的存儲方式:哈希碼算法,快速查找鍵值
TreeMap存儲方式:對鍵按序存放
8、HashMap的實現原理
HashMap基於hashing原理,我們通過put()和get()方法儲存和獲取對象。當我們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值對象。當獲取對象時,通過鍵對象的equals()方法找到正確的鍵值對,然後返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會儲存在鏈表的下一個節點中。 HashMap在每個鏈表節點中儲存鍵值對對象。
當兩個不同的鍵對象的hashcode相同時會發生什麼? 它們會儲存在同一個bucket位置的鏈表中。鍵對象的equals()方法用來找到鍵值對。
因爲HashMap的好處非常多,我曾經在電子商務的應用中使用HashMap作爲緩存。因爲金融領域非常多的運用Java,也出於性能的考慮,我們會經常用到HashMap和ConcurrentHashMap。
9、HashMap數據結構?
基本結構:
數組+單向鏈表
元素:
Node,包含key value Node(next)
基本限制
數組默認長度:1<<4 即 16
數組最大值 :1<<30
默認加載因子:0.75 ------ 數組容量*0.75 = 12 (使用大小觸發點:使用到12時做擴大數組容量的操作)
鏈表變形爲紅黑樹的觸發大小:8 -------- 注:變形目的是降低查找的時間複雜度。
紅黑樹變形爲鏈表的觸發大小:6
添加元素的方式
先存數組,如果重疊則往下存成鏈表
1.計算出在數組的位置
目的:得到0-15的某個值,方式:哈希算法,通過key的hashCode取數組大小的模-------key.hashCode()%數組大小=下標值(即數組位置)
源碼中的具體細節
1.如果爲空則resize() 初始化
2.根據hash進行運算,
3.node中的hash記錄
10、HashMap源碼理解
https://www.jianshu.com/p/d4fee00fe2f8
11、HashMap怎麼手寫實現?
https://www.jianshu.com/p/b638f19aeb64
12、ArrayMap和HashMap的對比
HashMap和ArrayMap各自的優勢
1.查找效率
HashMap因爲其根據hashcode的值直接算出index,所以其查找效率是隨着數組長度增大而增加的。
ArrayMap使用的是二分法查找,所以當數組長度每增加一倍時,就需要多進行一次判斷,效率下降。
所以對於Map數量比較大的情況下,推薦使用
2.擴容數量
HashMap初始值16個長度,每次擴容的時候,直接申請雙倍的數組空間。
ArrayMap每次擴容的時候,如果size長度大於8時申請size*1.5個長度,大於4小於8時申請8個,小於4時申請4個。
這樣比較ArrayMap其實是申請了更少的內存空間,但是擴容的頻率會更高。因此,如果當數據量比較大的時候,還是使用HashMap更合適,因爲其擴容的次數要比ArrayMap少很多。
3.擴容效率
HashMap每次擴容的時候時重新計算每個數組成員的位置,然後放到新的位置。
ArrayMap則是直接使用System.arraycopy。
所以效率上肯定是ArrayMap更佔優勢。
這裏需要說明一下,網上有一種傳聞說因爲ArrayMap使用System.arraycopy更省內存空間,這一點我真的沒有看出來。arraycopy也是把老的數組的對象一個一個的賦給新的數組。當然效率上肯定arraycopy更高,因爲是直接調用的c層的代碼。
4.內存耗費
以ArrayMap採用了一種獨特的方式,能夠重複的利用因爲數據擴容而遺留下來的數組空間,方便下一個ArrayMap的使用。而HashMap沒有這種設計。
由於ArrayMap只緩存了長度是4和8的時候,所以如果頻繁的使用到Map,而且數據量都比較小的時候,ArrayMap無疑是相當的節省內存的。
5.總結
綜上所述,
數據量比較小,並且需要頻繁的使用Map存儲數據的時候,推薦使用ArrayMap。
而數據量比較大的時候,則推薦使用HashMap。
13、HashMap和HashTable的區別
HashMap不是線程安全的,效率高一點、方法不是Synchronize的要提供外同步,有containsvalue和containsKey方法。
hashtable是,線程安全,不允許有null的鍵和值,效率稍低,方法是是Synchronize的。有contains方法方法。Hashtable 繼承於Dictionary 類
https://www.cnblogs.com/williamjie/p/9099141.html
14、HashMap與HashSet的區別
HashSet:
HashSet實現了Set接口,它不允許集合中出現重複元素。當我們提到HashSet時,第一件事就是在將對象存儲在
HashSet之前,要確保重寫hashCode()方法和equals()方法,這樣才能比較對象的值是否相等,確保集合中沒有
儲存相同的對象。如果不重寫上述兩個方法,那麼將使用下面方法默認實現:
public boolean add(Object obj)方法用在Set添加元素時,如果元素值重複時返回 "false",如果添加成功則返回"true"
HashMap:
HashMap實現了Map接口,Map接口對鍵值對進行映射。Map中不允許出現重複的鍵(Key)。Map接口有兩個基本的實現
TreeMap和HashMap。TreeMap保存了對象的排列次序,而HashMap不能。HashMap可以有空的鍵值對(Key(null)-Value(null))
HashMap是非線程安全的(非Synchronize),要想實現線程安全,那麼需要調用collections類的靜態方法synchronizeMap()實現。
public Object put(Object Key,Object value)方法用來將元素添加到map中。
HashSet與HashMap的區別:
15、ArrayList和LinkedList的區別,以及應用場景
區別
ArrayList底層是用數組實現的,可以認爲ArrayList是一個可改變大小的數組。隨着越來越多的元素被添加到ArrayList中,其規模是動態增加的。
LinkedList底層是通過雙向鏈表實現的, LinkedList和ArrayList相比,增刪的速度較快。但是查詢和修改值的速度較慢。同時LinkedList還實現了Queue接口,所以他還提供了offer(),peek(), poll()等方法。
在內存中這兩者也是有區別的,因爲底層分別用數組和鏈表實現的,所以在內存中ArrayList是連續的,而linkedList在底層中是用鏈表實現的所以在內存中可以不是連續的內存。
使用場景
LinkedList更適合大量的循環,並且循環時進行插入或者刪除。
ArrayList更適合大量的存取和刪除操作