不能。在Java中,只要是被定義爲final的類,也能夠說是被final修飾的類,就是不能被繼承的。html
簡單的區別: 1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。 (LinkedList是雙向鏈表,有next也有previous) 2.對於隨機訪問get和set,ArrayList以爲優於LinkedList,由於LinkedList要移動指針。 3.對於新增和刪除操做add和remove,LinedList比較佔優點,由於ArrayList要移動數據。java
深度的區別: 1.對ArrayList和LinkedList而言,在列表末尾增長一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增長一項,指向所添加的元素,偶爾可能會致使對數組從新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。react
2.在ArrayList的中間插入或刪除一個元素意味着這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。程序員
3.LinkedList不支持高效的隨機元素訪問。spring
4.ArrayList的空間浪費主要體如今在list列表的結尾預留必定的容量空間,而LinkedList的空間花費則體如今它的每個元素都須要消耗至關的空間數據庫
問題:好比父類靜態數據,構造函數,字段,子類靜態數據,構造函數,字 段,當new的時候,他們的執行順序。api
答案: 類加載器實例化時進行的操做步驟(加載–>鏈接->初始化)。 父類靜態變量、 父類靜態代碼塊、 子類靜態變量、 子類靜態代碼塊、 父類非靜態變量(父類實例成員變量)、 父類構造函數、 子類非靜態變量(子類實例成員變量)、 子類構造函數。數組
問題:好比HashMap是線程安全的嗎,併發下使用的Map是什麼,他們 內部原理分別是什麼,好比存儲方式,hashcode,擴容,默認容量等。 答案: 不安全,併發下使用ConcurrentHashMap。安全
緣由:經過 JDK 的源碼和官方文檔看來, 他們認爲的棄用分段鎖的緣由由如下幾點: 一、加入多個分段鎖浪費內存空間。 二、生產環境中, map 在放入時競爭同一個鎖的機率很是小,分段鎖反而會形成更新等操做的長時間等待。 三、爲了提升 GC 的效率性能優化
既然棄用了分段鎖, 那麼必定由新的線程安全方案, 咱們來看看源碼是怎麼解決線程安全的呢?CAS
首先經過 hash 找到對應鏈表事後, 查看是不是第一個object, 若是是, 直接用cas原則插入,無需加鎖,而後若是不是鏈表第一個object, 則直接用鏈表第一個object加鎖,這裏加的鎖是synchronized,雖然效率不如 ReentrantLock, 但節約了空間,這裏會一直用第一個object爲鎖, 直到從新計算map大小, 好比擴容或者操做了第一個object爲止。
能夠從下面幾個方面講述: 鎖的粒度 首先鎖的粒度並無變粗,甚至變得更細了。每當擴容一次,ConcurrentHashMap的併發度就擴大一倍。 Hash衝突 JDK1.7中,ConcurrentHashMap從過二次hash的方式(Segment -> HashEntry)可以快速的找到查找的元素。在1.8中經過鏈表加紅黑樹的形式彌補了put、get時的性能差距。 擴容 JDK1.8中,在ConcurrentHashmap進行擴容時,其餘線程能夠經過檢測數組中的節點決定是否對這條鏈表(紅黑樹)進行擴容,減少了擴容的粒度,提升了擴容的效率。
爲何是synchronized,而不是可重入鎖
Hashmap和Hashtable 都不是有序的。 TreeMap和LinkedHashmap都是有序的。(TreeMap默認是key升序,LinkedHashmap默認是數據插入順序) TreeMap是基於比較器Comparator來實現有序的。 LinkedHashmap是基於鏈表來實現數據插入有序的。
區別: 一、抽象類和接口都不能直接實例化,若是要實例化,抽象類變量必須指向實現全部抽象方法的子類對象,接口變量必須指向實現全部接口方法的類對象。 二、抽象類要被子類繼承,接口要被類實現。 三、接口只能作方法申明,抽象類中能夠作方法申明,也能夠作方法實現 四、接口裏定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量。 五、抽象類裏的抽象方法必須所有被子類所實現,若是子類不能所有實現父類抽象方法,那麼該子類只能是抽象類。一樣,一個實現接口的時候,如不能所有實現接口方法,那麼該類也只能爲抽象類。 六、抽象方法只能申明,不能實現。abstract void abc();不能寫成abstract void abc(){}。 七、抽象類裏能夠沒有抽象方法 八、若是一個類裏有抽象方法,那麼這個類只能是抽象類 九、抽象方法要被實現,因此不能是靜態的,也不能是私有的。 十、接口可繼承接口,並可多繼承接口,但類只能單根繼承。
類不能繼承多個類 接口能夠繼承多個接口 類能夠實現多個接口
繼承 指的是一個類繼承另外的一個類的功能,並能夠增長它本身的新功能的能力,繼承是類與類或者接口與接口之間最多見的關係;在Java中此類關係經過關鍵字extends明確標識。
聚合
聚合體現的是總體與部分、擁有的關係,此時總體與部分之間是可分離的,他們能夠具備各自的生命週期;好比計算機與CPU、公司與員工的關係等;
各IO的區別:
reactor是什麼?
//建立Class對象的方式一:(對象.getClass()),獲取類中的字節碼文件
Class class1 = p1.getClass();
//建立Class對象的方式二:(類.class:須要輸入一個明確的類,任意一個類型都有一個靜態的class屬性)
Class class3 = Person.class;
//建立Class對象的方式三:(forName():傳入時只須要以字符串的方式傳入便可)
//經過Class類的一個forName(String className)靜態方法返回一個Class對象,className必須是全路徑名稱;
//Class.forName()有異常:ClassNotFoundException
Class class4 = Class.forName("cn.xbmchina.Person");
複製代碼
Class.forName(className)方法,內部實際調用的方法是 Class.forName(className,true,classloader); 第2個boolean參數表示類是否須要初始化, Class.forName(className)默認是須要初始化。 一旦初始化,就會觸發目標對象的 static塊代碼執行,static參數也也會被再次初始化。 ClassLoader.loadClass(className)方法,內部實際調用的方法是 ClassLoader.loadClass(className,false); 第2個 boolean參數,表示目標對象是否進行連接,false表示不進行連接,由上面介紹能夠, 不進行連接意味着不進行包括初始化等一些列步驟,那麼靜態塊和靜態對象就不會獲得執行
原理區別:
java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理。
一、若是目標對象實現了接口,默認狀況下會採用JDK的動態代理實現AOP 二、若是目標對象實現了接口,能夠強制使用CGLIB實現AOP
三、若是目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
如何強制使用CGLIB實現AOP? (1)添加CGLIB庫,SPRING_HOME/cglib/*.jar (2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK動態代理和CGLIB字節碼生成的區別? (1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類 (2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 由於是繼承,因此該類或方法最好不要聲明成final
一、被final修飾的類不能夠被繼承 二、被final修飾的方法不能夠被重寫 三、被final修飾的變量不能夠被改變(切記不可變的是變量的引用而非引用指向對象的內容。) 四、被final修飾的方法,JVM會嘗試爲之尋求內聯,這對於提高Java的效率是很是重要的。所以,假如能肯定方法不會被繼承,那麼儘可能將方法定義爲final的,具體參見運行期優化技術的方法內聯部分 五、被final修飾的常量,在編譯階段會存入調用類的常量池中,具體參見類加載機制最後部分和Java內存區域
1 餓漢式
public class EagerSingleton {
static {
System.out.println("EagerSingleton 被加載");
}
//私有化構造方法,限制直接構造,只能調用 getInstance() 方法獲取單例對象
private EagerSingleton(){}
private static final EagerSingleton eagerSingleton=new EagerSingleton(); // 私有化靜態 final成員,類加載直接生成單例對象,比較佔用內存
public static EagerSingleton getInstance(){ //提供對外的公共api獲取單例對象
return eagerSingleton;
}
}
複製代碼
總結:餓漢式單例的特色:餓漢式在類建立的同時就實例化一個靜態對象出來,無論以後會不會使用這個單例,都會佔據必定的內存,可是相應的,在第一次調用時速度也會更快,由於其資源已經初始化完成。
2 懶漢式
public class LazySingleton {
static {
System.out.println("LazySingleton 被加載");
}
private LazySingleton(){} //私有化構造方法,限制直接構造,只能調用 getInstance() 方法獲取單例對象
private static LazySingleton lazySingleton=null;//靜態域初始化爲null,爲的是須要時再建立,避免像餓漢式那樣佔用內存
public static LazySingleton getInstance(){//提供對外的公共api獲取單例對象
if(lazySingleton==null){
synchronized (LazySingleton.class){ //在getInstance中作了兩次null檢查,確保了只有第一次調用單例的時候纔會作同步,這樣也是線程安全的,同時避免了每次都同步的性能損耗
if(lazySingleton==null){
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
複製代碼
總結:有同步鎖的性能消耗
3 靜態內部類實現
public class IoDHSingleton {
static {
System.out.println("IoDHSingleton 被加載");
}
private IoDHSingleton(){} //私有化構造方法,限制直接構造,只能調用 getInstance() 方法獲取單例對象
public static IoDHSingleton getInstance(){//提供對外的公共api獲取單例對象
//當getInstance方法第一次被調用的時候,它第一次讀取HolderClass.ioDHSingleton,內部類HolderClass類獲得初始化;
//而這個類在裝載並被初始化的時候,會初始化它的靜態域,從而創ioDHSingleton 的實例,因爲是靜態的域,所以只會在虛擬機裝載類的時候初始化一次,並由虛擬機來保證它的線程安全性。
return HolderClass.ioDHSingleton;
}
private static class HolderClass{
static {
System.out.println("HolderClass 被加載");
}
private static IoDHSingleton ioDHSingleton = new IoDHSingleton();
}
// 防止反序列化獲取多個對象的漏洞
private Object readResolve() throws ObjectStreamException {
return HolderClass.ioDHSingleton;
}
}
複製代碼
這個模式的優點在於,getInstance方法並無被同步,而且只是執行一個域的訪問,所以延遲初始化並無增長任何訪問成本。
考慮反射: 因爲在調用 SingletonHolder.instance 的時候,纔會對單例進行初始化,並且經過反射,是不能從外部類獲取內部類的屬性的。 因此這種形式,很好的避免了反射入侵。 考慮多線程: 因爲靜態內部類的特性,只有在其被第一次引用的時候纔會被加載,因此能夠保證其線程安全性。 總結: 優點:兼顧了懶漢模式的內存優化(使用時才初始化)以及餓漢模式的安全性(不會被反射入侵)。 劣勢:須要兩個類去作到這一點,雖然不會建立靜態內部類的對象,可是其 Class 對象仍是會被建立,並且是屬於永久帶的對象。
訪問修飾符,主要標示修飾塊的做用域,方便隔離防禦。
public: Java語言中訪問限制最寬的修飾符,通常稱之爲「公共的」。被其修飾的類、屬性以及方法不只能夠跨類訪問,並且容許跨包(package)訪問。
private: Java語言中對訪問權限限制的最窄的修飾符,通常稱之爲「私有的」。被其修飾的類、屬性以及方法只能被該類的對象訪問,其子類不能訪問,更不能容許跨包訪問。
protect: 介於public 和 private 之間的一種訪問修飾符,通常稱之爲「保護形」。被其修飾的類、屬性以及方法只能被類自己的方法及子類訪問,即便子類在不一樣的包中也能夠訪問。
default:即不加任何訪問修飾符,一般稱爲「默認訪問模式「。該模式下,只容許在同一個包中進行訪問。
淺拷貝(Shallow Copy):
①對於數據類型是基本數據類型的成員變量,淺拷貝會直接進行值傳遞,也就是將該屬性值複製一份給新的對象。由於是兩份不一樣的數據,因此對其中一個對象的該成員變量值進行修改,不會影響另外一個對象拷貝獲得的數據。 ②對於數據類型是引用數據類型的成員變量,好比說成員變量是某個數組、某個類的對象等,那麼淺拷貝會進行引用傳遞,也就是隻是將該成員變量的引用值(內存地址)複製一份給新的對象。由於實際上兩個對象的該成員變量都指向同一個實例。在這種狀況下,在一個對象中修改該成員變量會影響到另外一個對象的該成員變量值。
深拷貝:
首先介紹對象圖的概念。設想一下,一個類有一個對象,其成員變量中又有一個對象,該對象指向另外一個對象,另外一個對象又指向另外一個對象,直到一個肯定的實例。這就造成了對象圖。那麼,對於深拷貝來講,不只要複製對象的全部基本數據類型的成員變量值,還要爲全部引用數據類型的成員變量申請存儲空間,並複製每一個引用數據類型成員變量所引用的對象,直到該對象可達的全部對象。也就是說,對象進行深拷貝要對整個對象圖進行拷貝!
簡單地說,深拷貝對引用數據類型的成員變量的對象圖中全部的對象都開闢了內存空間;而淺拷貝只是傳遞地址指向,新的對象並無對引用數據類型建立內存空間。
數組和鏈表的區別: 一、從邏輯結構角度來看: 數組必須事先定義固定的長度(元素個數),不能適應數據動態地增減的狀況。當數據增長時,可能超出原先定義的元素個數;當數據減小時,形成內存浪費。 鏈表動態地進行存儲分配,能夠適應數據動態地增減的狀況,且能夠方便地插入、刪除數據項。(數組中插入、刪除數據項時,須要移動其它數據項) 二、數組元素在棧區,鏈表元素在堆區; 三、從內存存儲角度來看: (靜態)數組從棧中分配空間, 對於程序員方便快速,但自由度小。 鏈表從堆中分配空間, 自由度大但申請管理比較麻煩。 數組利用下標定位,時間複雜度爲O(1),鏈表定位元素時間複雜度O(n); 數組插入或刪除元素的時間複雜度O(n),鏈表的時間複雜度O(1)。
對於equals()與hashcode(),比較通用的規則: ①兩個obj,若是equals()相等,hashCode()必定相等 ②兩個obj,若是hashCode()相等,equals()不必定相等
面向對象的轉型只會發生在具備繼承關係的父子類中(接口也是繼承的一種) 向上轉型:其核心目的在於參數的統一上,根本不須要強制類型轉換。 向下轉型:是爲了操做子類定義的特殊功能,須要強制類型轉換,但是如今存在的問題是:向下轉型實際上是一種很是不安全的操做,覺得編譯的時候,程序不會報錯,而在運行的時候會報錯,這就是傳說中的—迷之報錯。
不過呢,在JDK1.5以後,新增長了泛型的技術,這就將上述向下轉型的問題消滅在了萌芽之中。 泛型的核心意義在於:類在進行定義的時候可使用一個標記,此標記就表示類中屬性或者方法以及參數的類型,標記在使用的時候,纔會去動態的設置類型。
HashSet 的內部採用 HashMap來實現。因爲 Map 須要 key 和 value,因此HashSet中全部 key 的都有一個默認 value。相似於 HashMap,HashSet 不容許重複的 key,只容許有一個null key,意思就是 HashSet 中只容許存儲一個 null 對象。
什麼是序列化? 序列化:把對象轉換爲字節序列的過程稱爲對象的序列化。 反序列化:把字節序列恢復爲對象的過程稱爲對象的反序列化
什麼狀況下須要序列化? 當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候; 當你想用套接字在網絡上傳送對象的時候; 當你想經過RMI傳輸對象的時候;
如何實現序列化? 實現Serializable接口便可
注意事項: transient 修飾的屬性,是不會被序列化的 靜態static的屬性,他不序列化。 實現這個Serializable 接口的時候,必定要給這個 serialVersionUID 賦值
關於 serialVersionUID 的描述: 序列化運行時使用一個稱爲 serialVersionUID 的版本號與每一個可序列化類相關聯,該序列號在反序列化過程當中用於驗證序列化對象的發送者和接收者是否爲該對象加載了與序列化兼容的類。若是接收者加載的該對象的類的 serialVersionUID 與對應的發送者的類的版本號不一樣,則反序列化將會致使 InvalidClassException。可序列化類能夠經過聲明名爲 「serialVersionUID」 的字段(該字段必須是靜態 (static)、最終 (final) 的 long 型字段)顯式聲明其本身的 serialVersionUID