撩課-Java面試題合輯1-50題
1.簡述JDK、JRE、JVM?
一、JDK JDK(Java Development Kit) 是整個JAVA的核心, 包括了Java執行環境(Java Runtime Envirnment), 一堆Java工具(javac/java/jdb等) 和Java基礎的類庫(即Java API 包括rt.jar)。 JDK是java開發工具包, 基本上每個學java的人都會先在機器 上裝一個JDK, 那他都包含哪幾部分呢? 在目錄下面有 六個資料夾、 一個src類庫原始碼壓縮包、 和其他幾個宣告檔案。 其中,真正在執行java時起作用的 是以下四個資料夾:bin、include、lib、 jre。 有這樣一個關係,JDK包含JRE,而JRE包 含JVM。 bin:最主要的是編譯器(javac.exe) include:java和JVM互動用的標頭檔案 lib:類庫 jre:java執行環境 二、JRE JRE(Java Runtime Environment,Java執行環境) 包含JVM標準實現及Java核心類庫。 JRE是Java執行環境,並不是一個開發環境, 所以沒有包含任何開發工具(如編譯器和偵錯程式) JRE是指java執行環境。 光有JVM還不能成class的 執行, 因為在解釋class的時候 JVM需要呼叫解釋所需要的類庫lib。 ( jre裡有執行.class的java.exe) JRE ( Java Runtime Environment ), 是執行 Java 程式必不可少的 (除非用其他一些編譯環境編譯成.exe可執行檔案……) JRE的 地位就象一臺PC機一樣, 我們寫好的Win64應用程式需要作業系統幫 我們執行, 同樣的,我們編寫的Java程式也必須要JRE才能執行。 三、JVM JVM(Java Virtual Machine), 即java虛擬機器, java執行時的環境, JVM是一種用於計算裝置的規範, 它是一個虛構出來的計算機, 是通過在實際的計算機上模擬模擬 各種計算機功能來實現的。 針對java使用者, 也就是擁有可執行的.class檔案包(jar或者war)的使用者。 裡面主要包含了jvm和java執行時基本類庫(rt.jar)。 rt.jar可以簡單粗暴地理解為: 它就是java原始碼編譯成的jar包。 Java虛擬機器在執行位元組碼時, 把位元組碼解釋成具體平臺上的機器指令執行。 這就是Java的能夠“一次編譯, 到處執行”的原因。
2.JDK、JRE、JVM三者的有什麼聯絡和區別?
1.三者聯絡: JVM不能單獨搞定class的執行, 解釋class的時候JVM需要呼叫解釋所需要的類庫lib。 在JDK下面的的jre目錄裡面 有兩個資料夾bin和lib, 在這裡可以認為bin裡的就是jvm, lib中則是jvm工作所需要的類庫, 而jvm和 lib和起來就稱為jre。 JVM+Lib=JRE。 總體來說就是, 我們利用JDK(呼叫JAVA API)開發了屬於 我們自己的JAVA程式後, 通過JDK中的編譯程式(javac) 將我們的文字java檔案編譯成JAVA位元組碼, 在JRE上執行這些JAVA位元組碼, JVM解析這些位元組碼, 對映到CPU指令集或OS的系統呼叫。 2.三者區別: JDK和JRE區別: 在bin資料夾下會發現, JDK有javac.exe而JRE裡面沒有, javac指令是用來將java檔案編譯成class檔案的, 這是開發者需要的, 而使用者(只需要執行的人)是不需要的。 JDK還有jar.exe, javadoc.exe等等 用於開發的可執行指令檔案。 這也證實了一個是開發環境, 一個是執行環境。 b.JRE和JVM區別: JVM並不代表就可以執行class了, JVM執行.class還需要JRE下的lib類庫的支援, 尤其是rt.jar。
3、簡述Java程式編譯和執行的過程?
Java程式從原始檔建立到程式執行要經過兩大步驟: 1、原始檔由編譯器編譯成位元組碼(ByteCode); 2、位元組碼由java虛擬機器解釋執行。 因為java程式既要編譯同時 也要經過JVM的解釋執行, 所以說Java被稱為半解釋語言

