1. 程式人生 > 程式設計 >Java基礎知識

Java基礎知識

1、JAVA中的幾種基本資料型別是什麼,各自佔用多少位元組。

2、String類能被繼承嗎,為什麼

不能。在Java中,只要是被定義為final的類,也可以說是被final修飾的類,就是不能被繼承的。

3、String,Stringbuffer,StringBuilder的區別。

4、ArrayList和LinkedList有什麼區別。

簡單的區別: 1.ArrayList是實現了基於動態陣列的資料結構,LinkedList基於連結串列的資料結構。 (LinkedList是雙向連結串列,有next也有previous) 2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指標。 3.對於新增和刪除操作add和remove,LinedList比較佔優勢,因為ArrayList要行動資料。

深度的區別: 1.對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部陣列中增加一項,指向所新增的元素,偶爾可能會導致對陣列重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry物件。

2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。

3.LinkedList不支援高效的隨機元素訪問。

4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間

5、講講類的例項化順序。

問題:比如父類靜態資料,建構函式,欄位,子類靜態資料,建構函式,字 段,當new的時候,他們的執行順序。

答案: 類載入器例項化時進行的操作步驟(載入–>連線->初始化)。 父類靜態變數、 父類靜態程式碼塊、 子類靜態變數、 子類靜態程式碼塊、 父類非靜態變數(父類例項成員變數)、 父類建構函式、 子類非靜態變數(子類例項成員變數)、 子類建構函式。

6、用過哪些Map類,都有什麼區別。

問題:比如HashMap是執行緒安全的嗎,併發下使用的Map是什麼,他們 內部原理分別是什麼,比如儲存方式,hashcode,擴容,預設容量等。 答案: 不安全,併發下使用ConcurrentHashMap。

7、JAVA8的ConcurrentHashMap為什麼放棄了分段鎖?

原因:通過 JDK 的原始碼和官方檔案看來, 他們認為的棄用分段鎖的原因由以下幾點: 1、加入多個分段鎖浪費記憶體空間。 2、生產環境中, map 在放入時競爭同一個鎖的概率非常小,分段鎖反而會造成更新等操作的長時間等待。 3、為了提高 GC 的效率

既然棄用了分段鎖, 那麼一定由新的執行緒安全方案, 我們來看看原始碼是怎麼解決執行緒安全的呢?CAS

首先通過 hash 找到對應連結串列過後, 檢視是否是第一個object, 如果是, 直接用cas原則插入,無需加鎖,然後如果不是連結串列第一個object, 則直接用連結串列第一個object加鎖,這裡加的鎖是synchronized,雖然效率不如 ReentrantLock, 但節約了空間,這裡會一直用第一個object為鎖, 直到重新計算map大小, 比如擴容或者操作了第一個object為止。

8、ConcurrentHashMap(JDK1.8)為什麼要使用synchronized而不是如ReentranLock這樣的可重入鎖?

可以從下面幾個方面講述: 鎖的粒度 首先鎖的粒度並沒有變粗,甚至變得更細了。每當擴容一次,ConcurrentHashMap的併發度就擴大一倍。 Hash衝突 JDK1.7中,ConcurrentHashMap從過二次hash的方式(Segment -> HashEntry)能夠快速的找到查詢的元素。在1.8中通過連結串列加紅黑樹的形式彌補了put、get時的效能差距。 擴容 JDK1.8中,在ConcurrentHashmap進行擴容時,其他執行緒可以通過檢測陣列中的節點決定是否對這條連結串列(紅黑樹)進行擴容,減小了擴容的粒度,提高了擴容的效率。

為什麼是synchronized,而不是可重入鎖

  1. 減少記憶體開銷 假設使用可重入鎖來獲得同步支援,那麼每個節點都需要通過繼承AQS來獲得同步支援。但並不是每個節點都需要獲得同步支援的,只有連結串列的頭節點(紅黑樹的根節點)需要同步,這無疑帶來了巨大記憶體浪費。
  2. 獲得JVM的支援 可重入鎖畢竟是API這個級別的,後續的效能優化空間很小。 synchronized則是JVM直接支援的,JVM能夠在執行時作出相應的優化措施:鎖粗化、鎖消除、鎖自旋等等。這就使得synchronized能夠隨著JDK版本的升級而不改動程式碼的前提下獲得效能上的提升。
