Java面試題-基礎
- 1、Java語言有哪些特點?
- 2、面向對象和面向過程的區別是什么?
- 3、說說標識符的命名規則?
- 4、說說Java八種基本數據類型的大小以及他們的封裝類?
- 5、instanceof關鍵字有什么作用?
- 6、自動裝箱與自動拆箱是什么?
- 7、重載和重寫有什么區別?
- 8、equals與==有什么區別?
- 9、Hashcode有什么作用?
- 10、String、StringBuffer 和 StringBuilder 的區別是什么?
- 11、ArrayList和linkedList的區別是什么?
- 12、HashMap和HashTable的區別是什么?
- 13、Collection和Collections的區別是什么?
- 14、Java的四種引用強弱軟虛是什么?
- 15、泛型特點有哪些?
- 16、Java創建對象的方式有哪些?
- 17、final有哪些用法?
- 18、static都有哪些用法?
- 19、有沒有可能兩個不相等的對象有相同的hashcode?
- 20、深拷貝和淺拷貝的區別是什么?
- 21、3*0.1== 0.3返回值是什么?
- 22、a=a+b與a+=b有什么區別嗎?
- 23、try catch finally,try里有return,finally還執行么?
- 24、說說Excption與Error?
- 25、常見的運行時異常有哪些?
- 26、常見被檢查異常有哪些?
- 27、常見Error錯誤有哪些?
- 28、OOM遇到過哪些情況?SOF遇到過哪些情況?
- 29、簡述線程、程序、進程的基本概念和關系?
- 30、Java序列化中如果有些字段不想進行序列化怎么辦?
- 31、說說Java中IO流?
- 32、Java lO和NIO區別?
- 33、java反射的作用和原理?
- 34、說說List,Set,Map三者的區別?
- 35、Object有哪些常用方法?大致說一下每個方法的含義
- 36、獲取一個類Class對象的方式有哪些?
- 37、ArrayList 和 LinkedList 的區別有哪些?
- 38、說一下ArrayList的特點?
- 39、有數組了為什么還要搞個 ArrayList 呢?
- 40、說說什么是 fail-fast?
- 41、說說Hashtable與HashMap 的區別?
- 42、HashMap中的key我們可以使用任何類作為key嗎?
- 43、HashMap的長度為什么是2的N次方呢?
- 44、HashMap與ConcurrentHashMap 的異同
- 45、紅黑樹有哪幾個特征?
- 46、說說你平時是怎么處理Java異常的?
- 47、JVM、JRE、JDK之間的關系?
- 48、public、protected、default、private的區別?
- 49、多態是什么?如何實現多態?
- 50、說說你對ArrayList的了解?
- 51、說說你對LinkedList的了解?
- 52、說說你對Vector的了解?
- 53、說說對Set的了解?
- 54、說說你對Map的了解?
- 55、Map的遍歷方式有哪些?
- 56、說說你對HashMap的了解?
- 57、說說你對TreeMap的了解?
- 58、什么是跨平臺性?原理是什么?
- 59、什么是字節碼?采用字節碼的最大好處是什么?
- 60、Java和C++的區別?
- 61、switch 是否能作用在 byte上?是否能作用在long或String上?
- 62、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
- 63、float f=3.4;這句代碼是否正確?
- 64、short s1 = 1; s1 = s1+1; 有錯嗎?short s1 = 1; s1 += 1;有錯嗎?
- 65、Java語言采用何種編碼方案?有何特點?
- 66、Java有哪些注釋?
- 67、&和&&的區別?
- 68、final有什么用?
- 69、this關鍵字有哪些用途?
- 70、super關鍵字有哪些用途?
- 71、this與super的區別?
- 72、static存在的意義是什么?
- 73、static的獨特之處是什么?
- 74、static應用場景有哪些?
- 75、static使用注意事項有哪些?
- 76、break,continue,return 的區別及作用?
- 77、在Java中如何跳出當前的多重嵌套循環?
- 78、面向對象的特征有哪些方面?
- 79、什么是多態機制?
- 80、java多態的實現方式?
- 81、說說面向對象編程的五大基本原則
- 82、說說抽象類和接口的異同點?
- 83、普通類與抽象類有什么區別?
- 84、抽象類能使用 final修飾嗎?
- 85、創建一個對象用什么關鍵字?對象實例與對象引用有何不同?
- 86、成員變量與局部變量有什么區別?
- 87、在Java中定義一個無參的默認構造方法的作用是什么?
- 88、在調用子類構造方法之前先調用父類的無參數構造方法目的是什么?
- 89、類的構造方法的作用是什么?若一個類沒有聲明構造方法,程序能正確執行嗎?
- 90、構造方法的特性有哪些?
- 91、靜態變量(也稱為類變量)和實例變量有什么區別?
- 92、靜態變量(類變量)和普通變量(實例變量)有什么區別?
- 93、靜態方法和實例方法有什么區別?
- 94、在一個靜態方法內調用一個非靜態成員為什么是非法的?
- 95、什么是方法的返回值?返回值的作用是什么?
- 96、內部類是什么?
- 97、內部類有哪些類型?
- 98、內部類哪些優缺點?
- 99、內部類有哪些應用場景?
- 100、局部內部類和匿名內部類訪問局部變量的時候,為什么變量必須要加上final?
- 101、構造器是否可被重寫?
- 102、HashSet如何檢查重復?
- 103、兩個對象的hashCode()相同,則equals()也一定為true對嗎?
- 104、說說hashCode和equals方法的關系?
- 105、為什么重寫equals時必須重寫hashCode方法?
- 106、說說你對hashCode()的了解?
- 107、為什么要有hashCode?
- 108、對象相等和引用相等有什么不同?
- 109、當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里是值傳遞還是引用傳遞?
- 110、為什么Java中只有值傳遞?
- 111、值傳遞和引用傳遞有什么區別?
- 112、JDK中常用的包有哪些?
- 113、java和javax有什么區別?
- 114、java 中10流分為幾種?
- 115、Files的常用方法都有哪些?
- 116、什么是反射機制?
- 117、Java反射機制有什么優缺點?
- 118、靜態編譯和動態編譯的區別是什么?
- 119、反射機制的應用場景有哪些?
- 120、Java獲取反射的三種方法?
- 121、字符型常量和字符串常量的區別是什么?
- 122、什么是字符串常量池?
- 123、String 是最基本的數據類型嗎?
- 124、String有哪些特性?
- 125、String為什么是不可變的嗎?
- 126、String有什么辦法可以變成可變的嗎?
- 127、String 類可以被繼承嗎?
- 128、String str="i"與 String str=new String("i")一樣嗎?
- 129、String s = new String("xyz");創建了幾個字符串對象?
- 130、如何將字符串反轉?
- 131、數組有沒有length()方法? String 有沒有length()方法?
- 132、String 類的常用方法都有那些?
- 133、在使用 HashMap 的時候,用String 做 key有什么好處?
- 134、String為什么是不可變的?
- 135、String和StringBuffer、 StringBuilder的區別是什么?
- 136、Integer a=127與Integer b=127相等嗎?
- 137、Integer a=128與Integer b=128相等嗎?
1、Java語言有哪些特點?
- 面向對象
- 平臺無關性
- 簡單性
- 多線程
- 安全性
- 健壯性
- 高性能
- 分布式處理
2、面向對象和面向過程的區別是什么?
- 面向過程:基于功能或過程,強調的是動作本身,按順序執行任務的程序設計。
- 面向對象:基于對象概念,強調數據和操作數據的方法結合,支持繼承、封裝、多態。
3、說說標識符的命名規則?
- 標識符的含義:在程序中我們自己定義的內容,譬如類的名字,方法名稱以及變量名稱等等,都是標識符。
- 命名規則:(硬性要求)標識符可以包含英文字母,0-9的數字,$以及_標識符不能以數字開頭,標識符不能是Java保留關鍵字
- 命名規范:(非硬性要求)類名規范:首字符大寫,后面每個單詞首字母大寫(大駝峰式)。變量名規范:首字母小寫,后面每個單詞首字母大寫(小駝峰式)。方法名規范:同變量名。
4、說說Java八種基本數據類型的大小以及他們的封裝類?
- byte:大小為8位,默認值0,封裝類是
Byte
。 - short:大小為16位,默認值0,封裝類是
Short
。 - int:大小為32位,默認值0,封裝類是
Integer
。 - long:大小為64位,默認值0L,封裝類是
Long
。 - float:大小為32位,默認值0.0f,封裝類是
Float
。 - double:大小為64位,默認值0.0d,封裝類是
Double
。 - char:大小為16位,默認值’\u0000’(即空字符),封裝類是
Character
。 - boolean:大小不明確(依賴于虛擬機實現)有一個默認值false,封裝類是
Boolean
。
5、instanceof關鍵字有什么作用?
instanceof
關鍵字用于檢查一個對象是否是指定類或其子類的實例,返回true
或false
。
6、自動裝箱與自動拆箱是什么?
自動裝箱:基本類型自動轉換為對應的包裝類型。例如:
- 將
int
轉換為Integer
- 將
double
轉換為Double
- 將
boolean
轉換為Boolean
自動拆箱:包裝類型自動轉換為對應的基本類型。例如:
- 將
Integer
轉換為int
- 將
Double
轉換為double
- 將
Boolean
轉換為boolean
7、重載和重寫有什么區別?
重載(Overloading):
- 發生在同一個類中。
- 方法名相同,參數列表不同(類型、個數、順序)。
- 返回類型可以不同,不影響重載判斷。編譯時多態。
重寫 (Overriding):
- 發生在父子類之間。
- 方法名、參數列表相同。
- 返回類型必須相同或為子類型(Java 5及之后)。
- 訪問權限不能比父類方法更嚴格。
- 運行時多態。
8、equals與==有什么區別?
==
:比較兩個對象的引用或基本數據類型的值是否相同。
equals
:默認比較對象的引用,可被重寫來比較對象的內容。
9、Hashcode有什么作用?
hashCode()
方法的作用是返回對象的哈希碼,主要用于優化信息存儲結構,如哈希表(HashMap
、 HashSet
等),通過哈希碼來快速定位對象的存儲地址,提高數據訪問效率。在Java中相等的對象必須有相同的哈希碼。
10、String、StringBuffer 和 StringBuilder 的區別是什么?
- String:不可變字符序列,每次修改都會生成新的字符串對象,效率較低于 StringBuffer 和 StringBuilder,適用于少量的字符串操作。
- StringBuffer:可變字符序列,線程安全,適用于多線程環境中的字符串操作,但線程安全特性使其效率略低于 StringBuilder。
- StringBuilder:可變字符序列,非線程安全,效率高于StringBuffer,適用于單線程環境中的大量字符串操作。
11、ArrayList和linkedList的區別是什么?
- ArrayList:
- 基于動態數組實現,支持隨機訪問。
- 插入、刪除操作需要數組拷貝,效率較低。
- 擴容操作成本高,需復制整個數組。
- LinkedList:
- 基于雙向鏈表實現。
- 插入、刪除操作效率高,不需要移動其他元素。
- 不支持高效的隨機訪問。
12、HashMap和HashTable的區別是什么?
- 線程安全:
HashMap
:非線程安全。HashTable
:線程安全,通過方法同步。
- 性能:
HashMap
:因非線程安全,性能較高。HashTable
:線程安全導致性能較低。
- 鍵和值的null:
HashMap
:允許一鍵為null,多個值為null。HashTable
:鍵和值都不能為null。
- 遍歷:
HashMap
:使用Iterator
遍歷。HashTable
:使用Enumerator
或Iterator
遍歷。
- 繼承:
HashMap
:繼承自AbstractMap
類。HashTable
:繼承自Dictionary
類。
13、Collection和Collections的區別是什么?
Collection包結構
java.util.Collection
是Java集合框架的根接口,它下面有幾個主要的子接口:
- List : 一個有序集合(如
ArrayList
、LinkedList
)。 - Set:一個無重復元素的集合(如
HashSet
、TreeSet
)。 - Queue:一個用于隊列操作的集合(如
LinkedList
、PriorityQueue
)。
Collections的區別
- Collection:是一個接口,提供了對集合對象進行基本操作的通用接口。
- Collections:是一個包含有關集合操作的靜態方法的工具類,如排序(
sort
)、搜索(search
)等,它作用于 Collection 接口及其子接口的實現。
總結:Collection
是一個集合接口,定義了集合的基本操作。Collections
是一個操作集合的工具類,提供了一系列靜態方法來操作集合數據。
14、Java的四種引用強弱軟虛是什么?
- 強引用(Strong Reference):
- 最常見的引用類型,如
Object obj = new Object();
。只要強引用存在,垃圾回收器永遠不會回收被引用的對象。
- 最常見的引用類型,如
- 軟引用(Soft Reference):
- 通過
SoftReference
類實現。軟引用的對象在系統將要發生內存溢出之前,會將這些對象列入回收范圍進行二次回收。適用于緩存實現。
- 通過
- 弱引用(Weak Reference):
- 通過
WeakReference
類實現。弱引用的對象只能生存到下一次垃圾收集發生之前。無論內存是否足夠,都會被回收。
- 通過
- 虛引用(Phantom Reference):
- 通過
PhantomReference
類實現。虛引用的對象完全不會影響其生命周期,僅僅提供了一種確保對象被 finalize后,能做某些事情的機制。
- 通過
15、泛型特點有哪些?
- 類型安全:泛型提供編譯時類型檢查,避免運行時的類型轉換錯誤。
- 消除類型強轉:使用泛型后,不需要進行顯式的類型轉換。
- 代碼重用:泛型使得代碼對不同類型的對象重用成為可能,提高了代碼的復用性。
- 泛型方法:允許在方法級別上指定類型參數,使得方法能在多種類型上操作。
- 泛型類/接口:可以定義帶有類型參數的類或接口,用于多種數據類型的操作。
- 類型擦除:泛型信息只存在于編譯階段,在運行時會被擦除,JVM看到的只是普通類和方法。
- 限制和通配符:可以使用 extends 和 super來限制泛型的類型范圍,增加了泛型的靈活性。
16、Java創建對象的方式有哪些?
- 使用
**new**
關鍵字:最常見的方式。 - 使用
**Class.forName()**
配合**newInstance()**
:反射機制創建對象。 - 使用
**clone()**
方法:克隆一個對象。 - 使用對象序列化和反序列化:通過讀取字節數據恢復為對象。
- 使用
**Constructor.newInstance()**
:反射中的Constructor創建對象。
17、final有哪些用法?
- 修飾變量:變量成為常量,初始化后不能被修改。
- 修飾方法:方法不能被子類覆蓋。
- 修飾類:類不能被繼承。
18、static都有哪些用法?
- 修飾變量:變量變成類的靜態變量,所有實例共享。
- 修飾方法:方法可以不通過對象而直接通過類來調用。
- 靜態初始化塊:用于初始化類的靜態變量,只執行一次。
- 靜態內部類:不需要外部類的對象就可以創建的內部類。
19、有沒有可能兩個不相等的對象有相同的hashcode?
是的,兩個不相等的對象可以有相同的hashCode
。這種情況稱為哈希碰撞(HashCollision)。由于哈希碼的值域(通常是int
類型的范圍)有限,而實際對象的數量可能遠遠超出這個范圍,理論上不可能為每個不同的對象分配一個唯一的哈希碼。因此不同對象產生相同哈希碼是可能的。
20、深拷貝和淺拷貝的區別是什么?
淺拷貝:只復制對象及其基本數據類型的值,對象內的引用類型指向同一地址。
深拷貝:復制對象及其內部所有層級的對象,完全獨立,無共享引用。
21、3*0.1== 0.3返回值是什么?
3 * 0.1 == 0.3
的返回值是False
。
這是因為浮點數的精度問題,計算機在處理浮點數時可能不會得到完全精確的結果。
22、a=a+b與a+=b有什么區別嗎?
- 類型轉換差異:
a = a + b
需要a
和b
類型完全匹配,或能夠通過類型提升自動匹配。a += b
內部包含隱式的類型轉換,即如果a``和b
類型不匹配,b
的類型會被自動提升或轉換為a
的類型,然后再進行賦值。
- 效率和簡潔性:
- 在編寫和閱讀代碼時,
a += b
更簡潔。 - 在某些編譯器優化中,
a += b
可能會略微高效,盡管這種差異通常非常小,對性能影響不大。
- 在編寫和閱讀代碼時,
23、try catch finally,try里有return,finally還執行么?
是的,即使try
塊中有return
語句,finally
塊仍然會執行。finally
塊設計用于確保無論try
塊內發生什么(包括返回和拋出異常),都能執行清理或釋放資源等操作。
24、說說Excption與Error?
Exception
和Error
都是Throwable
類的子類,它們構成了Java異常處理的兩大分支。
- Throwable
- 根類,表示所有可以作為異常被拋出的類。
- Exception
- 表示程序中出現的異常情況,可以被捕獲并由程序處理。
- 分為兩大類:
- Checked Exception:編譯時異常,必須被顯式捕獲或通過方法簽名聲明。
- Unchecked Exception(RuntimeException):運行時異常,不需要顯式捕獲或聲明。
- Error
- 表示嚴重的錯誤,通常是程序無法處理的,如虛擬機錯誤和系統錯誤。
- 例如,
OutOfMemoryError
、StackOverflowError
等。
結構圖如下:
Throwable
|——Exception
| |——IOException
| |——SQLException
| |——RuntimeException
| |——NullPointerException
| |——IndexOutOfBoundsException
| |——ArithmeticException
|——Error|——LinkageError|——VirtualMachineError| |——OutOfMemoryError| |——StackOverflowError|——AssertionError
25、常見的運行時異常有哪些?
常見的運行時異常(RuntimeException
的子類)包括:
**NullPointerException**
:當嘗試使用null
對象引用執行操作時拋出。**ArrayIndexOutOfBoundsException**
:嘗試訪問數組時使用了非法索引(負數或超出數組大小)。**ArithmeticException**
:發生異常的算術條件,例如除以零。**ClassCastException**
:嘗試將對象強制轉換為不是實例的類時拋出。**IllegalArgumentException**
:向方法傳遞了一個不合法或不適當的參數。**IllegalStateException**
:在不合法或不適當的時間調用方法。**NumberFormatException**
:嘗試將字符串轉換為數字格式,但字符串不具有適當的格式。**IndexOutOfBoundsException**
:某種類型的索引(如數組、字符串或向量)超出范圍時拋出。**ConcurrentModificationException**
:在對集合進行迭代時,除了迭代器自身之外的其他方式修改了集合,就會拋出此異常。
26、常見被檢查異常有哪些?
被檢查的異常(Checked Exception)是那些在編譯時必須被顯式處理(捕獲或通過方法簽名聲明拋出)的異常。它們直接繼承自Exception
類,但不包括繼承自RuntimeException
的異常。一些常見的被檢查異常包括:
**IOException**
:輸入輸出操作失敗或中斷時拋出,如讀寫文件錯誤。**FileNotFoundException**
:嘗試打開文件失敗時拋出,文件不存在等情況。**ClassNotFoundException**
:找不到類定義時拋出。**SQLException**
:處理數據庫時發生錯誤時拋出。**MalformedURLException**
:指定了未知協議或格式錯誤的 URL 時拋出。**InterruptedException**
:線程被另一個線程中斷時拋出。**NoSuchMethodException**
:請求的方法不存在時拋出。**SAXException**
:處理XML文件錯誤時拋出。**ParseException**
:解析日期、時間等格式出錯時拋出。
27、常見Error錯誤有哪些?
**OutOfMemoryError**
: JVM沒有足夠的內存分配對象。**StackOverflowError**
:棧溢出,通常是由深度遞歸調用導致。**NoClassDefFoundError**
:找不到類定義,可能是因為類路徑問題。**UnsatisfiedLinkError**
:當Java虛擬機不能找到一個本地方法的聲明時拋出。**NoSuchMethodError**
:調用不存在的方法。**ExceptionInInitializerError**
:靜態初始化器拋出異常或無法加載靜態初始化塊。**LinkageError**
:類依賴性問題,如類的不同版本之間的不兼容。**ThreadDeath**
:線程被stop()
方法殺死時拋出。**VirtualMachineError**
: JVM發生內部錯誤或資源不足時的超類。
28、OOM遇到過哪些情況?SOF遇到過哪些情況?
遇到的**OutOfMemoryError**
(OOM)情況:
- 堆內存溢出:對象創建過多,GC無法回收,導致堆內存耗盡。
- 永久代(元空間)溢出:加載的類信息太多或大量動態生成類,導致永久代(Java 8后為元空間)內存不足。
- 直接內存溢出:通過
ByteBuffer.allocateDirect()
分配的直接內存過多。 - 線程堆棧溢出:應用創建過多線程,每個線程分配的堆棧大小(
-Xss
)導致總體占用空間超過可用內存。 - Tomcat 內存溢出:Web應用部署過多或單個應用占用內存過大,超出Tomcat分配的內存限制。
遇到的**StackOverflowError**
(SOF)情況:
- 深度遞歸調用:遞歸調用層次太深,超出了JVM分配給線程堆棧的容量。
- 大量局部變量:方法中定義了大量局部變量,增加了每個方法幀的大小,導致堆棧快速耗盡。
- 無限循環或遞歸:無終止條件的遞歸或循環,使得方法不斷調用自身或其他方法。
面試官追問如何解決?通常這些情況通常需要通過代碼優化、合理配置JVM參數、監控和分析堆棧/內存使用情況來解決。
29、簡述線程、程序、進程的基本概念和關系?
程序:是指令和數據的集合,存儲在磁盤上的文件,是靜態的代碼。
進程:程序的一次執行過程,是系統資源分配的基本單位。它擁有獨立的內存空間,包含代碼、數據以及執行的上下文。
線程:是進程中的執行單元,是CPU調度的基本單位。一個進程可以包含多個線程,它們共享進程的資源但能夠并行執行任務。
關系:
- 程序是靜態的代碼和數據的集合,不具備運行的能力。
- 進程是程序運行的實例,提供必要的資源和環境。
- 線程是進程內部的執行單元,實現程序的并發執行。
簡而言之程序是死的,進程是程序的活體表現,線程是進程的執行路徑。一個程序可以被多個進程加載執行,一個進程可以包含多個線程共同完成任務,實現并發。
30、Java序列化中如果有些字段不想進行序列化怎么辦?
如果不希望某些字段被序列化,可以將這些字段聲明為transient
。使用transient
關鍵字修飾的字段不會被序列化到輸出流中,因此在反序列化時,這些字段將被忽略,其值會被設置為類型的默認值(例如,數值型為0,對象引用為null)。
31、說說Java中IO流?
IO流用于讀取和寫入數據,主要分為四大類,根據數據類型分為字節流和字符流,根據流向分為輸入流和輸出流:
- 字節流:
- 輸入流:
InputStream
是所有字節輸入流的父類,用于從源讀取字節數據。 - 輸出流:
OutputStream
是所有字節輸出流的父類,用于向目的地寫出字節數據。
- 輸入流:
- 字符流:
- 輸入流:
Reader
是所有字符輸入流的父類,用于從源讀取字符數據。 - 輸出流:
Writer
是所有字符輸出流的父類,用于向目的地寫出字符數據。
- 輸入流:
主要流類
- 字節流類:
FileInputStream
、FileOutputStream
、BufferedInputStream
、BufferedOutputStream
等。 - 字符流類:
FileReader
、FileWriter
、BufferedReader
、BufferedWriter
等。
特殊流類
- 轉換流:
InputStreamReader
和OutputStreamWriter
轉換流可以將字節流和字符流進行轉換。 - 序列化流:
ObjectInputStream
和ObjectOutputStream
用于對象的序列化和反序列化。 - 打印流:
PrintStream
和PrintWriter
提供了打印各種數據值表示的便捷方法。
使用場景
- 字節流:適用于處理原始數據,如二進制文件、圖片、音頻視頻等。
- 字符流:適用于處理文本數據。
32、Java lO和NIO區別?
區別:
- 基本概念:
- IO:面向流(Stream Oriented),阻塞式IO。每次從流中讀取或寫入數據時,都會阻塞直到有數據處理。
- NIO:面向緩沖區(Buffer Oriented),非阻塞式IO。通過通道(Channel)和緩沖區(Buffer)交換數據,支持非阻塞模式和選擇器(Selector)
- 阻塞與非阻塞:
- IO:基于流模型實現,進行讀寫操作時會一直阻塞,直到操作完成。
- NIO:可以設置為非阻塞模式,當沒有數據可讀或寫時,線程可以做其他任務。
- 數據處理單位:
- IO:以流的方式處理數據,直接對流進行讀寫。
- NIO:以塊(Buffer)的方式處理數據,數據首先讀取到緩沖區,再從緩沖區進行處理。
- 選擇器(Selectors):
- IO:不支持。
- NIO:支持選擇器,一個線程可以管理多個輸入和輸出通道。
- 使用場景:
- IO:適用于連接數目比較小且固定的架構,這種方式可以直接對流進行處理。
- NIO:適用于連接數目多且動態變化的架構,如高性能網絡服務器。
- 性能和可伸縮性:
- IO:簡單易用,但在高并發情況下性能和可伸縮性較差。
- NIO:在處理并發連接和高速數據讀寫時具有更高的性能和可伸縮性。
33、java反射的作用和原理?
反射的作用
Java反射機制允許程序在運行時取得任何類的內部信息,并能操作任意對象的內部屬性及方法。它的主要作用包括:
- 在運行時判斷任意一個對象所屬的類:反射機制可以通過對象獲得類的信息,如類的方法、字段、構造器等。
- 在運行時構造任意一個類的對象:可以通過反射機制創建對象,而不需要通過
new
關鍵字實例化。 - 在運行時判斷任意一個類所具有的成員變量和方法:反射機制可以遍歷類的字段和方法,甚至調用方法。
- 在運行時調用任意一個對象的方法:反射機制允許調用任意對象的方法,而不需要事先知道該對象的類型。
- 生成動態代理:利用反射機制生成類或接口的動態代理實現。
反射的原理
Java反射是通過類加載機制來實現的。當Java程序運行時,Java虛擬機(JVM)會將使用到的類加載到內存中,并為每個類創建一個Class
類型的對象(即類對象),用于存儲類的元數據信息(如類的名稱、方法信息、字段信息等)。當程序通過反射API(如Class.forName()
,obj.getClass()
,.class
語法)獲取到對應的Class
對象后,就可以利用這個對象來訪問類的信息和動態操作類或對象。
- 類的加載:當程序使用到某個類時,Java虛擬機將該類加載到內存中。
- 創建
**Class**
對象:加載過程中,JVM為每個類創建Class
對象,其中包含了類的元數據信息。 - 使用
**Class**
對象:程序可以通過Class
對象訪問類的元數據,創建實例,訪問字段和方法等。
34、說說List,Set,Map三者的區別?
List:
- 有序集合,按插入順序存儲元素。
- 允許重復的元素。
- 典型實現:
ArrayList
,LinkedList
。
Set:
- 無序集合,不保證存儲順序。
- 不允許重復的元素。
- 典型實現:
HashSet
,LinkedHashSet
,TreeSet
。
Map:
- 鍵值對集合,存儲元素為鍵值對( key-value)。
- 保證鍵的唯一性,值可以重復。
- 不是
Collection
接口的一部分。 - 典型實現:
HashMap
,LinkedHashMap
,TreeMap
。
區別:
- 存儲結構: List是序列集合,Set是不重復元素的集合,Map是鍵值對的映射。
- 元素唯一性:List 允許重復元素,Set不允許重復元素,Map的鍵不允許重復。
- 存儲順序:List保持元素的插入順序,Set通常不保證順序(除
LinkedHashSet
),Map不保證鍵值對的順序(除LinkedHashMap
)。
35、Object有哪些常用方法?大致說一下每個方法的含義
public final Class<?> getClass()
:- 返回此對象的運行時類。
public int hashCode()
:- 返回對象的哈希碼值,用于哈希表。
public boolean equals(Object obj)
:- 指示其他某個對象是否與此對象"相等”。
protected Object clone() throws CloneNotSupportedException
:- 創建并返回此對象的一個副本。
public String toString()
:- 返回對象的字符串表示,通常是對象的類名加上其哈希碼的無符號十六進制表示。
public final void notify()
:- 喚醒在此對象監視器上等待的單個線程。
public final void notifyAll()
:- 喚醒在此對象監視器上等待的所有線程。
public final void wait(long timeout) throws InterruptedException
;- 使當前線程等待直到另一個線程調用此對象的
notify()
方法或notifyAll()
方法,或者超過指定的時間量。
- 使當前線程等待直到另一個線程調用此對象的
public final void wait(long timeout, int nanos) throws InterruptedException
:- 使當前線程等待直到另一個線程調用此對象的
notify()
方法或notifyAll()
方法,或者其他某個線程中斷當前線程,或者已經過了指定的實際時間。
- 使當前線程等待直到另一個線程調用此對象的
protected void finalize() throws Throwable
:- 當垃圾收集器決定不存在對該對象的更多引用時,由垃圾收集器調用此方法。用于資源釋放等清理操作。已在Java 9中被標記為過時。
36、獲取一個類Class對象的方式有哪些?
- 使用
.class
語法,如String.class
。 - 通過對象調用
getClass()
方法,如"hello".getClass()
。 - 使用
Class.forName()
靜態方法,如Class.forName("java.lang.String")
。
37、ArrayList 和 LinkedList 的區別有哪些?
- 內部結構:
ArrayList
基于動態數組。LinkedList
基于雙向鏈表。
- 性能:
ArrayList
優于LinkedList
在隨機訪問數據。LinkedList
優于ArrayList
在添加和刪除操作。
- 內存占用:
ArraylList
更緊湊,但在擴容時需要重新分配內存并復制。LinkedList
為每個元素使用更多內存(因節點引用)。
38、說一下ArrayList的特點?
- 基于動態數組實現:內部使用可擴容的數組結構,便于索引訪問和存儲。
- 隨機訪問效率高:提供快速的隨機訪問性能,通過索引直接訪問元素。
- 添加、刪除元素成本較高:除了尾部添加外,插入或刪除元素可能需要移動多個元素,效率較低。
- 動態擴容:當添加元素超過當前容量時,自動擴容,但擴容操作涉及數組復制,可能影響性能。
- 不是線程安全的:多線程環境下,需要外部同步。
39、有數組了為什么還要搞個 ArrayList 呢?
- 動態擴容:數組大小固定,一旦創建不能改變。
ArrayList
可以自動擴展和縮減大小,提供了更大的靈活性。 - 便捷的操作:
ArrayList
提供了大量方法來進行元素的插入、刪除、遍歷等操作,使用起來更加方便。 - 泛型支持:
ArrayList
支持泛型,可以在編譯時檢查元素類型,提高代碼的安全性和可讀性。 - 集合框架的一部分:
ArrayList
是Java 集合框架的一部分,可以與其他集合類型(如Set
、Map
)無縫集成,提供了統一的編程接口。
40、說說什么是 fail-fast?
Fail-fast 是一種錯誤檢測機制,指的是在操作集合(如列表、集合等)時,如果檢測到集合在迭代過程中被結構性地修改(例如添加、刪除元素),則立即拋出ConcurrentModificationException
異常。這種機制旨在快速失敗,避免不確定的行為和潛在的錯誤。Java集合框架中的很多實現(如ArrayList
、HashMap
)都采用了fail-fast 機制。它主要通過在迭代器內部維護一個修改計數器(modCount)來實現,每次迭代前檢查計數器是否有變化,以保證迭代的一致性和安全性。
41、說說Hashtable與HashMap 的區別?
- 線程安全:
Hashtable
是線程安全的,HashMap
不是。 - 性能:因為線程安全,
Hashtable
性能較HashMap
低。 - 空值:
Hashtable
不允許鍵或值為null
,HashMap
允許一個鍵為null
和多個值為null
。 - 遍歷:
Hashtable
繼承自Dictionary
類,HashMap
是Java Collections Framework的一部分。
42、HashMap中的key我們可以使用任何類作為key嗎?
是的,可以使用任何類作為HashMap
中的key,但為了確保HashMap
正確地存儲和檢索鍵值對,有兩個重要條件需要滿足:
- 重寫
**equals()**
方法:確保當兩個鍵對象邏輯上等價時,可以返回true
。 - 重寫
**hashCode()**
方法:確保邏輯上等價的鍵對象產生相同的哈希碼。
如果這兩個方法沒有被適當地重寫,HashMap
可能無法準確地識別鍵對象,導致數據存取錯誤。
43、HashMap的長度為什么是2的N次方呢?
HashMap的長度是2的N次方主要是為了優化索引計算的效率。這樣設計可以使得索引的計算通過位運算(hash & (length-1)
)來完成,這比模運算更高效。同時,這種長度能夠幫助哈希表中的元素更均勻地分布,減少哈希沖突,提高了HashMap的整體性能。
44、HashMap與ConcurrentHashMap 的異同
相同點:
- 都實現了
Map
接口,用于存儲鍵值對。 - 內部結構都利用了哈希表。
不同點:
- 線程安全:
HashMap
是非線程安全的,適用于單線程環境。ConcurrentHashMap
是線程安全的,適用于多線程環境。
- 性能:
- 由于線程安全的實現方式不同、
ConcurrentHashMap
在多線程環境下性能優于使用Collections.synchronizedMap(new HashMap<>())
包裝的HashMap
。
- 由于線程安全的實現方式不同、
- 內部實現:
HashMap
允許一個null
鍵和多個null
值。ConcurrentHashMap
不允許null
鍵和null
值,因為并發讀取時無法區分返回值null
是映射值本身為 null還是鍵不在映射中。
- 并發控制:
HashMap
在擴容時直接對整個哈希表進行擴容。ConcurrentHashMap
使用分段鎖(在Java 8以后是通過分散數組、鏈表和紅黑樹的結構,以及CAS操作和synchronized
來保證線程安全),減少了鎖競爭,提高了效率。
45、紅黑樹有哪幾個特征?
紅黑樹的五個特征:
- 每個節點是紅色或黑色。
- 根節點是黑色。
- 所有葉子(NI節點)都是黑色。
- 每個紅色節點的兩個子節點都是黑色(紅色節點不能連續)。
- 從任一節點到其每個葉子的所有路徑都包含相同數目的黑色節點。
46、說說你平時是怎么處理Java異常的?
- 明確異常類型:區分檢查型異常和運行時異常。
- 合理使用 try-catch:捕獲具體能處理的異常,避免捕獲
Exception
或Throwable
。 - 合理利用finally:確保資源在異常發生時也能被正確釋放。
- 避免空catch塊:即使暫時不處理異常,也應記錄或注釋說明原因。
- 使用throws聲明:對于無法立即處理的檢查型異常,通過方法簽名向上拋出。
- 異常鏈:在捕獲異常后拋出新異常時,保留原始異常信息。
- 自定義異常:根據需要合理定義業務異常類,提高異常的可識別性。
- 避免異常用于控制流程:異常應用于異常情況處理,不應作為常規控制流程的一部分。
47、JVM、JRE、JDK之間的關系?
- JVM(Java Virtual Machine):是一個抽象的計算機,提供運行Java字節碼的環境,使得Java程序能夠在任何平臺上運行不受限制。
- JRE(Java Runtime Environment) :包括JVM和運行Java程序所需的核心庫及其他組件。它是運行已經開發的Java程序所需要的環境。
- JDK(Java Development Kit):包含了JRE以及開發Java程序所需的編譯器、工具和庫(比如javac)。JDK是用于開發Java應用程序的軟件開發工具包。
關系:JDK用于開發Java程序,包括JRE來運行編譯后的程序,而JRE包含JVM來提供一個平臺無關的運行環境。簡而言之,JDK > JRE > JVM,其中JDK是包含JRE的,而JRE是包含JVM的。
48、public、protected、default、private的區別?
在Java中,public
、protected
、default
(無修飾符)和private
關鍵字用于指定類成員(方法和變量)的訪問級別:
- public:成員可被任何其他類訪問。
- protected:成員可被同一包內的類以及所有子類訪問。
- default(無修飾符):成員只能被同一包內的類訪問。
- private:成員只能被其所在類訪問。
這些修飾符從寬松到嚴格排序為:public > protected > default > private,它們定義了類成員在不同上下文中的可見性和訪問性。
49、多態是什么?如何實現多態?
多態是面向對象編程中的一個核心概念,指的是同一操作作用于不同的對象時,可以有不同的解釋和表現。在Java中,多態可以通過繼承(inheritance)和接口(interfaces)來實現,具體體現為:
- 方法重寫(Override):子類重寫父類中的方法,實現運行時多態。
- 接口實現(Implements):類通過實現接口并提供接口方法的具體實現,同樣實現運行時多態。
- 向上轉型(Upcasting):子類對象直接賦值給父類引用,通過父類引用調用重寫方法,實現多態。
50、說說你對ArrayList的了解?
ArrayList
是Java中的一個可調整大小的數組實現,屬于java.util
包。它允許存儲任意類型的對象(包括null
),并且可以動態地增加和減少其容量。ArrayList
提供了快速的隨機訪問能力(即按索引訪問元素),但在列表中間插入或刪除元素的速度相對較慢,因為這可能需要移動現有元素。ArrayList
實現了List
接口,因此它支持所有的列表操作,如添加、刪除、清空列表以及支持迭代器等。由于其內部是通過數組實現的,當元素被添加到ArrayList
中而數組容量不足時,其內部會自動擴容以容納更多的元素。
51、說說你對LinkedList的了解?
LinkedList
是Java中的一個雙向鏈表實現,屬于java.util
包。它允許存儲任意類型的對象,包括null
。與ArrayList
相比,LinkedList
提供了更高效的元素插入和刪除操作,因為這些操作通常只需改變節點的指針,而不需要移動其他元素。然而,LinkedList
在隨機訪問元素時性能較低,因為它需要從頭或尾開始遍歷鏈表來訪問特定索引的元素。
LinkedList
實現了List
接口,因此支持所有列表操作,如添加、刪除和遍歷元素。此外,LinkedList
還實現了Deque
接口,使其能夠被用作雙端隊列進行元素的入隊和出隊操作。由于其鏈表的特性,LinkedList
在實現棧、隊列或雙端隊列時是一個好的選擇。
52、說說你對Vector的了解?
Vector
是Java中的一個動態數組實現,屬于java.util
包。與ArrayList
類似,Vector
也支持動態擴容,可以根據需要增加和減少容量來存儲任意類型的對象。不同之處在于Vector
是同步的(synchronized),這意味著它是線程安全的。因此,在多線程環境中,當多個線程同時訪問Vector
實例時,它保證了數據的一致性和完整性。
由于其線程安全的特性,Vector
的性能可能會比非同步的ArrayList
稍低。Vector
提供了類似于ArrayList
的API,支持快速隨機訪問、元素的添加、刪除和遍歷等操作。然而,在新的Java應用中,通常推薦使用Collections.synchronizedList
或CopyOnWriteArrayList
來獲得線程安全的列表,而不是直接使用Vector
。
53、說說對Set的了解?
Set
是Java中的一個接口,屬于java.util
包,代表一個不包含重復元素的集合。它是Java集合框架(Java Collections Framework)的一部分,用于存儲一組唯一的元素,不保證元素的順序。Set
接口主要有以下幾個實現:
- HashSet:基于哈希表實現,提供快速的插入、查找和刪除操作,不保證元素的迭代順序。
- LinkedHashSet:基于哈希表和鏈表實現,維護元素的插入順序,性能略低于
HashSet
。 - TreeSet:基于紅黑樹實現,元素按照自然順序或自定義比較器排序,提供有序的集合操作。
Set
接口支持基本操作如添加、刪除元素以及判斷元素是否存在。由于Set
不允許重復元素,添加已存在的元素會被忽略。Set
常用于去除重復數據、集合運算(如并集、交集、差集)等場景。
54、說說你對Map的了解?
Map
是Java中的一個接口,表示一個鍵(Key)到值(Value)的映射。它不能包含重復的鍵,每個鍵最多只能映射到一個值。這個接口主要用于存儲鍵值對,鍵和值都可以是任意類型的對象,包括null
。Map
接口的實現類有多種,包括但不限于:
- HashMap:基于哈希表實現,提供快速的查找、插入和刪除操作,不保證映射的順序。
- LinkedHashMap:基于哈希表和鏈表實現,維護元素的插入順序或訪問順序。
- TreeMap:基于紅黑樹實現,按照鍵的自然順序或者構造時提供的
Comparator
進行排序。 - Hashtable:和
HashMap
類似,但是它是同步的,不允許鍵或值為null
。
Map
提供的操作包括添加、刪除鍵值對,檢查鍵或值是否存在,以及訪問鍵集、值集或鍵值對集。它是處理鍵值對數據的重要數據結構,廣泛應用于需要快速查找數據的場景。
55、Map的遍歷方式有哪些?
遍歷Map
的方法主要有以下幾種:
- 使用
**keySet()**
遍歷鍵集:先獲取Map
的所有鍵的集合,然后通過遍歷這些鍵來訪問每個鍵對應的值。 - 使用
**values()**
遍歷值集:直接獲取Map
中所有值的集合,遍歷這個集合可以訪問所有的值,但無法直接獲取對應的鍵。 - 使用
**entrySet()**
遍歷鍵值對:獲取Map
中所有鍵值對的集合,然后遍歷這個集合。每個元素都是Map.Entry
對象,可以通過它獲取鍵和對應的值。 - 使用Java 8的
**forEach**
方法:利用forEach
方法和Lambda表達式直接對鍵值對進行操作,更加簡潔高效。 - 使用迭代器(
**lterator**
)遍歷:通過keySet()
、values()
或entrySet()
獲取迭代器,然后使用迭代器進行遍歷。
56、說說你對HashMap的了解?
HashMap
是Java中基于哈希表實現的Map
接口的一個類。它存儲鍵值對,并允許使用nul1值和null
鍵。HashMap
不保證映射的順序;隨著時間的推移,這個順序可能會改變。它不是線程安全的,如果多線程同時訪問HashMap
且至少有一個線程修改了映射,則必須外部同步。HashMap
提供了常數時間的性能 (O(1)
)對于基本操作,如獲取和插入元素,假設哈希函數將元素適當地分散在桶中。它通過使用哈希碼為每個鍵值對分配一個桶來實現快速查找和插入操作。
57、說說你對TreeMap的了解?
TreeMap
是Java中基于紅黑樹實現的Map接口的一個類。它存儲鍵值對,并且按照鍵的自然順序(或者根據構造TreeMap
時提供的Comparator
所指定的順序)對鍵進行排序,從而保證了元素的有序性。TreeMap
不允許使用null
鍵(如果使用自然排序),但允許使用null值。與HashMap
相比,TreeMap
提供了一致的O(log n)
時間性能對于包含。個元素的映射的查找、插入和刪除操作,因為紅黑樹是一種自平衡的二叉查找樹。TreeMap
適合于需要按順序訪問鍵的場景,如實現范圍查找和排序操作。
58、什么是跨平臺性?原理是什么?
- 跨平臺性指的是Java程序能夠在不同的操作系統上運行而不需要做任何修改。這種能力基于"編寫一次,處處運行”(Write Once,Run Anywhere,WORA)的原則。
- Java的跨平臺性原理是通過Java虛擬機(JVM)實現的。具體來說:
- 編譯為字節碼:Java源代碼被編譯成一種中間形式的字節碼(.class文件),而不是直接編譯為特定平臺的機器碼。
- JVM執行字節碼:JVM是一個運行在宿主機操作系統上的軟件,它能夠加載字節碼并執行它們。每個平臺(如Windows、Linux、macOS)都有適配該平臺的JVM實現。
- 平臺無關性:由于JVM負責字節碼與特定平臺之間的交互,因此Java程序不需要為了在不同平臺上運行而做出任何修改。
59、什么是字節碼?采用字節碼的最大好處是什么?
- 字節碼是一種中間代碼(Intermediate Code)形式,主要用于Java和一些其他語言(如Scala)。它介于高級語言代碼和機器語言代碼之間,是由Java編譯器從Java源代碼編譯得到的,存儲于
.class
文件中。字節碼是獨立于機器的代碼,需要通過Java虛擬機(JVM)來解釋執行或編譯執行(即川編譯)。 - 采用字節碼的最大好處是跨平臺性。字節碼可以在任何安裝了兼容的JVM的平臺上運行,實現了“編寫一次,處處運行”(Write Once,RunAnywhere,WORA)的目標。這種設計極大地提高了軟件的可移植性,開發者無需為每個目標平臺重新編譯代碼,降低了開發和維護成本。
60、Java和C++的區別?
Java和C++主要區別包括:
- 內存管理:Java具有自動垃圾回收機制,而C++需要手動管理內存。
- 平臺獨立性:Java程序編譯為平臺無關的字節碼,通過JM在不同平臺上運行。C++編譯為特定平臺的機器碼,直接由操作系統執行。
- 運行環境:Java需要JVM作為運行時環境。C++程序直接在操作系統上運行,無需虛擬機。
- 語言特性:C++支持運算符重載、多重繼承和指針操作,提供更接近硬件的編程能力。Java設計上簡化了這些特性,以減少程序復雜性和提高安全性。
- 性能:C++通常提供更高的性能,適合系統級開發,如操作系統和游戲引擎。Java在跨平臺和網絡應用中更為流行,犧牲了一定的性能以獲得更高的移植性和開發效率。
- 錯誤處理:Java使用異常處理機制來處理錯誤,C++既支持異常處理也支持傳統的錯誤處理代碼。
- 標準庫:Java提供了豐富的標準庫,尤其是在圖形界面和網絡編程方面。C++標準庫主要集中在容器、算法和函數對象等。
61、switch 是否能作用在 byte上?是否能作用在long或String上?
- byte:可以,
switch
可以作用在byte
類型上。 - long:不可以,
switch
不能作用在long
類型上。 - String:可以,從Java 7開始,
switch
可以作用在String
類型上。
62、Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
Math.round(11.5)
等于12。Math.round(-11.5)
等于-11。
63、float f=3.4;這句代碼是否正確?
不正確。字面量3.4默認是double
類型的,直接賦值給float
變量會導致編譯錯誤。應該聲明為float
類型,方法是在數字后加上f
或F
,如:
float f = 3.4f;
64、short s1 = 1; s1 = s1+1; 有錯嗎?short s1 = 1; s1 += 1;有錯嗎?
- 對于
short s1 = 1; s1 = s1 + 1;
,有錯誤。因為1
是int
類型,s1+1
的結果也會被提升為int
類型,不能直接賦值給short
類型的變量s1
,除非進行強制類型轉換。 - 對于
short s1 = 1; s1 += 1;
,沒有錯誤。+=
操作符會自動處理類型轉換的問題,它會將右側表達式的結果轉換為左側變量的類型,然后再賦值,因此不會有編譯錯誤。
65、Java語言采用何種編碼方案?有何特點?
Java語言采用Unicode編碼方案。特點包括:
- 跨平臺一致性:確保Java程序在不同平臺上字符表示的一致性。
- 國際化支持:支持多種語言和字符集,方便構建國際化應用。
- 固定長度:在Java中,
char
類型用于表示一個16位的Unicode字符(UTF-16編碼)。
66、Java有哪些注釋?
Java有三種注釋方式:
- 單行注釋:使用
//
,注釋從//
開始到行末。 - 多行注釋:使用
/*
和*/
包圍,可以跨越多行。 - 文檔注釋:使用
/**
和*/
包圍,用于生成JavaDoc文檔。
67、&和&&的區別?
&
是位運算符,用于按位與操作;在布爾邏輯中,也可以作為邏輯與操作,但它會對兩邊的表達式都進行求值。
&&
是邏輯與運算符,僅用于布爾邏輯中。它具有短路特性,即如果第一個操作數為false
,則不計算第二個操作數。
68、final有什么用?
final
關鍵字在Java中有三種主要用途:
- 聲明常量:用于變量,表示變量的值一旦被初始化后就不能被改變。
- 防止繼承:用于類,表示類不能被繼承。
- 防止重寫:用于方法,表示方法不能被子類重寫。
69、this關鍵字有哪些用途?
this
關鍵字在Java中主要有以下用途:
- 引用當前對象:在方法內部,
this
用來引用當前對象的實例。 - 調用其他構造器:在構造器中,
this()
用來調用同一個類的其他構造器。 - 傳遞當前對象:可以將
this
作為參數傳遞給其他方法或構造器。 - 解決命名沖突:用
this
來區分成員變量和局部變量,特別是當它們名稱相同時。
70、super關鍵字有哪些用途?
super
關鍵字在Java中主要有以下用途:
- 訪問父類的成員:用
super
來訪問父類中被子類覆蓋(重寫)的方法和變量。 - 調用父類的構造器:在子類的構造器中,
super()
用來調用父類的構造器。如果沒有顯式調用,Java編譯器會自動插入對父類無參構造器的調用。 - 解決命名沖突:當子類和父類有同名的成員時,可以用
super
來引用父類的成員。
71、this與super的區別?
區別:
this
引用的是當前對象的實例,用于訪問當前類的成員(變量、方法)、調用當前類的其他構造器、或者將當前對象傳遞給其他方法。super
引用的是當前對象的父類實例,用于訪問父類的成員(變量、方法)和調用父類的構造器,特別是訪問被子類覆蓋的成員或調用父類的構造器。
簡而言之,this
用于指代當前類的上下文,而super
用于指代父類的上下文。
72、static存在的意義是什么?
static
存在的主要意義在于:
- 共享:
static
關鍵字用于聲明類級別的變量和方法,使得它們可以在沒有創建類實例的情況下被訪問。static
變量被類的所有實例共享。 - 工具方法:使用
static
方法可以創建無需對象實例即可調用的工具方法,例如Math
,sqrt(double)
。 - 內存管理:
static
變量和方法屬于類,而非類的實例,因此它們在內存中只有一份,有助于減少內存使用。 - 初始化代碼塊:通過
static
初始化代碼塊,可以在類被加載時執行初始化操作。
73、static的獨特之處是什么?
static
的獨特之處在于:
- 屬于類:
static
成員(變量和方法)屬于類本身,而非類的實例對象。 - 內存共享:所有實例共享同一個
static
變量,static
方法可以在沒有類實例的情況下直接通過類名調用。 - 初始化時機:
static
變量和static
代碼塊在類加載到JVM時僅初始化一次。 - 無需實例:可以不創建對象實例而直接使用類名訪問
static
成員。 - 全局變量:可以用作跨實例共享的全局變量。
- 工具方法:
static
方法常用作工具或幫助方法,如Math
類中的方法。
74、static應用場景有哪些?
static
關鍵字的應用場景包括:
- 常量定義:使用
static final
定義類級別的常量。 - 工具/幫助方法:不依賴于對象狀態的方法,如數學計算或工具方法,可以聲明為
static
。 - 單例模式:使用
static
變量存儲類的單一實例。 - 全局狀態或資源:共享在所有實例之間的資源或狀態,如配置信息。
- 靜態初始化代碼塊:用于初始化類級別的資源或執行靜態變量的初始化。
- 靜態內部類:不需要外部類實例就可以創建的內部類,適合作為工具或輔助類。
75、static使用注意事項有哪些?
使用static
時的注意事項包括:
- 內存管理:
static
變量存儲在靜態區,隨類的加載而加載,隨類的消失而消失,過多使用可能增加內存負擔。 - 線程安全:
static
變量如果被多個線程訪問,需要考慮同步機制以避免線程安全問題。 - 生命周期:
static
成員的生命周期長于任何對象實例,它們在程序啟動時被初始化,程序結束時被銷毀。 - 訪問限制:
static
方法內不能直接訪問非靜態成員。 - 設計考慮:不應濫用
static
,應當僅在表示類級別的共享數據或行為時使用。 - 測試難度:靜態方法和靜態狀態可能增加單元測試的難度,因為它們不易被模擬或重置。
76、break,continue,return 的區別及作用?
- break:
- 作用:立即退出最近的循環(
for
、while
、do-while
)或者switch
語句。 - 區別:只影響一個循環或
switch
語句,不會退出方法。
- 作用:立即退出最近的循環(
- continue:
- 作用:立即跳過當前迭代,進入下一次循環的迭代。
- 區別:僅用于循環體內,不會影響循環外的代碼或退出循環,只是提前結束當前的迭代。
- return:
- 作用:退出當前方法,并可選擇返回一個值(對于非
void
方法)。 - 區別:
return
不僅能結束循環,還能結束整個方法的執行,并將控制權交回方法被調用的地方。如果方法聲明了返回類型,return
后應跟一個返回值。
- 作用:退出當前方法,并可選擇返回一個值(對于非
簡而言之,break
用于完全結束循環或switch
語句,continue
用于結束當前迭代進入下一次循環,而return
用于結束整個方法的執行。
77、在Java中如何跳出當前的多重嵌套循環?
- 可以通過使用帶標簽的
break
語句來跳出當前的多重嵌套循環。 - 首先給外層循環設置一個標簽,然后在需要跳出循環的地方使用
break
語句并指定該標簽。示例如下:
outerloop: //標簽
for(int i=0;i<10; i++) {for(int j=0;j<10; j++) {if(someCondition) {break outerLoop; //跳出外層循環}}
}
在這個例子中,如果滿足someCondition
條件,則通過break outerLoop;
語句跳出名為outerLoop
的外層循環。
78、面向對象的特征有哪些方面?
面向對象編程(OOP)的主要特征包括:
- 封裝:隱藏對象的內部細節,只暴露必要的操作接口。
- 繼承:允許新的類繼承現有類的屬性和方法。
- 多態性:允許不同類的對象對同一消息做出響應,但表現出不同的行為(例如,方法的重載和重寫)。
- 抽象:將復雜的現實問題抽象成簡單的模型,只關注與當前目標相關的部分。
79、什么是多態機制?
多態機制是面向對象編程中的一個核心概念,允許不同類的對象對同一消息(方法調用)作出不同的響應。多態主要有兩種形式:
- 編譯時多態(靜態多態):通過方法重載實現,同一個類中存在多個同名方法,但參數列表不同。
- 運行時多態(動態多態):通過方法重寫實現,子類重寫父類方法。在程序運行時,根據對象的實際類型來調用相應的方法。
80、java多態的實現方式?
Java中多態的實現主要依賴于以下三個機制:
- 繼承:子類繼承父類的方法和屬性,提供基礎的類層次結構。
- 重寫(Override):子類可以重寫父類中的方法,提供具有相同名稱和參數列表的新實現。運行時多態通過方法重寫實現,JVM在運行時決定要調用的具體方法。
- 向上轉型(Upcasting):在多態中,父類引用可以指向子類對象。這使得在運行時,可以通過父類引用調用實際子類的重寫方法,而編譯器只檢查父類引用的方法。
81、說說面向對象編程的五大基本原則
面向對象編程的五大基本原則,簡稱為SOLID原則,包括:
- 單一職責原則(Single Responsibility Principle,SRP):一個類應該只有一個引起它變化的原因。
- 開閉原則(Open/Closed Principle,OCP):軟件實體應當對擴展開放,對修改封閉。
- 里氏替換原則(Liskov Substitution Principle,LSP):子類應該能夠替換它們的基類。
- 接口隔離原則(Interface Segregation Principle,ISP) :客戶端不應該被迫依賴于它們不使用的接口。
- 依賴倒置原則( Dependency Inversion Principle,DIP):高層模塊不應該依賴低層模塊,它們都應該依賴于抽象;抽象不應該依賴于細節,細節應該依賴于抽象。
82、說說抽象類和接口的異同點?
抽象類和接口在Java中都用來定義抽象類型,它們有以下主要異同點:
相同點:
- 都不能被實例化。
- 都可以包含抽象方法,即沒有實現的方法。
不同點:
- 抽象類:
- 可以包含具有實現的方法。
- 可以包含成員變量。
- 一個類只能繼承一個抽象類。
- 可以有構造方法。
- 抽象方法可以有任何訪問修飾符。
- 接口:
- Java 8之前,接口中的方法都是抽象的,不能有實現(Java 8后,接口可以包含默認和靜態方法)。
- 接口中的變量默認都是
public static final
的。 - 一個類可以實現多個接口。
- 沒有構造方法。
- 接口中的方法默認是
public
的。
抽象類用于表示"is-a"關系,用于類的繼承;接口更多地用于表示"has-a"能力,或特定的行為契約。
83、普通類與抽象類有什么區別?
區別如下:
- 實例化:普通類可以被直接實例化,而抽象類不能被實例化。
- 包含抽象方法:抽象類可以包含抽象方法(即沒有具體實現的方法),普通類不能包含抽象方法。
- 目的:普通類主要用于創建對象和實現功能,而抽象類主要用于作為其他類的基類,定義共有的抽象方法,強制子類實現這些方法。
- 構造方法:盡管抽象類不能被實例化,它們仍然可以有構造方法,這個構造方法可以被子類通過
super
關鍵字調用。 - 使用場景:當你有一個包含方法實現的類時,使用普通類;當你想要定義一個模板類,其中包含一些方法聲明但不實現(留給子類實現)時,使用抽象類。
84、抽象類能使用 final修飾嗎?
不能,抽象類不能使用final
修飾。因為final
修飾的類不能被繼承,而抽象類的目的是為了被其他類繼承并實現其抽象方法。這兩個修飾符的目的相互矛盾,所以不能同時使用。
85、創建一個對象用什么關鍵字?對象實例與對象引用有何不同?
創建對象使用new
關鍵字。例如,new ClassName()
會創建ClassName
類型的一個對象實例。
對象實例與對象引用的區別在于:
- 對象實例:是通過使用
new
關鍵字創建的,它在內存中占有實際的空間,保存著對象的狀態(屬性值)和行為(方法)。 - 對象引用:是指向對象實例的變量。引用本身并不存儲對象實例的實際數據,而是存儲了對象實例在內存中的地址。通過引用,我們可以訪問和操作對象實例。
簡而言之,對象實例是具體的數據和方法的集合,而對象引用是一個指向那些數據和方法所在內存地址的變量。
86、成員變量與局部變量有什么區別?
區別主要包括:
- 聲明位置:成員變量聲明在類中,而局部變量聲明在方法內、方法參數或者代碼塊內。
- 生命周期:成員變量的生命周期與對象的生命周期一致,而局部變量的生命周期隨著方法或代碼塊的執行結束而結束。
- 初始值:成員變量有默認初始值(例如,int的默認值為0,對象引用的默認值為null),局部變量沒有默認初始值,必須先聲明、賦值后才能使用。
- 訪問修飾符:成員變量可以使用訪問修飾符(如public,private等),控制其訪問級別;局部變量不可以使用訪問修飾符。
- 作用范圍:成員變量的作用范圍是整個類內部,局部變量的作用范圍限于聲明它的方法或代碼塊內部。
87、在Java中定義一個無參的默認構造方法的作用是什么?
主要作用是:
- 提供對象實例化的能力:如果一個類中沒有顯式地定義任何構造方法,Java編譯器會自動提供一個默認的無參構造方法。但是,如果類中定義了至少一個構造方法(無論是否有參數),編譯器不會提供默認構造方法。因此,手動定義一個無參構造方法確保了類可以被實例化,即使類中還有其他帶參數的構造方法。
- 在子類構造方法中的調用:在繼承關系中,子類的構造方法默認會調用父類的無參構造方法,如果父類中沒有顯式地定義這樣一個構造方法,而且也沒有其他構造方法,子類的構造會失敗。提供一個無參構造方法可以解決這個問題。
88、在調用子類構造方法之前先調用父類的無參數構造方法目的是什么?
在調用子類構造方法之前先調用父類的無參數構造方法的目的是為了確保父類的狀態被正確初始化。這一過程保證了在子類的構造方法執行之前,父類的成員變量和環境已經被設置好,確保繼承體系中的對象在使用之前處于一個有效和一致的狀態。
89、類的構造方法的作用是什么?若一個類沒有聲明構造方法,程序能正確執行嗎?
類的構造方法的作用是初始化對象,為對象成員變量設置初始值,并執行任何啟動構造對象時必須的步驟。如果一個類沒有聲明構造方法,程序仍然能正確執行,因為Java編譯器會為這個類自動提供一個默認的無參數構造方法(default constructor),這個構造方法沒有參數,體內也沒有具體執行語句。這保證了即使沒有顯式定義構造方法,也能實例化對象。
90、構造方法的特性有哪些?
- 名稱與類名相同:構造方法的名稱必須與類名完全一致。
- 沒有返回類型:構造方法不定義返回值類型,連
void
也不寫。 - 初始化對象:構造方法的主要作用是初始化新創建的對象。
- 自動調用:當通過
new
關鍵字創建類的新實例時,構造方法會自動被調用。 - 可以重載:一個類可以有多個構造方法,彼此之間通過參數列表的不同進行區分(這被稱為構造方法重載)。
- 不可以被
**static**
、**final**
、**abstract**
、**synchronized**
修飾:構造方法不能被這些關鍵字修飾,因為它們與構造方法的目的不兼容。
91、靜態變量(也稱為類變量)和實例變量有什么區別?
區別在于:
- 存儲位置:靜態變量存儲在類的靜態存儲區,所有實例共享同一個靜態變量;實例變量存儲在堆上,每個對象有自己的獨立副本。
- 訪問方式:靜態變量可以通過類名直接訪問,無需創建對象實例;實例變量只能通過對象實例訪問。
- 生命周期:靜態變量的生命周期從類被加載開始,到類被卸載結束;實例變量的生命周期從對象創建開始,到對象被垃圾回收結束。
- 用途:靜態變量通常用于類級別的常量或方法(如工具方法)中;實例變量用于存儲對象級別的狀態信息。
92、靜態變量(類變量)和普通變量(實例變量)有什么區別?
- 聲明:靜態變量使用
static
關鍵字聲明,普通變量不使用。 - 存儲:靜態變量存儲在類的靜態存儲區,屬于類級別,所有實例共享同一個靜態變量;普通變量存儲在堆內存的每個對象實例中,每個對象有自己的一份副本。
- 訪問:靜態變量可以通過類名直接訪問,也可以通過對象實例訪問(不推薦);普通變量只能通過對象實例訪問。
- 生命周期:靜態變量的生命周期從類被加載到類被卸載;普通變量的生命周期隨對象的創建和垃圾回收。
- 用途:靜態變量常用于表示類的公共狀態或常量;普通變量用于表示對象的屬性和狀態。
93、靜態方法和實例方法有什么區別?
- 聲明:靜態方法使用
static
關鍵字聲明,實例方法不使用。 - 調用:靜態方法可以通過類名直接調用,不需要創建對象實例;實例方法必須通過對象實例來調用。
- 訪問變量:靜態方法只能直接訪問類的靜態變量和靜態方法;實例方法可以訪問類的靜態變量、靜態方法以及通過對象實例訪問非靜態變量和方法。
- 用途:靜態方法通常用于執行不依賴于對象實例的操作;實例方法用于執行與對象實例相關的操作,可以操作和修改對象實例的狀態。
- 重寫:靜態方法不能被重寫,但可以被隱藏;實例方法可以被重寫。
94、在一個靜態方法內調用一個非靜態成員為什么是非法的?
在一個靜態方法內調用一個非靜態成員是非法的,因為靜態方法屬于類本身,而不依賴于任何特定的對象實例來執行。非靜態成員(包括變量和方法)需要依賴于對象的實例,因為它們可能訪問或修改對象的狀態,而在靜態上下文中沒有this
實例引用可用來指向當前對象,因此無法確定要操作的具體對象實例。簡而言之,靜態方法無法確定非靜態成員屬于哪個對象的實例。
95、什么是方法的返回值?返回值的作用是什么?
方法的返回值是方法完成其操作后提供的輸出。方法執行結束時,可以將一個值傳回給調用者。返回值的數據類型在方法聲明時指定,且方法必須返回聲明類型的值(特殊情況是void類型,表示方法不返回任何值)。
返回值的作用是允許方法將結果傳遞回給調用者。這使得程序可以利用方法執行的結果進行進一步的操作或決策,增加了程序的模塊性和復用性。例如,一個計算兩個數和的方法會返回這兩個數的和,調用者可以使用這個返回值進行其他操作。
96、內部類是什么?
內部類是定義在另一個類內部的類。它可以訪問外部類的所有成員(包括私有成員),主要用于處理外部類中的某些特定問題,增強封裝性。
97、內部類有哪些類型?
內部類主要有四種類型:
- 成員內部類:類似于類的成員變量,可以訪問外部類的所有成員。
class OuterClass {class MemberInnerClass{}
}
- 靜態內部類:使用static修飾的內部類,不能直接訪問外部類的非靜態成員。
class OuterClass {static class StaticInnerClass{}
}
- 局部內部類:在方法或作用域內部定義的類。
class OuterClass {void someMethod() {class LocalInnerClass {}}
}
- 匿名內部類:沒有類名稱,用于創建一次性使用的類實例。
new Thread(new Runnable() {@Overridepublic void run() {// code}
}).start();
98、內部類哪些優缺點?
使用內部類的優缺點包括:
優點:
- 封裝性:內部類可以直接訪問外部類的成員,包括私有成員,提高了封裝性。
- 邏輯性:如果一個類只在另一個類的內部使用,將其作為內部類定義可以使代碼組織更加邏輯性強。
- 增強可讀性和維護性:將內部類放在使用它們的類的內部,可以使代碼更加易于理解和維護。
- 實現多繼承:通過內部類可以實現對多個類的繼承,避免了Java單繼承的限制。
缺點:
- 增加復雜性:內部類增加了代碼結構的復雜性,對初學者來說可能不易理解。
- 編譯生成多個
**.class**
文件:每個內部類都會編譯生成一個單獨的.class
文件,增加了部署應用時的復雜度。 - 可能導致內存泄漏:非靜態內部類會隱式持有外部類的引用,如果不當使用可能導致內存泄漏問題。
99、內部類有哪些應用場景?
- 封裝功能模塊:當某個功能只在一個類內部使用時,使用內部類可以更好地封裝這個功能。
- 實現接口而不暴露給外部:可以創建內部類來實現接口或繼承某個類,而不使外部類的類型發生改變。
- 回調函數和事件處理:在圖形用戶界面(GUI)編程中,匿名內部類常用于事件監聽器(listener)和回調函數,使代碼更簡潔。
- 迭代器模式:在實現迭代器模式時,可以使用內部類來實現
Iterator
接口,隱藏迭代邏輯。 - 減少代碼冗余:如果多個類有相似的功能,可以通過內部類來共享這部分代碼,減少冗余。
- 策略模式和工廠模式:在設計模式中,特別是策略模式和工廠模式,使用內部類可以提供更好的封裝和數據隱藏。
100、局部內部類和匿名內部類訪問局部變量的時候,為什么變量必須要加上final?
局部內部類和匿名內部類訪問局部變量時,變量必須要加上final
(在Java 8及之后版本,即使不顯式聲明為final
,也要求局部變量事實上不被修改,稱為"effectively final"),這是因為:
- 生命周期差異:當局部內部類或匿名內部類的對象存在時,方法中的局部變量可能已經退出作用域并被銷毀。為了使內部類仍然可以訪問這些變量,它們的值在創建內部類實例時被拷貝到內部類中。
- 數據一致性:如果局部變量被允許修改,那么內部類中拷貝的值和原始變量的值可能會不一致。將變量聲明為
final
或確保其為"effectively final"可以避免這種不一致性,確保數據的穩定性和一致性。
101、構造器是否可被重寫?
不能,構造器(constructor)不能被重寫(override)。構造器是用于初始化一個新對象的特殊類型的方法,而重寫涉及到兩個方法間的多態性,這在父類和子類之間的方法中才會發生。不過,構造器可以被重載(overload),即在同一個類中可以有多個構造器,它們的參數列表不同。
102、HashSet如何檢查重復?
HashSet
檢查重復元素主要依賴于元素的hashCode()
方法和equals()
方法:
- 當向
HashSet
添加元素時,首先調用元素的hashCode()
方法計算其哈希碼,以此確定元素存儲在內部哈希表的哪個位置(即哪個桶)。 - 如果計算得到的哈希碼在哈希表中沒有對應的條目,則直接將元素存儲在該位置,認為沒有重復。
- 如果該哈希碼對應的位置已經有元素存在(即發生哈希碰撞),則調用元素的
equals()
方法與該位置上的每個元素逐一比較。如果equals()
方法返回true
,則判斷為重復元素,不會添加到HashSet
中;如果equals()
返回false
,則將新元素添加到該位置。
因此,HashSet
檢查重復的效率高低直接受到其元素hashCode()
方法的實現和equals()
方法的實現質量的影響。
103、兩個對象的hashCode()相同,則equals()也一定為true對嗎?
不對。兩個對象的hashCode()
相同,只意味著它們被存放在哈希表的同一個桶中,但并不意味著它們通過equals()
方法比較時一定為true
。hashCode()
相同是發生碰撞的情況,需要進一步通過equals()
方法來檢查兩個對象是否真正相等。
104、說說hashCode和equals方法的關系?
hashCode()
和 equals()
方法之間的關系體現在以下兩個主要原則上:
- 一致性:如果兩個對象通過
equals()
方法比較相等,則這兩個對象的hashCode()
方法必須返回相同的整數值。 - 不一定反向成立:如果兩個對象的
hashCode()
方法返回相同的值,它們通過equals()
方法比較不一定相等。
這種設計是為了確保對象可以正確地存儲在基于哈希的集合中,如HashSet
、HashMap
等,保證集合的正確性和性能。
105、為什么重寫equals時必須重寫hashCode方法?
重寫equals()
時必須重寫hashCode()
方法,以維護hashCode()
與equals()
方法之間的一致性約定:如果兩個對象相等(即equals()
方法返回true
),則它們的哈希碼(hashCode()
方法返回的值)也必須相等。這個約定確保了基于哈希的集合(如HashSet
、HashMap
)能夠正確地處理對象,維護集合的性能和正確性。如果不這樣做,相等的對象可能具有不同的哈希碼,導致無法在集合操作中正確識別對象,例如,可能會在HashSet
中添加重復元素,或在HashMap
中找不到鍵的正確映射。
106、說說你對hashCode()的了解?
hashCode()
是Java中 Object
類的一個方法,它返回對象的哈希碼,即一個整數值。這個方法主要用于優化基于哈希表的集合(如HashMap
、HashSet
、HashTable
)的性能。在這些集合中,hashCode()
用于確定對象存儲的位置(即哈希桶的索引),從而加快搜索、插入和刪除操作的速度。每個對象的哈希碼是根據對象的內部狀態計算出來的,且在程序執行期間不應該改變。理想情況下,不同的對象應有不同的哈希碼,但不同對象產生相同哈希碼的情況(哈希沖突)也是允許的。
107、為什么要有hashCode?
hashCode
存在的原因是為了提高基于哈希表的數據結構(如HashMap
、HashSet
、HashTable
)的性能。通過將對象轉換成哈希碼(一個整數值),hashCode
允許快速定位對象應該存儲的桶位置,從而實現快速插入、查找和刪除操作。理想情況下,不同的對象會產生不同的哈希碼,減少哈希沖突,確保數據結構的高效性。
108、對象相等和引用相等有什么不同?
對象的相等通常指的是兩個對象的狀態或內容相同,這通過重寫equals()
方法來判斷。而引用相等指的是兩個引用變量指向內存中的同一個對象地址。簡而言之,對象相等關注的是內容是否相同,而引用相等關注的是是否是同一個對象。
109、當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里是值傳遞還是引用傳遞?
Java中是值傳遞。當對象作為參數傳遞給方法時,傳遞的是對象引用的副本(值)。這意味著方法內部可以通過這個引用副本改變對象的屬性,但不能改變外部引用本身指向的對象。
110、為什么Java中只有值傳遞?
Java中只有值傳遞是因為無論是基本數據類型還是對象,方法調用時傳遞的都是變量的副本。對于基本數據類型,這個副本是實際的值;對于對象,這個副本是對象引用的值(即內存地址的副本)。這樣設計的目的是為了保護數據,避免原始數據被無意或惡意地修改,從而增強程序的安全性和可靠性。
111、值傳遞和引用傳遞有什么區別?
值傳遞(Pass by Value):方法調用時,實參向形參傳遞的是值的副本。對副本的任何修改不會影響到原始數據。
引用傳遞(Pass by Reference):方法調用時,實參向形參傳遞的是引用(或內存地址)的副本。通過這個引用的副本,方法可以修改原始對象所指向的數據。
區別在于,值傳遞不會影響原始數據,而引用傳遞允許方法修改原始對象。
112、JDK中常用的包有哪些?
- java.lang:包含語言基礎類,如
String
、Math
、System
等。 - java.util:包含集合框架、日期時間類、事件模型、隨機數生成等工具類。
- java.io:提供輸入輸出(I/O)相關的類和接口,用于讀寫數據。
- java.net:包含執行與網絡相關的操作的類和接口,如URL處理、套接字編程。
- java.sql:提供了進行JDBC數據庫編程的類和接口。
- java.awt:抽象窗口工具包,用于構建圖形用戶界面(GUI)和圖像處理。
- javax.swing:提供了一套更加復雜的GUI組件庫,建立在AWT之上。
- java.nio:新輸入輸出,提供了高速的、可伸縮的I/O操作。
113、java和javax有什么區別?
java
和 javax
包的區別主要在于它們的歷史和用途上。java
包是Java的核心API的一部分,提供了最基礎的類和接口,如集合框架、線程、異常處理等。javax
包最初被用來作為Java核心API的擴展,包含了額外的功能和工具,如Swing GUI工具包、XML處理、JavaMail等。隨著時間的發展,javax
包中的一些API變得非常重要,但基本上,java
包含核心功能,而javax包含擴展功能或補充API。
114、java 中10流分為幾種?
分為四種主要類型:字節輸入流、字節輸出流、字符輸入流和字符輸出流。
115、Files的常用方法都有哪些?
copy(Path source, Path target, CopyOption... options)
:復制文件或目錄。move(Path source, Path target, CopyOption... options)
:移動或重命名文件或目錄。delete(Path path)
:刪除文件或目錄。exists(Path path, LinkOption... options)
:檢查文件或目錄是否存在。size(Path path)
:返回文件的大小。createFile(Path path, FileAttribute<?>... attrs)
:創建一個新文件。createDirectory(Path path, FileAttribute<?>... attrs)
:創建一個目錄。createDirectories(Path path, FileAttribute<?>... attrs)
:創建一個目錄及其所有父目錄。newBufferedReader(Path path)
:打開文件以進行讀取。newBufferedWriter(Path path, OpenOption... options)
:打開或創建文件以進行寫入。readAllLines(Path path)
:讀取文件的所有行
到一個列表。
write(Path path, Iterable<? extends CharSequence> lines, OpenOption... options)
:將多行寫入文件。isDirectory(Path path, LinkOption... options)
:檢查是否為目錄。isRegularFile(Path path, LinkOption... options)
:檢查是否為普通文件。setLastModifiedTime(Path path, FileTime time)
:設置文件最后修改時間。
116、什么是反射機制?
Java中的反射機制是一種動態機制,允許程序在運行時訪問、檢測和修改它本身的類和對象的信息。它使得Java程序能夠動態加載類、獲取類的元數據(如類的方法、字段、構造器等)、調用對象的方法、修改對象的字段,即便在編譯時這些類、方法、字段是未知的。反射主要通過java.lang.Class
類以及java.lang.reflect
包中的Method
、Field
、Constructor
等類實現。
117、Java反射機制有什么優缺點?
優點:
- 靈活性:允許程序在運行時動態加載和操作對象,提高了程序的靈活性和擴展性。
- 泛型擦除的解決:可以用于訪問在編譯時期被泛型擦除的類型信息。
- 框架開發:是許多Java框架(如 Spring,Hibernate)的基礎,用于實現依賴注入、ORM等功能。
缺點:
- 性能開銷:反射調用比直接代碼調用慢,因為它需要進行類型檢查和訪問控制檢查。
- 安全風險:允許運行時修改程序行為可能會引入安全漏洞。
- 破壞封裝性:可以訪問私有成員和方法,破壞了類的封裝性。
- 代碼復雜性:使代碼更難理解和維護,尤其是對于非反射機制的使用者。
118、靜態編譯和動態編譯的區別是什么?
區別主要在于編譯時機和執行效率:
- 靜態編譯:在程序運行前,源代碼被編譯成機器語言代碼。這種編譯一次完成,生成的可執行文件直接在硬件上運行,通常提供更高的執行效率和更好的優化,但缺乏靈活性。
- 動態編譯:在程序運行時,源代碼或字節碼被即時(JIT)編譯成機器語言。這允許更高的靈活性和平臺獨立性,可以針對當前運行環境進行優化,但在編譯過程中會增加額外的性能開銷。
119、反射機制的應用場景有哪些?
- 框架開發:如Spring的依賴注入和Hibernate的ORM映射,通過反射自動裝配對象和管理數據庫操作。
- 插件化或模塊化平臺:動態加載和運行第三方開發的插件或模塊。
- 單元測試框架:如JUnit使用反射來識別和執行測試方法。
- 動態代理:在運行時創建代理對象,用于攔截原始對象的方法調用,實現如AOP (面向切面編程)的功能。
- 配置解析:解析并應用配置文件中的設置,如通過反射根據配置實例化類和設置屬性。
- 泛型類型擦除的補救:通過反射獲取和操作泛型類型的實際參數類型。
120、Java獲取反射的三種方法?
- 使用
**Class.forName()**
方法:傳遞類的全限定名(包括包名)作為字符串參數,適用于動態加載類。
Class<?> c = Class.forName("java.lang.String"):
- 通過
**.class**
語法:直接在類名后使用.class
獲得對應的Class
對象,適用于編譯時已知的類。
Class<?> c = String.class;
- 使用對象的
**.getClass()**
方法:對于任意對象,調用其.getClass()
方法獲取其運行時類的Class
對象,適用于已有對象實例。
String s = "example";
Class<?> c = s.getClass();
121、字符型常量和字符串常量的區別是什么?
字符型常量(Character Constant)是單個字符,使用單引號(')括起來,如'A'
,在Java中占用2字節,表示一個單一的Unicode字符。
字符串常量(String Constant)是一系列字宇符的集合,使用雙引號(")括起來,如"Hello"
,在Java中是String
類型的對象,可以包含零個或多個字符,占用的內存大小取決于字符串中字符的數量。
122、什么是字符串常量池?
字符串常量池(String Constant Pool)是Java堆內存的一部分,用于存儲唯一的字符串常量。這種機制允許JVM節省內存空間,通過確保所有相同的字符串常量都指向內存中的同一個位置。當創建字符串字面量時(例如,通過直接賦值String s = "hello";
),JVM首先檢查字符串常量池中是否存在相同內容的字符串。如果存在,就返回對該字符串的引用;如果不存在,就在池中創建一個新的字符串,并返回其引用。這種機制不適用于new String()
創建的字符串對象。
123、String 是最基本的數據類型嗎?
不是,String
在Java中是一個類,屬于引用數據類型,不是基本數據類型。Java中的基本數據類型包括 byte
、short
、int
、long
、float
、double
、boolean
和char
。
124、String有哪些特性?
- 不可變性:字符串一旦創建,其值就不能被改變。
- 常量池:字符串常量池幫助節省內存,使得相同內容的字符串共享內存。
- 線程安全:由于不可變性,字符串在Java中是線程安全的。
- 支持字符串拼接:可以使用
+
操作符進行字符串拼接,但每次拼接都會生成新的字符串對象。 - 支持
**intern()**
方法:可以確保字符串常量池中只有一個唯一的字符串實例。 - 實現了
**Serializable**
**和 ****Comparable**
接口:使得字符串可以序列化,并且可以自然地排序。
125、String為什么是不可變的嗎?
主要因為以下幾個原因:
- 安全性:字符串經常作為參數傳遞給網絡連接和文件路徑等敏感操作。不可變性保證了值不會被更改,確保安全性。
- 同步性:由于不可變,
String
可以在多線程環境下安全使用,無需額外的同步操作。 - 性能:不可變性使得字符串常量池的實現成為可能,相同的字符串宇面量可以共享相同的內存地址,節省內存。
- 哈希碼緩存:由于
String
的內容不會改變,其哈希碼可以被緩存,這在使用字符串作為HashMap
或HashSet
的鍵時可以提高性能。
126、String有什么辦法可以變成可變的嗎?
可以通過使用StringBuilder
或 StringBuffer
類使字符串變得可變。這兩個類提供了用于修改字符串的API,如追加(append
)、插入(insert
)、刪除( delete
)等操作。StringBuilder
通常用于單線程環境下,因為它不是線程安全的,但其性能比StringBuffer
更優,后者是線程安全的,適用于多線程環境。使用這些類可以構建和修改字符串,然后通過調用它們的toString()
方法將其轉換回不可變的String
對象。
127、String 類可以被繼承嗎?
不可以,String
類在Java中被聲明為final
,因此不能被繼承。
128、String str="i"與 String str=new String(“i”)一樣嗎?
不一樣。String str = "i";
創建的字符串會檢查字符串常量池中是否存在內容為"i"的字符串,如果存在,則直接返回其引用;如果不存在,會在常量池中創建一個然后返回其引用。而String str = new String("i");
會在堆內存中創建一個新的String
對象,即使常量池中已存在內容為"i"的字符串,也會創建新的對象,不會使用常量池中的對象。
129、String s = new String(“xyz”);創建了幾個字符串對象?
可能創建了兩個字符串對象:一個在字符串常量池中(如果常量池中尚不存在字面量"xyz"),另一個是通過new String("xyz")
在堆上顯式創建的。
130、如何將字符串反轉?
可以使用StringBuilder
或StringBuffer
的reverse()
方法來反轉字符串:
String original = "example";=;
String reversed = new StringBuilder(original).reverse().toString();
這段代碼創建了一個StringBuilder
對象,初始化為原始字符串,然后調用reverse()
方法將其反轉,最后通過toString()
方法將其轉換回字符串。
131、數組有沒有length()方法? String 有沒有length()方法?
數組沒有length()
方法,它有一個length
屬性用來獲取數組的長度。
String
有一個length()
方法用來獲取字符串的長度。
132、String 類的常用方法都有那些?
length()
:返回字符串的長度。charAt(int index)
:返回指定索引處的字符。subString(int beginIndex, int endIndex)
:返回一個新字符串,它是此字符串的一個子字符串。concat(String str)
:將指定字符串連接到此字符串的末尾。indexOf(int ch)
,indexOf(String str)
:返回指定字符或字符串第一次出現的位置。lastIndexOf(int ch)
,lastIndexOf(String str)
:返回指定字符或字符串最后一次出現的位置。equals(0bject anObject)
:比較此字符串與指定對象。equalsIgnoreCase(String anotherString)
:與equals
方法類似,忽略大小寫差異。startsWith(String prefix)
:測試此字符串是否以指定的前綴開始。endsWith(String suffix)
:測試此字符串是否以指定的后綴結束。tolowerCase()
:使用默認語言環境的規則將此String
中的所有字符都轉換為小寫。toUpperCase()
:使用默認語言環境的規則將此String
中的所有字符都轉換為大寫。trim()
:返回字符串的副本,忽略前導空白和尾部空白。replace(char oldChar, char newChar)
、replace(CharSequence target, CharSequence replacement)
:返回一個新的字符串,它是通過用新字符替換此字符串中出現的所有舊字符或子字符串得到的。split(String rege)
:根據給定正則表達式的匹配拆分此字符串。valueOf(各種類型)
:返回各種類型數據的字符串表示形式。
133、在使用 HashMap 的時候,用String 做 key有什么好處?
使用String
作為HashMap
的key
有以下好處:
- 不可變性:
String
的不可變性保證了key
的唯一性和一致性,確保了HashMap
中key
的哈希值不會改變。 - 哈希碼緩存:
String
類內部緩存了其哈希碼,當再次使用相同的String
作為key
查找時,可以快速訪問,提高了查找效率。 - 天然的唯一性和等價性:
String
重寫了equals()
和hashCode()
方法,保證了只要內容相同,無論是哪個String
實例,都能正確地映射到相同的值,這使得使用String
作為key
時,HashMap
的行為非常直觀和可預測。
134、String為什么是不可變的?
- 安全性:字符串經常作為參數傳遞給網絡連接和文件路徑等敏感操作。不可變性保證了值不會被更改,確保安全性。
- 同步性:由于不可變,
String
可以在多線程環境下安全使用,無需額外的同步操作。 - 性能:不可變性使得字符串常量池的實現成為可能,相同的字符串字面量可以共享相同的內存地址,節省內存。
- 哈希碼緩存:由于
String
的內容不會改變,其哈希碼可以被緩存,這在使用字符串作為HashMap
或HashSet
的鍵時可以提高性能。
135、String和StringBuffer、 StringBuilder的區別是什么?
- String:不可變的字符序列,每次修改都會生成新的
String
對象,適用于少量的字符串操作。 - StringBuffer:可變的字符序列,線程安全,適用于多線程環境下的字符串操作,性能略低于
StringBuilder
由于同步開銷。 - StringBuilder:可變的字符序列,非線程安全,適用于單線程環境下的字符串操作,性能高于
StringBuffer
因為省去了同步開銷。
136、Integer a=127與Integer b=127相等嗎?
是的,Integer a = 127
與Integer b = 127
相等。在Java中,整數值在-128
到127
之間的Integer
實例會被緩存,因此a
和b
引用的是同一個Integer
對象。
137、Integer a=128與Integer b=128相等嗎?
不相等。在Java中,超過-128
到127
這個范圍的整數不會被緩存,因此Integer a = 128
和 Integer b = 128
會指向不同的Integer
對象實例。使用==
比較時,比較的是引用,不是值。