一 JAVA基礎
1. JAVA中的幾種基本數據類型是什么,各自占用多少字節。
int 32bit short 16bit
long 64bit byte 8bit
char 16bit float 32bit
double 64bit boolean 1bit
============================================================
2. String類能被繼承嗎,為什么?
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
String 被final修飾了,所有不能被繼承。
1.final修飾的對象不能被修改;
2.final修飾的類不能被繼承;
3.final修飾的方法不能被重寫;
==================================================================
3. String,Stringbuffer,StringBuilder的區別。
1.可變與不可變
String類中使用字符數組保存字符串,如下就是,因為有“final”修飾符,所以可以知道string對象是不可變的。
private final char value[];
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,如下就是,可知這兩種對象都是可變的。
char[] value;
2.是否多線程安全
String中的對象是不可變的,也就可以理解為常量,顯然線程安全。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。看如下源碼
最后,如果程序不是多線程的,那么使用StringBuilder效率高於StringBuffer。
。
==================================================================
4 . ArrayList和LinkedList有什么區別。
ArrayList和Vector使用了數組的實現,
LinkedList使用了循環雙向鏈表數據結構。 場景使用不同
對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。
2.在ArrayList的中間插入或刪除一個元素意味着這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
3.LinkedList不支持高效的隨機元素訪問。
4.ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間
可以這樣說:當操作是在一列數據的后面添加數據而不是在前面或中間,並且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數據的前面或中間添加或刪除數據,並且按照順序訪問其中的元素時,就應該使用LinkedList了。
==================================================================
5. 講講類的實例化順序,比如父類靜態數據,構造函數,字段,子類靜態數據,構造函數,字段,當new的時候,他們的執行順序。
類的實例化順序:先靜態再父子
父類靜態數據->子類靜態數據->父類字段->子類字段->父類構造函數->子類構造函數
==================================================================
6. Map區別
用過哪些Map類,都有什么區別,HashMap是線程安全的嗎,並發下使用的Map是什么,他們內部原理分別是什么,比如存儲方式,hashcode,擴容,默認容量等。
最常用的Map實現類有:HashMap,ConcurrentHashMap(jdk1.8),LinkedHashMap,TreeMap,HashTable;
其中最頻繁的是HashMap和ConcurrentHashMap,他們的主要區別是HashMap是非線程安全的。ConcurrentHashMap是線程安全的。
並發下可以使用ConcurrentHashMap和HashTable,他們的主要區別是:
1.ConcurrentHashMap的hash計算公式:(key.hascode()^ (key.hascode()>>> 16)) & 0x7FFFFFFF
HashTable的hash計算公式:key.hascode()& 0x7FFFFFFF
2.HashTable存儲方式都是鏈表+數組,數組里面放的是當前hash的第一個數據,鏈表里面放的是hash沖突的數據
ConcurrentHashMap是數組+鏈表+紅黑樹
3.默認容量都是16,負載因子是0.75。就是當hashmap填充了75%的busket是就會擴容,最小的可能性是(16*0.75),一般為原內存的2倍
4 .線程安全的保證:HashTable是在每個操作方法上面加了synchronized來達到線程安全,ConcurrentHashMap線程是使用CAS(compore and swap)來保證線程安全的
==================================================================
7. JAVA8的ConcurrentHashMap為什么放棄了分段鎖,有什么問題嗎,如果你來設計,你如何設計。
jdk8 放棄了分段鎖而是用了Node鎖,減低鎖的粒度,提高性能,並使用CAS操作來確保Node的一些操作的原子性,取代了鎖。
但是ConcurrentHashMap的一些操作使用了synchronized鎖,而不是ReentrantLock,雖然說jdk8的synchronized的性能進行了優化,但是我覺得還是使用ReentrantLock鎖能更多的提高性能
==================================================================
8. 有沒順序的 Map 實現類,如果有,他們是怎么保證有序的 。 順序的 Map 實現類:LinkedHashMap,TreeMap
LinkedHashMap 是基於元素進入集合的順序或者被訪問的先后順序排序,TreeMap 則是基於元素的固有順序 (由 Comparator 或者 Comparable 確定)。
==================================================================
9. 抽象類和接口的區別,類可以繼承多個類么,接口可以繼承多個接口么,類可以實現多個接口么。抽象類和接口的區別:
1.抽象類可以有自己的實現方法,接口在jdk8以后也可以有自己的實現方法(default)
2.抽象類的抽象方法是由非抽象類的子類實現,接口的抽象方法有接口的實現類實現
3.接口不能有私有的方法跟對象,抽象類可以有自己的私有的方法跟對象
類不可以繼承多個類,接口可以繼承多個接口,類可以實現多個接口
==================================================================
10. 繼承和聚合的區別在哪。
繼承:指的是一個類(稱為子類、子接口)繼承另外的一個類(稱為父類、父接口)的功能,並可以增加它自己的新功能的能力,繼承是類與類或者接口與接口之間最常見的關系;在Java中此類關系通過關鍵字extends明確標識,在設計時一般沒有爭議性;
聚合:聚合是關聯關系的一種特例,他體現的是整體與部分、擁有的關系,即has-a的關系,此時整體與部分之間是可分離的,他們可以具有各自的生命周期,部分可以屬於多個整體對象,也可以為多個整體對象共享;比如計算機與CPU、公司與員工的關系等;表現在代碼層面,和關聯關系是一致的,只能從語義級別來區分;
==================================================================
11. 講講你理解的nio。他和bio的區別是啥,談談reactor模型。
BIO:同步阻塞式IO,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。
NIO:同步非阻塞式IO,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。
reactor模型:反應器模式(事件驅動模式):當一個主體發生改變時,所有的屬體都得到通知,類似於觀察者模式。
==================================================================
12. 反射的原理,反射創建類實例的三種方式是什么。
反射的原理:如果知道一個類的名稱/或者它的一個實例對象, 就能把這個類的所有方法和變量的信息(方法名,變量名,方法,修飾符,類型,方法參數等等所有信息)找出來。
反射創建類實例的三種方式:
1.Class.forName("com.A");
2.new A().getClass();
3.A.class;
==================================================================
13. 反射中,Class.forName和ClassLoader區別。
class.forName()除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執行類中的static塊。
classLoader只干一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。
==================================================================
14. 描述動態代理的幾種實現方式,分別說出相應的優缺點。
動態代理有兩種實現方式,分別是:jdk動態代理和cglib動態代理
jdk動態代理的前提是目標類必須實現一個接口,代理對象跟目標類實現一個接口,從而避過虛擬機的校驗。
cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被聲明成final。
==================================================================
15. 動態代理與cglib實現的區別。
動態代理有兩種實現方式,分別是:jdk動態代理和cglib動態代理
jdk動態代理的前提是目標類必須實現一個接口,代理對象跟目標類實現一個接口,從而避過虛擬機的校驗。
cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被聲明成final。
==================================================================
16. 為什么cglib方式可以對接口實現代理。
cglib動態代理是繼承並重寫目標類,所以目標類和方法不能被聲明成final。而接口是可以被繼承的。
==================================================================
17. final的用途。
1.final修飾的對象不能被修改;
2.final修飾的類不能被繼承;
3.final修飾的方法不能被重寫;
==================================================================
18 如何在父類中為子類自動完成所有的hashcode和equals實現?這么做有何優劣。
父類的equals不一定滿足子類的equals需求。比如所有的對象都繼承Object,默認使用的是Object的equals方法,在比較兩個對象的時候,是看他們是否指向同一個地址。
但是我們的需求是對象的某個屬性相同,就相等了,而默認的equals方法滿足不了當前的需求,所以我們要重寫equals方法。
如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引速度。
==================================================================
20. 請結合OO設計理念,談談訪問修飾符public、private、protected、default在應用設計中的作用。
OO設計理念:封裝、繼承、多態
封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。所以我們可以通過public、private、protected、default 來進行訪問控制
關鍵字 |
類內部 |
本包 |
子類 |
外部包 |
public |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ |
× |
default |
√ |
√ |
× |
× |
private |
√ |
× |
× |
× |
java訪問控制符的含義和使用情況
==================================================================
21. 深拷貝和淺拷貝區別。
淺拷貝只拷貝指針,深拷貝就是拷貝他的值,重新生成的對像。
==================================================================
23. error和exception的區別,CheckedException,RuntimeException的區別。
Error(錯誤)表示系統級的錯誤和程序不必處理的異常,是java運行環境中的內部錯誤或者硬件問題。比如:內存資源不足等。對於這種錯誤,程序基本無能為力,除了退出運行外別無選擇,它是由Java虛擬機拋出的。
Exception(違例)表示需要捕捉或者需要程序進行處理的異常,它處理的是因為程序設計的瑕疵而引起的問題或者在外的輸入等引起的一般性問題,是程序必須處理的。
Exception又分為運行時異常,受檢查異常。
RuntimeException(運行時異常),表示無法讓程序恢復的異常,導致的原因通常是因為執行了錯誤的操作,建議終止程序,因此,編譯器不檢查這些異常。
CheckedException(受檢查異常),是表示程序可以處理的異常,也即表示程序可以修復(由程序自己接受異常並且做出處理), 所以稱之為受檢查異常。
==================================================================
24. 請列出5個運行時異常。
NullPointerException
IndexOutOfBoundsException
ClassCastException
ArrayStoreException
BufferOverflowException
==================================================================
25. 在自己的代碼中,如果創建一個java.lang.String對象,這個對象是否可以被類加載器加載?為什么。
不可以,雙親委派模式會保證父類加載器先加載類,就是BootStrap(啟動類)加載器加載jdk里面的java.lang.String類,而自定義的java.lang.String類永遠不會被加載到
==================================================================
26. 說一說你對java.lang.Object對象中hashCode和equals方法的理解。在什么場景下需要重新實現這兩個方法。
父類的equals不一定滿足子類的equals需求。比如所有的對象都繼承Object,默認使用的是Object的equals方法,在比較兩個對象的時候,是看他們是否指向同一個地址。
但是我們的需求是對象的某個屬性相同,就相等了,而默認的equals方法滿足不了當前的需求,所以我們要重寫equals方法。
如果重寫了equals 方法就必須重寫hashcode方法,否則就會降低map等集合的索引速度。
==================================================================
27. 在jdk1.5中,引入了泛型,泛型的存在是用來解決什么問題。
泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。==================================================================
28. 有沒可能 2個不相等的對象有同hashcode。
有可能,最簡單的方法,百分百實現的方式就是重寫hascode();
==================================================================
29. Java中的HashSet內部是如何工作的。
public HashSet() {
map = new HashMap<>();}
默認使用的是HaseMap;
==================================================================
30什么是序列化,怎么序列化,為什么序列化,反序列化會遇到什么問題,如何解決。
序列化是一種用來處理對象流的機制 ,所謂對象流就是將對象的內容進行流化。
序列化是為了解決在對對象流進行讀寫操作時所引發的問題。
序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法,implements Serializable只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接着,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流;