9、有沒有有順序的Map實現類,如果有,他們是怎麼保證有序的。

Hashmap和Hashtable 都不是有序的。 TreeMap和LinkedHashmap都是有序的。(TreeMap預設是key升序,LinkedHashmap預設是資料插入順序) TreeMap是基於比較器Comparator來實現有序的。 LinkedHashmap是基於連結串列來實現資料插入有序的。

www.iteye.com/blog/uule-1…

10、抽象類和介面的區別,類可以繼承多個類麼,介面可以繼承多個介面麼,類可以實現多個介面 麼。

區別: 1、抽象類和介面都不能直接例項化,如果要例項化,抽象類變數必須指向實現所有抽象方法的子類物件,介面變數必須指向實現所有介面方法的類物件。 2、抽象類要被子類繼承,介面要被類實現。 3、介面只能做方法申明,抽象類中可以做方法申明,也可以做方法實現 4、介面裡定義的變數只能是公共的靜態的常量,抽象類中的變數是普通變數。 5、抽象類裡的抽象方法必須全部被子類所實現,如果子類不能全部實現父類抽象方法,那麼該子類只能是抽象類。同樣,一個實現介面的時候,如不能全部實現介面方法,那麼該類也只能為抽象類。 6、抽象方法只能申明,不能實現。abstract void abc();不能寫成abstract void abc(){}。 7、抽象類裡可以沒有抽象方法 8、如果一個類裡有抽象方法,那麼這個類只能是抽象類 9、抽象方法要被實現,所以不能是靜態的,也不能是私有的。 10、介面可繼承介面,並可多繼承介面,但類只能單根繼承。

類不能繼承多個類 介面可以繼承多個介面 類可以實現多個介面

11、繼承和聚合的區別在哪。

繼承 指的是一個類繼承另外的一個類的功能,並可以增加它自己的新功能的能力,繼承是類與類或者介面與介面之間最常見的關係;在Java中此類關係通過關鍵字extends明確標識。

聚合

聚合體現的是整體與部分、擁有的關係,此時整體與部分之間是可分離的,他們可以具有各自的生命週期;比如計算機與CPU、公司與員工的關係等;

12、IO模型有哪些,講講你理解的nio ,他和bio,aio的區別是啥,談談reactor模型。

各IO的區別:

reactor是什麼?

  1. 事件驅動
  2. 可以處理一個或多個輸入源
  3. 通過Service Handle同步的將輸入事件採用多路複用分發給相應的Request Handler(一個或多個)處理

13、反射的原理,反射建立類例項的三種方式是什麼。
//建立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");
        
複製程式碼

blog.csdn.net/LianXu3344/…

14、反射中,Class.forName和ClassLoader區別 。

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表示不進行連結,由上面介紹可以, 不進行連結意味著不進行包括初始化等一些列步驟,那麼靜態塊和靜態物件就不會得到執行

www.cnblogs.com/zabulon/p/5…

15、描述動態代理的幾種實現方式,分別說出相應的優缺點。

原理區別:

java動態代理是利用反射機制生成一個實現代理介面的匿名類,在呼叫具體方法前呼叫InvokeHandler來處理。

而cglib動態代理是利用asm開源包,對代理物件類的class檔案載入進來,通過修改其位元組碼生成子類來處理。

1、如果目標物件實現了介面,預設情況下會採用JDK的動態代理實現AOP  2、如果目標物件實現了介面,可以強制使用CGLIB實現AOP

3、如果目標物件沒有實現了介面,必須採用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

blog.csdn.net/qq_23000805…

16、final的用途。

