前 50 個 Java 核心面試問題和答案。第1部分
收藏
25. Java中集合是什麼意思?
集合是一個旨在儲存和操作物件的框架。用於執行以下操作:- 搜尋;
- 排序;
- 操縱;
- 添加;
- 刪除。
java.util
套件中。
26. Collection框架中有哪些類別和介面可用?
接口:- 收藏;
- 列表;
- 放;
- 地圖;
- 排序集;
- 排序地圖;
- 隊列。
- 列表:
- 數組列表;
- 鍊錶;
- 向量(已棄用)。
- 套:
- 哈希集;
- 鏈接哈希集;
- 樹集。
- 地圖:
- 哈希映射
- 樹狀圖
- 哈希表(已棄用)
- 連結哈希映射
- 佇列
- 優先隊列。
27.集合中排序和排序是什麼意思?
訂購:
這意味著儲存在集合中的項目是基於添加到集合中的值。這樣我們就可以按照特定的順序迭代集合中的值。換句話說,這意味著集合的元素有自己特定的排列順序。為了更好地理解,未排序的集合以隨機順序儲存其元素。例如,設定。排序:
這意味著根據集合元素的資料將一組元素排序到集合中。也就是說,不僅集合是有序的,而且元素的順序也取決於它們的值。如果您按不同的元素值排序,則此順序可能會變更。28. 有哪些集合具有List介面?你如何與清單一起工作?
工作表中元素的值是基於它們的索引——它們按索引排序。元素重複是允許的(也就是說,你可以多次將同一個物件加入集合就可以了)。數組列表:
最常見的集合。本質上,它是一個大小動態擴展的陣列。管理數組大小的工作由集合負責。對我們來說,重要的是要了解,在大多數情況下,這就是我們需要使用的。特點:- 快速搜尋和快速索引搜尋;
- 集合按索引排序,但未排序;
- 實現隨機存取介面;
- 慢慢地添加到清單的中間。
public class A {
public static void main(String[] args) {
ArrayList names = new ArrayList<>();
names.add("John");
names.add("John");
names.add("Roman");
names.add("Ivan");
}
}
>> 輸出
[John, John, Roman, Ivan]
輸出顯示這些是可重複的元素。它們按照記錄的順序顯示。還有什麼可讀的?是的,有很多訊息,你甚至不需要離開 JavaRush:
連結列表:
這是一個集合,其中每個元素都有到上一個和下一個元素的連結。這些連結允許您從一個元素移動到另一個元素。當添加元素時,前一個和下一個元素的連結只會改變:- 元素之間相互連接,即實現了雙向鍊錶;
- 整體運行速度明顯低於ArrayList;
- 對於在數組中間進行大量插入和刪除的絕佳選擇;
- 實作了 Queue 和 Deque 列表接口,因此有它們的工作方法。
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("One");
linkedList.add("Two");
linkedList.add("Three");
29. 請介紹 Map 集合及其實作?
Map 是一個鍵值集合。有一個唯一的鍵和一個與該值相符的值。equals()
方法也用於hashcode()
確定密鑰的唯一性。
哈希映射:
- 未分類或排序;
- 如果順序和排序不重要則使用;
- 支援空鍵。
public class CollectionExample {
public static void main(String[] args) {
HashMap positions = new HashMap<>();
positions.put("junior", "Ivan");
positions.put("middle", "Roman");
positions.put("senior", "Vasily");
positions.put("team lead", "Anton");
positions.put("arthitect", "Andrew");
positions.put("senior", "John");
System.out.println(positions);
}
}
// вывод в консоль
// {junior=Ivan, middle=Roman, senior=John, team lead=Anton, arthitect=Andrew}
密鑰始終是唯一的,因此只記錄了一位高級人員。
連結哈希映射:
- 維護插入順序;
- 比HashMap慢;
- 迭代預計比 HashMap 更快。
public class CollectionExample {
public static void main(String[] args) {
LinkedHashMap<String, String> positions = new LinkedHashMap<>();
positions.put("junior", "Ivan");
positions.put("middle", "Roman");
positions.put("senior", "Vasily");
positions.put("team lead", "Anton");
positions.put("arthitect", "Andrew");
positions.put("senior", "John");
System.out.println(positions);
}
}
// вывод в консоль
// {junior=Ivan, middle=Roman, senior=John, team lead=Anton, arthitect=Andrew}
樹狀圖:
一種映射實現,可以根據鍵的自然順序對條目進行排序,或者更好的是,如果在建立映射時在構造函數中提供了比較器,則使用比較器。例子:-
不含比較器
public class CollectionExample { public static void main(String[] args) { TreeMap<Integer, String> positions = new TreeMap<>(); positions.put(1, "Ivan"); positions.put(3, "Roman"); positions.put(2, "Vasily"); positions.put(10, "Anton"); positions.put(7, "Andrew"); positions.put(1, "John"); System.out.println(positions); } } // вывод в консоль // {1=John, 2=Vasily, 3=Roman, 7=Andrew, 10=Anton}
-
附比較器
public class CollectionExample { public static void main(String[] args) { //используем реализацию Strategy Pattern'a и добавим компаратор: TreeMap<Integer, String> positions = new TreeMap<>(Comparator.reverseOrder()); positions.put(1, "Ivan"); positions.put(3, "Roman"); positions.put(2, "Vasily"); positions.put(10, "Anton"); positions.put(7, "Andrew"); positions.put(1, "John"); System.out.println(positions); } } // вывод в консоль // {10=Anton, 7=Andrew, 3=Roman, 2=Vasily, 1=John}
30. 給我們介紹一下Set集合及其實作?
集合是唯一元素的集合,這是它的主要特徵。即Set不允許相同的元素重複出現。 這裡重要的是,新增的物件必須實作一個方法equals
。
哈希集:
- 未排序或排序。在底層有一個帶有值佔位符的 HashMap。你自己看 ;)
- 使用hashCode添加物件;
- 當您需要擁有唯一的物件並且它們的順序並不重要時,應該使用它。
public class CollectionExample {
public static void main(String[] args) {
HashSet<String> positions = new HashSet<>();
positions.add("junior");
positions.add("junior");
positions.add("middle");
positions.add("senior");
positions.add("team lead");
positions.add("architect");
System.out.println(positions);
}
}
// вывод в консоль
// [senior, middle, team lead, architect, junior]
在這裡您可以看到新增了兩次的「junior」元素僅出現在一個實例中。而且順序和添加時不一樣。
連結哈希集:
- HashSet 的有序版本;
- 支援所有元素的雙向鍊錶;
- 當迭代過程中需要有序性時使用它。
public class CollectionExample {
public static void main(String[] args) {
LinkedHashSet<String> positions = new LinkedHashSet<>();
positions.add("junior");
positions.add("junior");
positions.add("middle");
positions.add("senior");
positions.add("team lead");
positions.add("architect");
System.out.println(positions);
}
}
// вывод в консоль
// [senior, middle, team lead, architect, junior]
樹集:
- 兩個已排序集合之一;
- 採用紅黑樹結構,並保證元素依升序排列;
- 在底層,它是一個帶有值存根的 TreeMap。TreeSet 的元素是 TreeMap 的鍵(另請參閱;))。
public class CollectionExample {
public static void main(String[] args) {
TreeSet<String> positions = new TreeSet<>();
positions.add("junior");
positions.add("junior");
positions.add("middle");
positions.add("senior");
positions.add("team lead");
positions.add("architect");
System.out.println(positions);
}
}
// вывод в консоль
// [architect, junior, middle, senior, team lead]
例外情況
31.什麼是異常?
異常是運行時可能發生的問題。這是由於某種原因而出現的特殊情況。異常繼承圖如下所示(您需要熟記在心;)): 此圖顯示,一般來說,所有異常都分為兩組 -異常和錯誤。 錯誤- JVM 用於顯示錯誤,之後應用程式不再有意義。例如,StackOverFlowError,它表示堆疊已滿,程式無法再運行。 異常- 在程式碼中以程式設計方式產生的異常。有各種異常,檢查的和未檢查的,但最重要的是它們存在,並且可以捕獲它們並且應用程式可以繼續運行。異常又進一步分為繼承自 RuntimeException 的異常和 Exception 的其他後代。關於這個問題有足夠的資訊。我們將在下面討論什麼是檢查/非檢查異常。32. JVM如何處理異常?
怎麼運作的?一旦某個地方拋出異常,運行時就會建立一個異常物件(表示為 ExcObj)。它儲存工作所需的所有資訊 - 引發的異常本身以及發生的位置。創建ExcObj
並傳輸到運行時無非就是“拋出異常”。 ExcObj
包含可用於到達引發異常的位置的方法。這組方法稱為呼叫堆疊。接下來,運行時系統在呼叫堆疊中尋找可以處理異常的方法。如果它確實找到了對應的處理程序,即異常類型與處理程序中的類型匹配,則一切正常。如果找不到,運行時會將所有內容傳遞給預設異常處理程序,該處理程序準備回應並退出。視覺上看起來如何:
/**
* Пример, в котором показываются две опции — когда находится обработчик для исключения и когда нет.
*/
class ThrowerExceptionExample {
public static void main(String[] args) throws IllegalAccessException {
ThrowerExceptionExample example = new ThrowerExceptionExample();
System.out.println(example.populateString());
}
/**
* Здесь происходит перехват одного из возможных исключений — {@link IOException}.
* А вот второй будет пробрасываться дальше вверх по вызову.
*/
private String populateString() throws IllegalAccessException {
try {
return randomThrower();
} catch (IOException e) {
return "Caught IOException";
}
}
/**
* Здесь две опции: or бросается {@link IOException} or {@link IllegalAccessException}.
* Выбирается случайным образом.
*/
private String randomThrower() throws IOException, IllegalAccessException {
if (new Random().nextBoolean()) {
throw new IOException();
} else {
throw new IllegalAccessException();
}
}
}
在我們的範例中,CallStack 大致如下所示:
randomThrower() => populateString() => main(String[] args)
有兩種選擇:隨機拋出一個或另一個異常。對於 IOException 一切正常,如果產生它,那麼工作結果將是:"Caught IOException"
。但是,如果出現第二個沒有處理程序的異常,程式將停止並顯示以下輸出:
Exception in thread "main" java.lang.IllegalAccessException
at ThrowerExceptionExample.randomThrower(CollectionExample.java:38)
at ThrowerExceptionExample.populateString(CollectionExample.java:24)
at ThrowerExceptionExample.main(CollectionExample.java:15)
33. 程式設計師如何處理異常?
在上面的問題中,某些關鍵字已經用於處理異常;現在我們需要更詳細地討論它們。關鍵字是什麼?- 嘗試
- 抓住
- 丟
- 投擲
- 最後
try-catch-finally
是一個允許您正確捕獲和處理異常的構造。try
- 只能有一次,即邏輯發生的時刻;catch
— 接收某種類型異常的區塊;可以有很多異常。例如,一個try區塊會拋出幾個彼此無關的例外;finally
- 「終於」這個區塊。這是一個在任何情況下都會執行的區塊,無論 try、catch 中做了什麼。
try {
// сюда передают тот code, который может вызвать исключение.
} catch (IOException e) {
// первый catch блок, который принимает IOException и все его подтипы(потомки).
// Например, нет file при чтении, выпадает FileNotFoundException, и мы уже соответствующе
// обрабатываем это.
} catch (IllegalAccessException e) {
// если нужно, можно добавить больше одного catch блока, в этом нет проблем.
} catch (OneException | TwoException e) {
// можно даже объединять несколько в один блок
} catch (Throwable t) {
// а можно сказать, что мы принимаем ВСЁ))))
} finally {
// этот блок может быть, а может и не быть.
// и он точно выполнится.
}
仔細閱讀例子的描述一切就清楚了)
34. Java 中的 throw 和 throws
丟
throw
當您需要明確建立新異常時使用。它用於創建和引發自訂異常。例如,與驗證相關的異常。通常,為了驗證,它們繼承自RuntimeException
. 例子:
// пример пробрасывания исключения
throw new RuntimeException("because I can :D");
重要的是,此構造只能由繼承自 的物件使用Throwable
。也就是說,你不能這樣說:
throw new String("How тебе такое, Илон Маск?");
接下來,執行緒的工作被終止,並開始搜尋可以處理它的處理程序。當它找不到它時,它會轉到呼叫它的方法,因此搜尋將沿著呼叫行向上進行,直到找到相應的處理程序或讓應用程式保持運行。我們看看吧:
// Пример, который демонстрирует работу throw
class ThrowExample {
void willThrow() throws IOException {
throw new IOException("Because I Can!");
}
void doSomething() {
System.out.println("Doing something");
try {
willThrow();
} catch (IOException e) {
System.out.println("IOException was successfully handled.");
}
}
public static void main(String args[]) {
ThrowExample throwExample = new ThrowExample();
throwExample.doSomething();
}
}
如果我們運行該程序,我們會得到以下結果:
Doing something
IOException was successfully handled.
投擲
throws
- 一種方法可以拋出一個或多個異常的機制。它們以逗號分隔添加。讓我們看看它是多麼容易和簡單:
private Object willThrow() throws RuntimeException, IOException, FileNotFoundException
此外,值得注意的是,可以存在受控異常和非受控異常。當然,未經檢查的異常可能不會被添加到 中throws
,但出於禮貌,否則會這樣說。如果這些是可檢查的,那麼使用產生它們的方法,您需要以某種方式處理它。有兩種選擇:
try-catch
用適當的和上面的繼承異常來寫。throws
以完全相同的方式使用它,以便其他人已經遇到這個問題:D
35. Java中的受檢異常和非受檢異常
Java中有兩種類型的異常—受控異常和非受控異常。檢查異常:
這些是在編譯時檢查的異常。如果方法中的某些程式碼在異常期間拋出已檢查的異常,則該方法必須使用 處理它try-catch
,或進一步轉發它。例如,從路徑“/users/romankh3/image.png”讀取圖像,並更新它以某種方式(對我們來說這並不重要)並將其保存回來。
class CheckedImageExample {
public static void main(String[] args) {
File imageFile = new File("/users/romankh3/image.png");
BufferedImage image = ImageIO.read(imageFile);
updateAndSaveImage(image, imageFile);
}
private static void updateAndSaveImage(BufferedImage image, File imageFile) {
ImageIO.write(image, "png", imageFile);
}
}
這類程式碼將無法編譯,因為靜態方法ImageIO.read()
會拋出ImageIO.write()
IOException,該例外會被檢查並必須進行對應處理。這裡有兩個選項我們已經在上面討論過:要麼使用try-catch
,要麼進一步轉發。為了更好地同化,我們會做這做那。也就是說,updateAndSave
我們只需在方法中轉發它,然後在 main 方法中使用它try-catch
:
class CheckedImageExample {
public static void main(String[] args) {
File imageFile = new File("/users/romankh3/image.png");
try {
BufferedImage image = ImageIO.read(imageFile);
updateAndSaveImage(image, imageFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void updateAndSaveImage(BufferedImage image, File imageFile) throws IOException {
ImageIO.write(image, "png", imageFile);
}
}
未經檢查的異常:
這些是在編譯階段不檢查的異常。也就是說,一個方法可以產生 RuntimeException,但編譯器不會提醒您以某種方式處理它。如下所示,我們將所有繼承自 RuntimeException 和 Error 的內容都取消選取。 考慮以下 Java 程式。該程式碼編譯良好,但在運行時拋出異常ArrayIndexOutOfBoundsException
。編譯器允許它編譯,因為ArrayIndexOutOfBoundsException
它是未經檢查的異常。數組的常見情況可能是:
class CheckedImageExample {
public static void main(String[] args) {
int[] array = new int[3];
array[5] = 12;
}
}
結果將是:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at main(CheckedImageExample.java:12)
順便說一句,您是否已經注意到在 Java 中沒有人給出短名稱?越大越好。他,Spring Framework,在這方面非常成功:只需使用一些BeanFactoryPostProcessor類別))))
36. 什麼是資源嘗試?
這是一種必須正確關閉所有資源的機制。有點不清楚,對吧?)首先,什麼是資源…資源是一個對象,使用後需要關閉它,即調用close()
. 資源是指實作介面的所有對象AutoClosable
,而對象又實作介面Closeable
。對我們來說,重要的是要明白一切InputStream
都是OutpuStream
資源,都需要正確、成功地釋放。這正是我們需要使用try-with-resource
該結構的原因。它看起來是這樣的:
private void unzipFile(File zipFile) throws IOException {
try(ZipInputStream zipOutputStream = new ZipInputStream(new FileInputStream(zipFile))) {
ZipEntry zipEntry = zipOutputStream.getNextEntry();
while (zipEntry != null) {
}
}
}
private void saveZipEntry(ZipEntry zipEntry) {
// логика сохранения
}
在此範例中,資源為ZipInputStream
,使用後您需要將其關閉。為了不考慮呼叫方法close()
,我們只需在 try 區塊中定義此變量,如範例所示,並在該區塊中執行所有必要的操作。這個例子有什麼作用?它將解壓縮 zip 檔案。為此,您需要使用InputStream
'om. 您可以定義多個變數;它們之間用分號分隔。有什麼問題?但您finally
可能會說,您可以使用區塊。這裡有一篇文章詳細介紹了這種方法的問題。它還描述了忽略使用此設計的人可能遇到的失敗的完整清單。我建議閱讀它;)最後一部分有關於多線程主題的問題/答案。 我的 GitHub 個人資料
GO TO FULL VERSION