第一步(編譯): 建立完原始檔之後, 程式先要被JVM中的java編譯器 進行編譯為.class檔案。 java編譯一個類時, 如果這個類所依賴的類還沒有被編譯, 編譯器會自動的先編譯這個所依賴的類, 然後引用。 如果java編譯器在指定的目錄下 找不到該類所依賴的類的 .class檔案 或者 .java原始檔, 就會報"Cant found sysbol"的異常錯誤。 編譯後的位元組碼檔案格式 主要分為兩部分: 常量池和方法位元組碼。 常量池記錄的是程式碼出現過的 (常量、類名、成員變數等) 以及符號引用(類引用、方法引用,成員變數引用等); 方法位元組碼中放的是各個方法的位元組碼。 第二步(執行): java類執行的過程大概分為兩個步驟: (1)類的載入 (2)類的執行。 需要說明的一點的是: JVM主要在程式第一次執行時主動使用類的時候, 才會立即去載入。 換言之, JVM並不是在執行時就會把所有使用到的類 都載入到記憶體中, 而是用到,不得不載入的時候, 才載入進來,而且只加載一次!
4、請說出八種基礎資料型別及位元組大小?
1. byte8位 2. short16位 3. int32位 4. long64位 5. float32位 6. double64位 7. boolean1位 8. char16位
5.說說&和&&的區別?
&和&&都是邏輯運算子, 都是判斷兩邊同時真則為真,否則為假; 但是&&當第一個條件不成之後, 後面的條件都不執行了, 而&則還是繼續執行, 直到整個條件語句執行完為止。
6.float型float f=3.4是否正確?
答: 不正確; 精度不準確, 應該用強制型別轉換, 如下所示:float f=(float)3.4
7.short s1 = 1; s1 = s1 + 1;有什麼錯? short s1 = 1; s1 += 1;有什麼錯?
short s1 = 1; s1 = s1 + 1; s1+1 運算結果是int型, 需要強制轉換型別; short s1 = 1; s1 += 1; 可以正確編譯,自動型別提升。
8.int 和 Integer 有什麼區別?
Java 提供兩種不同的型別: 引用型別和原始型別(或內建型別); int是java的原始資料型別, Integer是java為int提供的封裝類。 引用型別和原始型別的行為完全不同, 並且它們具有不同的語義。 引用型別和原始型別具有不同的特徵和用法, 它們包括:大小和速度問題, 這種型別以哪種型別的資料結構儲存, 當引用型別和原始型別 用作某個類的例項資料時所指定的預設值。 物件引用例項變數的預設值為 null, 而原始型別例項變數的預設值 與它們的型別有關。
9.在JAVA中,如何跳出當前的多重巢狀迴圈?
在最外層迴圈前加label標識, 然後用break:label方法即可跳出多重迴圈。 ok:while(true){ while(true){ break ok; } }
10.使用巢狀的for迴圈列印九九乘法表。
public class test { public static void main(String[] args) { for (int i = 1; i <= 9; i++) { for (int j = 1; j <= i; j++) { System.out.print(j + "*" + i + "=" + i * j + " "); } System.out.println(); } } }
ofollow,noindex">撩課Java+系統架構點選開始學習
11、面向物件的特徵有哪些方面
1.抽象: 抽象就是忽略一個主題中與當前目標無關的那些方面, 以便更充分地注意與當前目標有關的方面。 抽象並不打算了解全部問題,而只是選擇其中的一部分, 暫時不用部分細節。 抽象包括兩個方面, 一是過程抽象, 二是資料抽象。 2.繼承: 繼承是一種聯結類的層次模型, 並且允許和鼓勵類的重用, 它提供了一種明確表述共性的方法。 物件的一個新類可以從現有的類中派生, 這個過程稱為類繼承。 新類繼承了原始類的特性, 新類稱為原始類的派生類(子類), 而原始類稱為新類的基類(父類)。 派生類可以從它的基類那裡繼承方法和例項變數, 並且類可以修改或增加新的方法使之更適合特殊的需要。 3.封裝: 封裝是把過程和資料包圍起來, 對資料的訪問只能通過已定義的介面。 面向物件計算始於這個基本概念, 即現實世界可以被描繪成一系列完全自治、 封裝的物件, 這些物件通過一個受保護的介面訪問其他物件。 4. 多型性: 多型性是指允許不同類的物件對同一訊息作出響應。 多型性包括引數化多型性和包含多型性。 多型性語言具有靈活、抽象、行為共享、程式碼共享的優勢, 很好的解決了應用程式函式同名問題。
12.java 建立物件的幾種方式
採用new 通過反射 採用clone 通過序列化機制 前2者都需要顯式地呼叫構造方法。 造成耦合性最高的恰好是第一種, 因此你發現無論什麼框架, 只要涉及到解耦必先減少new的使用。
13.修飾符public,private,protected,以及不寫時的區別
修飾符 | 當前類 | 同一package | 子孫類 | 其他package |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private | √ | × | × | × |
不寫時預設為friendly/default
friendly許可權是java的預設許可權,也稱作包(package)訪問許可權
只要不加private、public、protect的
就是friendly訪問許可權,
所有的成員僅限同一個包內的成員訪問
14.String s = new String("xyz");建立了幾個String Object
兩個,一個字元物件,一個字元物件引用物件
15.Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math.round(11.5)==12; Math.round(-11.5)==-11; round方法返回與引數最接近的長整數, 引數加1/2後求其floor
16.Java有沒有goto?
java中的保留字,現在沒有在java中使用
17.Overload和Override的區別。Overloaded的方法是否可以改變返回值的型別
方法的重寫Overriding和過載Overloading是Java多型性的不同表現。 重寫Overriding是父類與子類之間多型性的一種表現, 過載Overloading是一個類中多型性的一種表現。 如果在子類中定義某方法與其父類有相同的名稱和引數, 我們說該方法被重寫 (Overriding)。 子類的物件使用這個方法時, 將呼叫子類中的定義, 對它而言, 父類中的定義如同被"遮蔽"了。 如果在一個類中定義了多個同名的方法, 它們或有不同的引數個數或有不同的引數型別, 則稱為方法的過載(Overloading)。 Overloaded的方法是可以改變返回值的型別
18.abstract class和interface有什麼區別
宣告方法的存在而不去實現它的類被叫做抽象類(abstract class), 它用於要建立一個體現某些基本行為的類, 併為該類宣告方法, 但不能在該類中實現該類的情況。 不能建立abstract 類的例項。 然而可以建立一個變數, 其型別是一個抽象類, 並讓它指向具體子類的一個例項。 不能有抽象建構函式或抽象靜態方法。 Abstract 類的子類為它們父類中的 所有抽象方法提供實現, 否則它們也是抽象類為。 取而代之,在子類中實現該方法。 知道其行為的其它類可以在類中實現這些方法 介面(interface)是抽象類的變體。 在介面中,所有方法都是抽象的。 多繼承性可通過實現這樣的介面而獲得。 介面中的所有方法都是抽象的, 沒有一個有程式體。 介面只可以定義static final成員變數。 介面的實現與子類相似, 除了該實現類不能從介面定義中繼承行為。 當類實現特殊介面時, 它定義(即將程式體給予)所有這種介面的方法。 然後,它可以在實現了該介面的類的 任何物件上呼叫介面的方法。 由於有抽象類, 它允許使用介面名作為引用變數的型別。 通常的動態聯編將生效。 引用可以轉換到介面型別或從介面型別轉換, instanceof 運算子可以用來 決定某物件的類是否實現了介面
19.介面是否可繼承介面?
介面可以繼承介面。 抽象類可以實現(implements)介面, 抽象類是否可繼承實體類,但 前提是實體類必須有明確的建構函式
20.swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上
swtich()裡面必須是int和enum--即列舉型別。 short、 char 或者 byte他會自動轉換為int的。。 long不能自動轉換為int.. 因為long比int範圍大..可能會丟失精度.. 在java的1.7之後的jdk版本, java中的switch裡面表示式的型別可以是string型別, 之前是不可以使用的
21.final, finally, finalize的區別
1、final修飾符(關鍵字)。 被final修飾的類, 就意味著不能再派生出新的子類, 不能作為父類而被子類繼承。 因此一個類不能既被abstract宣告, 又被final宣告。將變數或方法宣告為final, 可以保證他們在使用的過程中不被修改。 被宣告為final的變數必須在宣告時給出變數的初始值, 而在以後的引用中只能讀取。 被final宣告的方法也同樣只能使用, 即不能方法重寫。
22、finally是在異常處理時
提供finally塊來執行任何清除操作。 不管有沒有異常被丟擲、捕獲,finally塊都會被執行。 try塊中的內容是在無異常時執行到結束。 catch塊中的內容, 是在try塊內容發生catch所宣告的異常時, 跳轉到catch塊中執行。 finally塊則是無論異常是否發生, 都會執行finally塊的內容, 所以在程式碼邏輯中有需要 無論發生什麼都必須執行的程式碼, 就可以放在finally塊中。 3、finalize是方法名。 java技術允許使用finalize()方法 在垃圾收集器將物件從記憶體中 清除出去之前做必要的清理工作。 這個方法是由垃圾收集器 在確定這個物件沒有被引用時對這個物件呼叫的。 它是在object類中定義的, 因此所有的類都繼承了它。 子類覆蓋finalize()方法以整理系統資源或者被執行其他清理工作。 finalize()方法是在垃圾收集器 刪除物件之前對這個物件呼叫的。 ###2.Overload和Override的區別。 首先過載和重寫是應用於兩個不同場景下面的兩種不同的手段: 兩者各自的特徵: 過載(Overload):首先是位於一個類之中或者其子類中, 具有相同的方法名, 但是方法的引數不同, 返回值型別可以相同也可以不同。 (1):方法名必須相同 (2):方法的引數列表一定不一樣。 (3):訪問修飾符和返回值型別可以相同也可以不同。 其實簡單而言:過載就是對於不同的情況寫不同的方法。 比如,同一個類中, 寫不同的建構函式用於初始化不同的引數。 重寫(override):一般都是表示子類和父類之間的關係, 其主要的特徵是: 方法名相同, 引數相同, 但是具體的實現不同。 重寫的特徵: (1):方法名必須相同,返回值型別必須相同 (2):引數列表必須相同 (3):訪問許可權不能比父類中被重寫的方法的訪問許可權更低。 例如:如果父類的一個方法被宣告為public, 那麼在子類中重寫該方法就不能宣告為protected。 (4):子類和父類在同一個包中, 那麼子類可以重寫父類所有方法, 除了宣告為private和final的方法。 (5):構造方法不能被重寫, 簡單而言:就是具體的實現類對於父類的該方法實現不滿意, 需要自己在寫一個滿足於自己要求的方法。
23. Java中的String,StringBuilder,StringBuffer三者的區別?
首先說執行速度,或者說是執行速度, 在這方面執行速度快慢為:StringBuilder > StringBuffer > String String最慢的原因: String為字串常量, 而StringBuilder和StringBuffer均為字串變數, 即String物件一旦建立之後該物件是不可更改的, 但後兩者的物件是變數,是可以更改的。 而StringBuilder和StringBuffer的物件是變數, 對變數進行操作就是直接對該物件進行更改, 而不進行建立和回收的操作, 所以速度要比String快很多。 String---->字串常量 StringBuffer---->字串變數(執行緒安全的) StringBuilder---->字串變數(非執行緒安全的) String:適用於少量的字串操作的情況 StringBuilder:適用於單執行緒下在字元緩衝區進行大量操作的情況 StringBuffer:適用多執行緒下在字元緩衝區進行大量操作的情況
24.GC是什麼? 為什麼要有GC?
GC是垃圾收集的意思, 記憶體處理是程式設計人員容易出現問題的地方, 忘記或者錯誤的記憶體回收 會導致程式或系統的不穩定甚至崩潰, Java提供的GC功能 可以自動監測物件是否超過作用域 從而達到自動回收記憶體的目的, Java語言沒有提供釋放已分配記憶體的顯示操作方法。J ava程式設計師不用擔心記憶體管理, 因為垃圾收集器會自動進行管理。 要請求垃圾收集, 可以呼叫下面的方法之一: System.gc()或Runtime.getRuntime().gc(), 但JVM可以遮蔽掉顯示的垃圾回收呼叫。 垃圾回收可以有效的防止記憶體洩露, 有效的使用可以使用的記憶體。 垃圾回收器通常是作為一個單獨的低優先順序的執行緒執行, 不可預知的情況下對記憶體堆中 已經死亡的或者長時間沒有使用的物件進行清除和回收, 程式設計師不能實時的呼叫垃圾回收器 對某個物件或所有物件進行垃圾回收。 Java有了GC, 就不需要程式設計師去人工釋放記憶體空間。 當Java虛擬機發覺記憶體資源緊張的時候, 就會自動地去清理無用變數所佔用的記憶體空間。 當然,如果需要, 程式設計師可以在Java程式中顯式地使用System.gc() 來強制進行一次立即的記憶體清理。
25.構造器如何工作?
Java在構造例項時的順序是這樣的: 1、分配物件空間,並將物件中成員初始化為0或者空 ,java不允許使用者操縱一個不定值的物件。 2、執行屬性值的顯式初始化 3、執行構造器 4 、將變數關聯到堆中的物件上 而執行構造器的步驟有可以分為以下幾步: 1、Bind構造器的引數 2、如果顯式的呼叫了this,那就遞迴呼叫this構造器然後跳到步驟5 3、遞迴呼叫顯式或者隱式的父類構造器,除了Object以外,因為它沒有父類 4、執行顯式的例項變數初始化(也就是上邊的流程中的第二步,呼叫返回以後執行, 這個步驟相當於在父構造器執行後隱含執行的,看樣子像一個特殊處理)
26.構造器Constructor是否可被override?
構造器Constructor不能被繼承, 因此不能重寫Overriding, 但可以被過載Overloading 1). 構造器不能是native,final,static,synchronized 的, 可以是public,private,或什麼都沒有。 2). 構造器函式裡可以寫return呢,但後面什麼都不許有(包括null) 3). 構造器不能返回值. 但如果有個"構造器"返值了, 它就不是構造器嘍,只是個普通方法 4). super();this();這兩個方法只能在構造方法裡呼叫. 5). 成員變數宣告時候賦值,比建構函式還早.
27.寫一個Singleton出來。
Singleton模式主要作用是保證在Java應用程式中, 一個類Class只有一個例項存在。 一般Singleton模式通常有幾種種形式: 第一種形式: 定義一個類, 它的建構函式為private的, 它有一個static的private的該類變數, 在類初始化時例項話, 通過一個public的getInstance方法獲取對它的引用, 繼而呼叫其中的方法。 public class Singleton { private Singleton(){} //在自己內部定義自己一個例項,是不是很奇怪? //注意這是private 只供內部呼叫 private static Singleton instance = new Singleton(); //這裡提供了一個供外部訪問本class的靜態方法,可以直接訪問 public static Singleton getInstance() { return instance; } } 第二種形式: public class Singleton { private static Singleton instance = null; public static synchronized Singleton getInstance() { //這個方法比上面有所改進,不用每次都進行生成物件,只是第一次 //使用時生成例項,提高了效率! if (instance==null) instance=new Singleton(); return instance; } } 其他形式: 定義一個類, 它的建構函式為private的, 所有方法為static的。 一般認為第一種形式要更加安全些
28.error和exception有什麼區別?
Error類和Exception類都繼承自Throwable類。 二者的不同之處: Exception: 1.可以是可被控制(checked) 或不可控制的(unchecked)。 2.表示一個由程式設計師導致的錯誤。 3.應該在應用程式級被處理。 Error: 1.總是不可控制的(unchecked)。 2.經常用來用於表示系統錯誤或低層資源的錯誤。 3.如何可能的話,應該在系統級被捕捉。 error 表示恢復不是不可能但很困難的情況下的一種嚴重問題。 比如說記憶體溢位。 不可能指望程式能處理這樣的情況。 exception 表示一種設計或實現問題。 也就是說, 它表示如果程式執行正常, 從不會發生的情況。
29.HashMap和Hashtable的區別?
hashmap: 1.執行緒不安全 2.允許有null的鍵和值 3.效率高一點、 4.方法不是Synchronize的要提供外同步 5.有containsvalue和containsKey方法 6.HashMap 是Java1.2 引進的Map interface 的一個實現 7.HashMap是Hashtable的輕量級實現 hashtable: 1.執行緒安全 2.不允許有null的鍵和值 3.效率稍低、 4.方法是是Synchronize的 5.有contains方法方法 6.Hashtable 繼承於Dictionary 類 7.Hashtable 比HashMap 要舊
30.==和equals()區別?
對於==, 如果作用於基本資料型別的變數, 則直接比較其儲存的 “值”是否相等; 如果作用於引用型別的變數, 則比較的是所指向的物件的地址 對於equals方法, 注意:equals方法不能作用於基本資料型別的變數 如果沒有對equals方法進行重寫, 則比較的是引用型別的變數所指向的物件的地址; 諸如String、Date等類對equals方法進行了重寫的話, 比較的是所指向的物件的內容。
31.靜態變數和例項變數的區別?
靜態變數也叫類變數, 這種變數前加了static修飾符。 可以直接用類名呼叫, 也可以用物件呼叫, 而且所有物件的同一個類變數 都是共享同一塊記憶體空間。 例項變數也叫物件變數, 這種變數沒有加static修飾符。 只能通過物件呼叫, 而且所有物件的同一個例項變數 是共享不同的記憶體空間的。 區別在於: 靜態變數是所有物件共有的, 某一個物件將它的值改變了, 其他物件再去獲取它的值, 得到的是改變後的值; 例項變數則是每一個物件私有的, 某一個物件將它的值改變了, 不影響其他物件取值的結果, 其他物件仍會得到例項變數 一開始就被賦予的值。 例項變數必須建立物件後 才可以通過這個物件來使用, 靜態變數 則可以直接使用類名來引用。
32.垃圾回收器的基本原理是什麼?
垃圾回收器是Java平臺中用的 最頻繁的一種物件銷燬方法。 垃圾回收器會全程偵測Java應用程式的執行情況。 當發現有些物件成為垃圾時, 垃圾回收器就會銷燬這些物件, 並釋放這些物件所佔用的記憶體空間。 在這裡,程式開發人員需要知道, 在哪些情況下垃圾回收器 會認為這些物件是垃圾物件。 通常情況下,如果發生以下兩種情況時, 系統會認為這些物件是垃圾物件, 需要銷燬。 一是將一個NULL值賦值給物件。 二是物件其超出了作用範圍,
33.垃圾回收器可以馬上回收記憶體嗎?
不會馬上回收, 只有在必須回收時才會回收, 或者你可以呼叫垃圾回收方法, 虛擬機器會在空閒時回收, 至於什麼時候回收, 虛擬機器說了算
34.有什麼辦法主動通知虛擬機器進行垃圾回收?
對於GC來說, 當程式設計師建立物件時, GC就開始監控這個物件的地址、 大小以及使用情況。 通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件。 通過這種方式確定哪些物件是”可達的”, 哪些物件是”不可達的”。 當GC確定一些物件為”不可達”時, GC就有責任回收這些記憶體空間。 可以。程式設計師可以手動執行System.gc(), 通知GC執行, 但是Java語言規範 並不保證GC一定會執行。 System.gc()的工作原理 Java中的記憶體分配 是隨著new一個新的物件來實現的, 這個很簡單, 而且也還是有一些 可以“改進”記憶體回收的機制的, 其中最顯眼的 就是這個System.gc()函式。 乍一看這個函式似乎是可以進行垃圾回收的, 可事實並不是那麼簡單。 其實這個gc()函式的作用只是提醒虛擬機器: 程式設計師希望進行一次垃圾回收。 但是它不能保證垃圾回收一定會進行, 而且具體什麼時候進行 是取決於具體的虛擬機器的, 不同的虛擬機器有不同的對策。
35.內部類可以引用他包含類的成員嗎?
完全可以。 如果不是靜態內部類, 那沒有什麼限制! 一個內部類物件可以訪問 建立它的外部類物件的成員包括私有成員。 如果你把靜態巢狀類當作內部類的一種特例, 那在這種情況下不可以訪問外部類的 普通成員變數, 而只能訪問外部類中的靜態成員。 內部類的訪問規則: 1、內部類可以直接訪問外部類中的成員, 包括私有。 之所以可以直接訪問外部類中的成員, 是因為內部類中持有了 一個外部類的引用, 格式 外部類名.this 2、外部類要訪問內部類,必須建立內部類物件。 內部類定義在區域性時, 1、不可以被成員修飾符修飾 2、可以直接訪問外部類中的成員, 因為還持有外部類中的引用。 但是不可以訪問它所在的區域性中的變數。 只能訪問被final修飾的區域性變數。
36.Java 中的異常處理機制的簡單原理和應用?
一、Execption可以分為 java標準定義的異常 程式設計師自定義異常2種 1.一種是當程式違反了java語規則的時候, JAVA虛擬機器就會將發生的錯誤 表示為一個異常. 這裡語法規則指的是 JAVA類庫內建的語義檢查。 例如 int i = 2 / 0 或者 String str = null;str.length(); 2.另一種情況就是JAVA允許程式設計師 擴充套件這種語義檢查, 程式設計師可以建立自己的異常, 並自由選擇在何時用throw關鍵字 引發異常。 例如 Exception ex = new Exception("這是我自定義的異常; throw ex; 所有的異常都是Thowable的子類。 異常處理是與程式執行是並行的。 二、異常的處理方式 1.捕獲異常 try { int i = 2 / 0; } catch (Exception ex) { ex.printStackTrace(); System.out.println("異常資訊:" + ex.getMessage()); } 2.上拋異常 throws public void test() throws Exception { String str = null; str.length(); }
37.執行時異常與一般異常有何異同?
(1)執行時異常 都是RuntimeException類 及其子類異常, 如NullPointerException、 IndexOutOfBoundsException等, 這些異常是不檢查異常, 程式中可以選擇捕獲處理, 也可以不處理。 這些異常一般是由程式邏輯錯誤引起的, 程式應該從邏輯角度 儘可能避免這類異常的發生。 當出現RuntimeException的時候, 我們可以不處理。 當出現這樣的異常時, 總是由虛擬機器接管。 比如:我們從來沒有人 去處理過NullPointerException異常, 它就是執行時異常, 並且這種異常還是最常見的異常之一。 出現執行時異常後, 系統會把異常一直往上層拋, 一直遇到處理程式碼。 如果沒有處理塊, 到最上層, 如果是多執行緒就由Thread.run()丟擲, 如果是單執行緒就被main()丟擲。 丟擲之後, 如果是執行緒, 這個執行緒也就退出了。 如果是主程式丟擲的異常, 那麼這整個程式也就退出了。 執行時異常是Exception的子類, 也有一般異常的特點, 是可以被Catch塊處理的。 只不過往往我們不對他處理罷了。 也就是說, 你如果不對執行時異常進行處理, 那麼出現執行時異常之後, 要麼是執行緒中止, 要麼是主程式終止。 如果不想終止, 則必須撲捉所有的執行時異常, 決不讓這個處理執行緒退出。 佇列裡面出現異常資料了, 正常的處理應該是把異常資料捨棄, 然後記錄日誌。 不應該由於異常資料 而影響下面對正常資料的處理。 (2)非執行時異常 是RuntimeException以外的異常, 型別上都屬於Exception類及其子類。 如 IOException、SQLException 等 以及使用者自定義的Exception異常。 對於這種異常, JAVA編譯器強制要求我們 必需對出現的這些異常進行catch並處理, 否則程式就不能編譯通過。 所以,面對這種異常不管我們是否願意, 只能自己去寫一大堆catch塊 去處理可能的異常。
38.為什麼Map介面不繼承Collection 介面?
Collection是最基本的集合介面, 聲明瞭適用於JAVA集合(只包括Set和List) 的通用方法。 Set 和List 都繼承了Conllection; Set具有與Collection完全一樣的介面, 因此沒有任何額外的功能, 不像前面有兩個不同的List。 實際上Set就是Collection,只 是行為不同。 (這是繼承與多型思想的典型應用:表現不同的行為。) Set不儲存重複的元素(至於如何判斷元素相同則較為負責) Map沒有繼承於Collection介面 從Map集合中檢索元素時, 只要給出鍵物件, 就會返回對應的值物件。 Collection 和 Map 的區別 容器內每個為之所儲存的元素個數不同。 Collection型別者, 每個位置只有一個元素。 Map型別者, 持有 key-value pair, 像個小型資料庫 儘管Map介面和它的實現也是集合框架的一部分, 但Map不是集合, 集合也不是Map。 因此,Map繼承Collection毫無意義, 反之亦然。 如果Map繼承Collection介面, 那麼元素去哪兒? Map包含key-value對, 它提供抽取key或value列表集合的方法, 但是它不適合“一組物件”規範。
40.comparable 和 comparator的不同之處?
Comparable可以認為是一個內比較器, 實現了Comparable介面的類有一個特點, 就是這些類是可以和自己比較的, 至於具體和另一個實現了Comparable介面的類如何比較, 則依賴compareTo方法的實現, compareTo方法也被稱為自然比較方法。 如果開發者add進入 一個Collection的物件想要Collections的sort方法 幫你自動進行排序的話, 那麼這個物件必須實現Comparable介面。 compareTo方法的返回值是int, 有三種情況: 1、比較者大於被比較者 (也就是compareTo方法裡面的物件), 那麼返回正整數 2、比較者等於被比較者,那麼返回0 3、比較者小於被比較者,那麼返回負整數 Comparator可以認為是是一個外比較器, 個人認為有兩種情況 可以使用實現Comparator介面的方式: 1、一個物件不支援自己和自己比較 (沒有實現Comparable介面), 但是又想對兩個物件進行比較 2、一個物件實現了Comparable介面, 但是開發者認為compareTo方法中的 比較方式並不是自己想要的那種比較方式 Comparator接口裡面有一個compare方法, 方法有兩個引數T o1和T o2, 是泛型的表示方式, 分別表示待比較的兩個物件, 方法返回值和Comparable介面一樣是int, 有三種情況: 1、o1大於o2,返回正整數 2、o1等於o2,返回0 3、o1小於o2,返回負整數 總結 兩種比較器Comparable和Comparator, 後者相比前者有如下優點: 1、如果實現類沒有實現Comparable介面, 又想對兩個類進行比較 或者實現類實現了Comparable介面, 但是對compareTo方法內的比較演算法不滿意, 那麼可以實現Comparator介面, 自定義一個比較器, 寫比較演算法 2、實現Comparable介面的方式比 實現Comparator介面的耦合性要強一些, 如果要修改比較演算法, 要修改Comparable介面的實現類, 而實現Comparator的類是在外部進行比較的, 不需要對實現類有任何修 改。 從這個角度說, 其實有些不太好, 尤其在我們將實現類的.class檔案 打成一個.jar檔案 提供給開發者使用的時候。 實際上實現Comparator 介面的方式 後面會寫到就是一種典型的策略模式。 當然,這不是鼓勵用Comparator, 意思是開發者還是要在具體場景下 選擇最合適的那種比較器而已。
31.靜態變數和例項變數的區別?
靜態變數也叫類變數, 這種變數前加了static修飾符。 可以直接用類名呼叫, 也可以用物件呼叫, 而且所有物件的同一個類變數 都是共享同一塊記憶體空間。 例項變數也叫物件變數, 這種變數沒有加static修飾符。 只能通過物件呼叫, 而且所有物件的同一個例項變數 是共享不同的記憶體空間的。 區別在於: 靜態變數是所有物件共有的, 某一個物件將它的值改變了, 其他物件再去獲取它的值, 得到的是改變後的值; 例項變數則是每一個物件私有的, 某一個物件將它的值改變了, 不影響其他物件取值的結果, 其他物件仍會得到例項變數 一開始就被賦予的值。 例項變數必須建立物件後 才可以通過這個物件來使用, 靜態變數 則可以直接使用類名來引用。
32.垃圾回收器的基本原理是什麼?
垃圾回收器是Java平臺中用的 最頻繁的一種物件銷燬方法。 垃圾回收器會全程偵測Java應用程式的執行情況。 當發現有些物件成為垃圾時, 垃圾回收器就會銷燬這些物件, 並釋放這些物件所佔用的記憶體空間。 在這裡,程式開發人員需要知道, 在哪些情況下垃圾回收器 會認為這些物件是垃圾物件。 通常情況下,如果發生以下兩種情況時, 系統會認為這些物件是垃圾物件, 需要銷燬。 一是將一個NULL值賦值給物件。 二是物件其超出了作用範圍,
33.垃圾回收器可以馬上回收記憶體嗎?
不會馬上回收, 只有在必須回收時才會回收, 或者你可以呼叫垃圾回收方法, 虛擬機器會在空閒時回收, 至於什麼時候回收, 虛擬機器說了算
34.有什麼辦法主動通知虛擬機器進行垃圾回收?
對於GC來說, 當程式設計師建立物件時, GC就開始監控這個物件的地址、 大小以及使用情況。 通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件。 通過這種方式確定哪些物件是”可達的”, 哪些物件是”不可達的”。 當GC確定一些物件為”不可達”時, GC就有責任回收這些記憶體空間。 可以。程式設計師可以手動執行System.gc(), 通知GC執行, 但是Java語言規範 並不保證GC一定會執行。 System.gc()的工作原理 Java中的記憶體分配 是隨著new一個新的物件來實現的, 這個很簡單, 而且也還是有一些 可以“改進”記憶體回收的機制的, 其中最顯眼的 就是這個System.gc()函式。 乍一看這個函式似乎是可以進行垃圾回收的, 可事實並不是那麼簡單。 其實這個gc()函式的作用只是提醒虛擬機器: 程式設計師希望進行一次垃圾回收。 但是它不能保證垃圾回收一定會進行, 而且具體什麼時候進行 是取決於具體的虛擬機器的, 不同的虛擬機器有不同的對策。
35.內部類可以引用他包含類的成員嗎?
完全可以。 如果不是靜態內部類, 那沒有什麼限制! 一個內部類物件可以訪問 建立它的外部類物件的成員包括私有成員。 如果你把靜態巢狀類當作內部類的一種特例, 那在這種情況下不可以訪問外部類的 普通成員變數, 而只能訪問外部類中的靜態成員。 內部類的訪問規則: 1、內部類可以直接訪問外部類中的成員, 包括私有。 之所以可以直接訪問外部類中的成員, 是因為內部類中持有了 一個外部類的引用, 格式 外部類名.this 2、外部類要訪問內部類,必須建立內部類物件。 內部類定義在區域性時, 1、不可以被成員修飾符修飾 2、可以直接訪問外部類中的成員, 因為還持有外部類中的引用。 但是不可以訪問它所在的區域性中的變數。 只能訪問被final修飾的區域性變數。
36.Java 中的異常處理機制的簡單原理和應用?
一、Execption可以分為 java標準定義的異常 程式設計師自定義異常2種 1.一種是當程式違反了java語規則的時候, JAVA虛擬機器就會將發生的錯誤 表示為一個異常. 這裡語法規則指的是 JAVA類庫內建的語義檢查。 例如 int i = 2 / 0 或者 String str = null;str.length(); 2.另一種情況就是JAVA允許程式設計師 擴充套件這種語義檢查, 程式設計師可以建立自己的異常, 並自由選擇在何時用throw關鍵字 引發異常。 例如 Exception ex = new Exception("這是我自定義的異常; throw ex; 所有的異常都是Thowable的子類。 異常處理是與程式執行是並行的。 二、異常的處理方式 1.捕獲異常 try { int i = 2 / 0; } catch (Exception ex) { ex.printStackTrace(); System.out.println("異常資訊:" + ex.getMessage()); } 2.上拋異常 throws public void test() throws Exception { String str = null; str.length(); }
37.執行時異常與一般異常有何異同?
(1)執行時異常 都是RuntimeException類 及其子類異常, 如NullPointerException、 IndexOutOfBoundsException等, 這些異常是不檢查異常, 程式中可以選擇捕獲處理, 也可以不處理。 這些異常一般是由程式邏輯錯誤引起的, 程式應該從邏輯角度 儘可能避免這類異常的發生。 當出現RuntimeException的時候, 我們可以不處理。 當出現這樣的異常時, 總是由虛擬機器接管。 比如:我們從來沒有人 去處理過NullPointerException異常, 它就是執行時異常, 並且這種異常還是最常見的異常之一。 出現執行時異常後, 系統會把異常一直往上層拋, 一直遇到處理程式碼。 如果沒有處理塊, 到最上層, 如果是多執行緒就由Thread.run()丟擲, 如果是單執行緒就被main()丟擲。 丟擲之後, 如果是執行緒, 這個執行緒也就退出了。 如果是主程式丟擲的異常, 那麼這整個程式也就退出了。 執行時異常是Exception的子類, 也有一般異常的特點, 是可以被Catch塊處理的。 只不過往往我們不對他處理罷了。 也就是說, 你如果不對執行時異常進行處理, 那麼出現執行時異常之後, 要麼是執行緒中止, 要麼是主程式終止。 如果不想終止, 則必須撲捉所有的執行時異常, 決不讓這個處理執行緒退出。 佇列裡面出現異常資料了, 正常的處理應該是把異常資料捨棄, 然後記錄日誌。 不應該由於異常資料 而影響下面對正常資料的處理。 (2)非執行時異常 是RuntimeException以外的異常, 型別上都屬於Exception類及其子類。 如 IOException、SQLException 等 以及使用者自定義的Exception異常。 對於這種異常, JAVA編譯器強制要求我們 必需對出現的這些異常進行catch並處理, 否則程式就不能編譯通過。 所以,面對這種異常不管我們是否願意, 只能自己去寫一大堆catch塊 去處理可能的異常。
38.為什麼Map介面不繼承Collection 介面?
Collection是最基本的集合介面, 聲明瞭適用於JAVA集合(只包括Set和List) 的通用方法。 Set 和List 都繼承了Conllection; Set具有與Collection完全一樣的介面, 因此沒有任何額外的功能, 不像前面有兩個不同的List。 實際上Set就是Collection,只 是行為不同。 (這是繼承與多型思想的典型應用:表現不同的行為。) Set不儲存重複的元素(至於如何判斷元素相同則較為負責) Map沒有繼承於Collection介面 從Map集合中檢索元素時, 只要給出鍵物件, 就會返回對應的值物件。 Collection 和 Map 的區別 容器內每個為之所儲存的元素個數不同。 Collection型別者, 每個位置只有一個元素。 Map型別者, 持有 key-value pair, 像個小型資料庫 儘管Map介面和它的實現也是集合框架的一部分, 但Map不是集合, 集合也不是Map。 因此,Map繼承Collection毫無意義, 反之亦然。 如果Map繼承Collection介面, 那麼元素去哪兒? Map包含key-value對, 它提供抽取key或value列表集合的方法, 但是它不適合“一組物件”規範。
40.comparable 和 comparator的不同之處?
Comparable可以認為是一個內比較器, 實現了Comparable介面的類有一個特點, 就是這些類是可以和自己比較的, 至於具體和另一個實現了Comparable介面的類如何比較, 則依賴compareTo方法的實現, compareTo方法也被稱為自然比較方法。 如果開發者add進入 一個Collection的物件想要Collections的sort方法 幫你自動進行排序的話, 那麼這個物件必須實現Comparable介面。 compareTo方法的返回值是int, 有三種情況: 1、比較者大於被比較者 (也就是compareTo方法裡面的物件), 那麼返回正整數 2、比較者等於被比較者,那麼返回0 3、比較者小於被比較者,那麼返回負整數 Comparator可以認為是是一個外比較器, 個人認為有兩種情況 可以使用實現Comparator介面的方式: 1、一個物件不支援自己和自己比較 (沒有實現Comparable介面), 但是又想對兩個物件進行比較 2、一個物件實現了Comparable介面, 但是開發者認為compareTo方法中的 比較方式並不是自己想要的那種比較方式 Comparator接口裡面有一個compare方法, 方法有兩個引數T o1和T o2, 是泛型的表示方式, 分別表示待比較的兩個物件, 方法返回值和Comparable介面一樣是int, 有三種情況: 1、o1大於o2,返回正整數 2、o1等於o2,返回0 3、o1小於o2,返回負整數 總結 兩種比較器Comparable和Comparator, 後者相比前者有如下優點: 1、如果實現類沒有實現Comparable介面, 又想對兩個類進行比較 或者實現類實現了Comparable介面, 但是對compareTo方法內的比較演算法不滿意, 那麼可以實現Comparator介面, 自定義一個比較器, 寫比較演算法 2、實現Comparable介面的方式比 實現Comparator介面的耦合性要強一些, 如果要修改比較演算法, 要修改Comparable介面的實現類, 而實現Comparator的類是在外部進行比較的, 不需要對實現類有任何修 改。 從這個角度說, 其實有些不太好, 尤其在我們將實現類的.class檔案 打成一個.jar檔案 提供給開發者使用的時候。 實際上實現Comparator 介面的方式 後面會寫到就是一種典型的策略模式。 當然,這不是鼓勵用Comparator, 意思是開發者還是要在具體場景下 選擇最合適的那種比較器而已。
41.Iterator、ListIterator 和 Enumeration的區別?
迭代器是一種設計模式, 它是一個物件, 它可以遍歷並選擇序列中的物件, 而開發人員不需要了解 該序列的底層結構。 迭代器通常被稱為“輕量級”物件, 因為建立它的代價小。 Java中的Iterator功能比較簡單, 並且只能單向移動: (1) 使用方法iterator()要求容器返回一個Iterator。 第一次呼叫Iterator的next()方法時, 它返回序列的第一個元素。 注意:iterator()方法是java.lang.Iterable介面 被Collection繼承。 (2) 使用next()獲得序列中的下一個元素。 (3) 使用hasNext()檢查序列中是否還有元素。 (4) 使用remove()將迭代器新返回的元素刪除。 Iterator是Java迭代器最簡單的實現, 為List設計的ListIterator具有更多的功能, 它可以從兩個方向遍歷List, 也可以從List中插入和刪除元素。 ------------- ListIterator的特點: 它的父類介面是Iterator, 名稱是系列表迭代器, 允許程式設計師按任一方向遍歷列表、 迭代期間修改列表, 並獲得迭代器在列表中的當前位置。 ListIterator沒有當前元素, 它的游標位置始終位於呼叫previous() 所返回的元素和呼叫next() 所返回的元素之間。 長度為n的列表的迭代器有n+1個 可能的指標位置。 ------------------ Enumeration的特點: API中是這樣描述的, 它主要是和Vector結合配套使用。 另外此介面的功能與Iterator介面的功能是重複的, 此外,Iterator介面添加了 一個可選的移除操作, 並且使用較短的方法名。 新的實現應該優先 考慮使用Iterator介面 而不是Enumeration介面。 ----------------------- java中的集合類都提供了 返回Iterator的方法, 就是迭代器, 它和Enumeration的主要區別 其實就是Iterator可以刪除元素, 但是Enumration卻不能。
42.Java 中 Set 與 List 有什麼不同?
1、Set 不允許重複,List允許重複 2、Set 沒有順序,List有順序 List介面對Collection進行了簡單的擴充, 它的具體實現類常用的有ArrayList和LinkedList。 你可以將任何東西放到一個List容器中, 並在需要時從中取出。 ArrayList從其命名中可以看出 它是一種類似陣列的形式進行儲存, 因此它的隨機訪問速度極快, 而LinkedList的內部實現是連結串列, 它適合於在連結串列中間 需要頻繁進行插入和刪除操作。 在具體應用時可以根據需要自由選擇。 前面說的Iterator只能對容器進行向前遍歷, 而ListIterator則繼承了Iterator的思想, 並提供了對List進行雙向遍歷的方法。 Set介面也是Collection的一種擴充套件, 而與List不同的時, 在Set中的物件元素不能重複, 也就是說你不能把同樣的東西 兩次放入同一個Set容器中。 它的常用具體實現有HashSet和TreeSet類。 HashSet能快速定位一個元素, 但是你放到HashSet中的物件 需要實現hashCode()方法, 它使用了前面說過的雜湊碼的演算法。 而TreeSet則將放入 其中的元素按序存放, 這就要求你放入 其中的物件是可排序的, 這就用到了集合框架提供的 另外兩個實用類Comparable和Comparator。 一個類是可排序的, 它就應該實現Comparable介面。 有時多個類具有相同的排序演算法, 那就不需要在每分別重複定義 相同的排序演算法, 只要實現Comparator介面即可。 集合框架中還有兩個很實用的公用類: Collections和Arrays。 Collections提供了對一個Collection容器 進行諸如排序、複製、查詢和填充等 一些非常有用的方法, Arrays則是對一個數組進行類似的操作。
43.arraylist 與 vector 的區別?
ArrayList與Vector的區別, 這主要包括兩個方面:. 1.同步性: Vector是執行緒安全的, 也就是說是它的方法之間是執行緒同步的, 而ArrayList是執行緒序不安全的, 它的方法之間是執行緒不同步的。 如果只有一個執行緒會訪問到集合, 那最好是使用ArrayList, 因為它不考慮執行緒安全, 效率會高些; 如果有多個執行緒會訪問到集合, 那最好是使用Vector, 因為不需要我們自己 再去考慮和編寫執行緒安全的程式碼。 備註: 對於Vector&ArrayList、Hashtable&HashMap, 要記住執行緒安全的問題, 記住Vector與Hashtable是舊的, 是java一誕生就提供了的, 它們是執行緒安全的, ArrayList與HashMap是java2時才提供的, 它們是執行緒不安全的。 2.資料增長: ArrayList與Vector 都有一個初始的容量大小, 當儲存進它們裡面的元素的個數超過了容量時, 就需要增加ArrayList與Vector的儲存空間, 每次要增加儲存空間時, 不是隻增加一個儲存單元, 而是增加多個儲存單元, 每次增加的儲存單元的個數 在記憶體空間利用與程式效率之間 要取得一定的平衡。 Vector預設增長為原來兩倍, 而ArrayList的增長策略 在文件中沒有明確規定 從原始碼看到的是增長為原來的1.5倍。 ArrayList與Vector都可以設定初始的空間大小, Vector還可以設定增長的空間大小, 而ArrayList沒有提供 設定增長空間的方法。 總結: 即Vector增長原來的一倍, ArrayList增加原來的0.5倍。
44.什麼類實現了List介面?
List介面的實現類中 最經常使用最重要的就是這三個: ArrayList、 Vector、 LinkedList。 1.三個都直接實現了AbstractList這個抽象類 2,ArrayList和Vector都實現了 RandomAccess介面。 而LinkedList沒有。 這是什麼意思呢? 在JDK 中, RandomAccess介面是一個空介面, 所以它沒有實際意義。就是一個標記, 標記這個類支援高速隨機訪問, 所以,arrayList和 vector是支援隨機訪問的, 可是LinkedList不支援持 3.serializbale介面表明他們都支援序列化。
45.什麼類實現了Set介面?
HashSet LinkedHashSet TreeSet HashSet是使用雜湊表(hash table)實現的, 其中的元素是無序的。 HashSet的 add、 remove、 contains方法 的時間複雜度為常量O(1)。 -------------------- TreeSet使用樹形結構 演算法書中的紅黑樹red-black tree 實現的。 TreeSet中的元素是可排序的, 但add、remove和contains方法的時間 複雜度為O(log(n))。 TreeSet還提供了 first()、 last()、 headSet()、 tailSet()等 方法來操作排序後的集合。 ----------------------- LinkedHashSet介於HashSet和TreeSet之間。 它基於一個由連結串列實現的雜湊表, 保留了元素插入順序。 LinkedHashSet中基本方法的 時間複雜度為O(1)。
46.如何保證一個集合執行緒安全?
Java提供了不同層面的執行緒安全支援。 在傳統集合框架內部, 除了Hashtable等同步容器, 還提供了所謂的同步包裝器(Synchronized Wrapper), 可以呼叫Collections工具類提供的包裝方法, 來獲取一個同步的包裝容器, 例如Collections.synchronizedMap()。 但是它們都是利用非常粗粒度的同步方式, 在高併發情況下的效能比較低下。 另外,更加普遍的選擇是利用併發包(java.util.concurrent) 提供的執行緒安全容器類: 各種併發容器, 比如ConcurrentHashMap、 CopyOnWriteArrayList。 各種執行緒安全佇列(Queue/Deque), 比如ArrayBlockingQueue、 SynchronousQueue。 各種有序容器的執行緒安全版本等。 具體保證執行緒安全的方式, 包括有從簡單的synchronized方式, 到基於更加精細化的, 比如基於分離鎖實現的ConcurrentHashMap等併發實現等。 具體選擇要看開發的場景需求, 總體來說, 併發包內提供的容器通用場景, 遠遠優於早期的簡單同步實現。 為什麼需要ConcurrentHashMap 首先,Hashtable本身比較低效, 因為它的實現基本就是 將put、get、size等方法 簡單粗暴地加上“synchronized”。 這就導致了所有併發操作都要競爭同一把鎖, 一個執行緒在進行同步操作時, 其它執行緒只能等待, 大大降低了併發操作的效能。
47.是否可以往 TreeSet 或者 HashSet 中新增 null 元素?
1.TreeSet 是二差樹實現的, Treeset中的資料是自動排好序的, 不允許放入null值 2.HashSet 是雜湊表實現的, HashSet中的資料是無序的, 可以放入null, 但只能放入一個null, 兩者中的值都不能重複, 就如資料庫中唯一約束 3.HashSet要求放入的物件 必須實現HashCode()方法, 放入的物件,是以hashcode碼作為標識的, 而具有相同內容的String物件, hashcode是一樣, 所以放入的內容不能重複。 但是同一個類的物件可以放入不同的例項
48.hashCode() 和 equals() 方法的重要性?如何在Java中使用它們?
Java中的HashMap使用 hashCode()和equals()方法 來確定鍵值對的索引, 當根據鍵獲取值的時候 也會用到這兩個方法。 如果沒有正確的實現這兩個方法, 兩個不同的鍵可能會有相同的hash值, 因此可能會被集合認為是相等的。 而且,這兩個方法也用來發現重複元素, 所以這兩個方法的實現對HashMap的 精確性和正確性是至關重要的。 同一個物件(沒有發生過修改) 無論何時呼叫hashCode(), 得到的返回值必須一樣。 hashCode()返回值相等, 物件不一定相等, 通過hashCode()和equals() 必須能唯一確定一個物件。 一旦重寫了equals(), 就必須重寫hashCode()。 而且hashCode()生成雜湊值的依據應該是 equals()中用來比較是否相等的欄位。 如果兩個由equals()規定相等的物件 生成的hashCode不等, 對於HashMap來說, 他們可能分別對映到不同位置, 沒有呼叫equals()比較是否相等的機會, 兩個實際上相等的物件可能被插入到不同位置, 出現錯誤。 其他一些基於雜湊方法的集合類 可能也會有這個問題。 ---------------- 怎麼判斷兩個物件是相同的? 使用等號== 判斷兩個物件是否相同, 這種是嚴格的相同, 即記憶體中的同一個物件 Object的equal方法就是使用==判斷兩個物件是否相同 ------------ 集合set要求元素是唯一的,怎麼實現? 要實現元素的唯一, 需要在往集合set中新增元素時, 判斷集合set是否存在相同的元素, 如果存在,則不新增,反之。 那麼怎麼確定兩個元素是否相同, 1.如果是使用等號==判斷兩個元素是否相同, 即預設使用Object的equals的方法。 2.如果沒有使用等號==判斷兩個元素是否相同, 而是按照某種業務規則判斷兩個元素是否相同, 即重寫了Object的equals的方法。 ---------------------- 當重寫equals方法,必須重寫hashCode方法嗎? 不是必須的, 得看具體的情況 當equals方法返回的結果和使用等號 比較的結果是一致的時候, 是沒有必要重寫hashCode方法。 當用等號比較物件, 只有是記憶體中同一個物件例項, 才會返回true, 當然呼叫其hashCode()方法 肯定返回相同的值, 這滿足了滿足了hashCode的約束條件, 所以不用重寫hashCode()方法。 當equals方法返回的結果 和使用等號比較的結果是不一致的時候, 就需要重寫hashCode方法。 當重寫後的equals方法 不認為只有是在記憶體中同一個物件例項, 才返回true, 如果不重新hashCode方法() Object的hashCode()方法 是對記憶體地址的對映, hashCode方法返回的值肯定是不同的, 這違背了hashCode的約束條件, 所以必須要重新hashCode方法, 並滿足對hashCode的約束條件。
49.array 和 arraylist 的區別?
兩者間的區別: Array 的容量是固定的, ArrayList 的容量是根據需求自動擴充套件 ArrayList 提供了 新增、插入或移除 某一範圍元素的方法 而 Array 中, 只能一次獲取或設定一個元素值 用Synchronized方法可以 很容易地建立ArrayList的同步版本 而 Array 將一直保持 它知道使用者實現同步為止 array 陣列的用法 type [] name = new type [size]; 注意:size不能省略,type前後要一致 缺點:在資料間插入資料是 ArrayList 動態陣列的用法 是 Array 的複雜版本 動態的增加和減少元素, 實現 ICollection 和 IList 介面 靈活的設定陣列大小
50.如何將一個字串轉換為arraylist?
string 轉 ArrayList 先將字串按照某個字元切割,轉為string陣列 然後用Arrays的asList方法,將陣列轉為List public class test1 { public static void main(String[] args){ //string 轉 ArrayList String str1 = "a,b,c"; ArrayList<String> list = new ArrayList<String>(Arrays.asList(str1.split(","))); System.out.println(list); } } ArrayList 轉 string public class test1 { public static void main(String[] args){ //ArrayList 轉 string ArrayList<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); System.out.println(list);//[a, b, c] String list_str = StringUtils.join(list,","); System.out.println(list_str);//a,b,c } }