1、被final修飾的類不可以被繼承 2、被final修飾的方法不可以被重寫 3、被final修飾的變數不可以被改變(切記不可變的是變數的引用而非引用指向物件的內容。) 4、被final修飾的方法,JVM會嘗試為之尋求內聯,這對於提升Java的效率是非常重要的。因此,假如能確定方法不會被繼承,那麼儘量將方法定義為final的,具體參見執行期優化技術的方法內聯部分 5、被final修飾的常量,在編譯階段會存入呼叫類的常量池中,具體參見類載入機制最後部分和Java記憶體區域

www.cnblogs.com/swisszhang/…

17、寫出三種單例模式實現 。

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 物件還是會被建立,而且是屬於永久帶的物件。

www.cnblogs.com/ngy0217/p/9…

18、如何在父類中為子類自動完成所有的hashcode和equals實現?這麼做有何優劣。

www.iteye.com/blog/java-m…

19、請結合OO設計理念,談談訪問修飾符public、private、protected、default在應用設計中的作用。

訪問修飾符,主要標示修飾塊的作用域,方便隔離防護。

public: Java語言中訪問限制最寬的修飾符,一般稱之為“公共的”。被其修飾的類、屬性以及方法不僅可以跨類訪問,而且允許跨包(package)訪問。

private: Java語言中對訪問許可權限制的最窄的修飾符,一般稱之為“私有的”。被其修飾的類、屬性以及方法只能被該類的物件訪問,其子類不能訪問,更不能允許跨包訪問

protect: 介於public 和 private 之間的一種訪問修飾符,一般稱之為“保護形”。被其修飾的類、屬性以及方法只能被類本身的方法及子類訪問,即使子類在不同的包中也可以訪問。

default:即不加任何訪問修飾符,通常稱為“預設訪問模式“。該模式下,只允許在同一個包中進行訪問。

20、深拷貝和淺拷貝區別。

淺拷貝(Shallow Copy):

①對於資料型別是基本資料型別的成員變數,淺拷貝會直接進行值傳遞,也就是將該屬性值複製一份給新的物件。因為是兩份不同的資料,所以對其中一個物件的該成員變數值進行修改,不會影響另一個物件拷貝得到的資料。 ②對於資料型別是引用資料型別的成員變數,比如說成員變數是某個陣列、某個類的物件等,那麼淺拷貝會進行引用傳遞,也就是隻是將該成員變數的引用值(記憶體地址)複製一份給新的物件。因為實際上兩個物件的該成員變數都指向同一個例項。在這種情況下,在一個物件中修改該成員變數會影響到另一個物件的該成員變數值。

深拷貝:

首先介紹物件圖的概念。設想一下,一個類有一個物件,其成員變數中又有一個物件,該物件指向另一個物件,另一個物件又指向另一個物件,直到一個確定的例項。這就形成了物件圖。那麼,對於深拷貝來說,不僅要複製物件的所有基本資料型別的成員變數值,還要為所有引用資料型別的成員變數申請儲存空間,並複製每個引用資料型別成員變數所引用的物件,直到該物件可達的所有物件。也就是說,物件進行深拷貝要對整個物件圖進行拷貝!

簡單地說,深拷貝對引用資料型別的成員變數的物件圖中所有的物件都開闢了記憶體空間;而淺拷貝只是傳遞地址指向,新的物件並沒有對引用資料型別建立記憶體空間。

www.cnblogs.com/shakinghead…

21、陣列和連結串列資料結構描述,各自的時間複雜度。

陣列和連結串列的區別: 1、從邏輯結構角度來看: 陣列必須事先定義固定的長度(元素個數),不能適應資料動態地增減的情況。當資料增加時,可能超出原先定義的元素個數;當資料減少時,造成記憶體浪費。 連結串列動態地進行儲存分配,可以適應資料動態地增減的情況,且可以方便地插入、刪除資料項。(陣列中插入、刪除資料項時,需要移動其它資料項) 2、陣列元素在棧區,連結串列元素在堆區; 3、從記憶體儲存角度來看: (靜態)陣列從棧中分配空間,對於程式設計師方便快速,但自由度小。 連結串列從堆中分配空間,自由度大但申請管理比較麻煩。 陣列利用下標定位,時間複雜度為O(1),連結串列定位元素時間複雜度O(n); 陣列插入或刪除元素的時間複雜度O(n),連結串列的時間複雜度O(1)。

22、error和exception的區別,CheckedException,RuntimeException的區別。

23、在自己的程式碼中,如果建立一個java.lang.String類,這個類是否可以被類載入器載入?為什麼。

載入過程中會先檢查類是否被已載入,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已載入就視為已載入此類,保證此類只所有ClassLoader載入一次。而載入的順序是自頂向下,也就是說當發現這個類沒有的時候會先去讓自己的父類去載入,父類沒有再讓兒子去載入,那麼在這個例子中我們自己寫的String應該是被Bootstrap ClassLoader載入了,所以App ClassLoader就不會再去載入我們寫的String類了,導致我們寫的String類是沒有被載入的。

blog.csdn.net/u013206465/…

24、說一說你對java.lang.Object物件中hashCode和equals方法的理解。在什麼場景下需要重新實現這兩個方法。

對於equals()與hashcode(),比較通用的規則: ①兩個obj,如果equals()相等,hashCode()一定相等 ②兩個obj,如果hashCode()相等,equals()不一定相等

25、在jdk1.5中,引入了泛型,泛型的存在是用來解決什麼問題。

面向物件的轉型只會發生在具有繼承關係的父子類中(介面也是繼承的一種) 向上轉型:其核心目的在於引數的統一上,根本不需要強制型別轉換。 向下轉型:是為了操作子類定義的特殊功能,需要強制型別轉換,可是現在存在的問題是:向下轉型其實是一種非常不安全的操作,以為編譯的時候,程式不會報錯,而在執行的時候會報錯,這就是傳說中的—迷之報錯。

不過呢,在JDK1.5之後,新增加了泛型的技術,這就將上述向下轉型的問題消滅在了萌芽之中。 泛型的核心意義在於:類在進行定義的時候可以使用一個標記,此標記就表示類中屬性或者方法以及引數的型別,標記在使用的時候,才會去動態的設定型別。

26、Java中的HashSet內部是如何工作的。

HashSet 的內部採用 HashMap來實現。由於 Map 需要 key 和 value,所以HashSet中所有 key 的都有一個預設 value。類似於        HashMap,HashSet 不允許重複的 key,只允許有一個null key,意思就是 HashSet 中只允許儲存一個 null 物件。

blog.csdn.net/qq_32575047…

27、什麼是序列化,怎麼序列化,為什麼序列化,反序列化會遇到什麼問題,如何解決。

什麼是序列化? 序列化:把物件轉換為位元組序列的過程稱為物件的序列化。 反序列化:把位元組序列恢復為物件的過程稱為物件的反序列化

什麼情況下需要序列化? 當你想把的記憶體中的物件狀態儲存到一個檔案中或者資料庫中時候; 當你想用套接字在網路上傳送物件的時候; 當你想通過RMI傳輸物件的時候;

如何實現序列化? 實現Serializable介面即可

注意事項: transient 修飾的屬性,是不會被序列化的 靜態static的屬性,他不序列化。 實現這個Serializable 介面的時候,一定要給這個 serialVersionUID 賦值

關於 serialVersionUID 的描述: 序列化執行時使用一個稱為 serialVersionUID 的版本號與每個可序列化類相關聯,該序列號在反序列化過程中用於驗證序列化物件的傳送者和接收者是否為該物件載入了與序列化相容的類。如果接收者載入的該物件的類的 serialVersionUID 與對應的傳送者的類的版本號不同,則反序列化將會導致 InvalidClassException。可序列化類可以通過宣告名為 “serialVersionUID” 的欄位(該欄位必須是靜態 (static)、最終 (final) 的 long 型欄位)顯式宣告其自己的 serialVersionUID

blog.csdn.net/riemann_/ar…

28、java8的新特性。

www.cnblogs.com/frankdeng/p…

image