做電商網(wǎng)站的感想免費(fèi)b站推廣網(wǎng)站在線
Java 基礎(chǔ)面試300題 (261-290)
261.CompletableFuture.runAsync
和CompletableFuture.supplyAsync
方法有什么區(qū)別?
這兩個方法都可用于異步運(yùn)行代碼。但兩者之間有一些區(qū)別如下 :
-
runAsync
不返回結(jié)果,返回的是一個CompletableFuture<Void>
,另一方面supplyAsync
從線程返回一個CompletableFuture<T>
-
runAsync
方法接受Runnable
為參數(shù)。另一方面,supplyAsync
接受Supplier
為參數(shù)。 -
runAsync
方法在單獨(dú)的線程中執(zhí)行Runnable
中的代碼。另一方面,supplyAsync
在單獨(dú)的線程中執(zhí)行Supplier
提供的代碼,并返回由Supplier
生成的值。
262.什么是模塊?它們有什么好處?
一個模塊由一組相關(guān)包組成。就像將一組相關(guān)類放入一個包中一樣,可以將一組相關(guān)包放入一個模塊中。模塊提供以下幾個好處:
-
如果應(yīng)用程序有大量包,則很難跟蹤。模塊充當(dāng)救援角色,它們有助于組織包,相關(guān)包可以分組到一個模塊中。
-
模塊可以自行部署, 有助于減小應(yīng)用程序的大小。
-
模塊提供更好的安全性。在模塊之前,使類在其他包中可重用的唯一方法是將其公開。然而,這構(gòu)成了一個安全問題,因?yàn)楣?類對每個人都開放,都可以訪問。將包分組到模塊中,確保無法在模塊外訪問該類。
-
由于Java 9之前沒有模塊,像
rt.jar
這樣的Java API jar文件的非常大。有了模塊后,Java 9將其拆分為更小的模塊,這些小模塊更易于測試和維護(hù)。 -
在Java 9之前,安全性一直是個問題,因?yàn)殚_發(fā)人員能夠訪問內(nèi)部JDK文件。模塊也有助于解決這個問題。模塊增加了更多的訪問控制,可以控制模塊內(nèi)哪些包在模塊外可見和可訪問。
263.模塊描述符是什么?
模塊描述符是一個名為module-info.java的Java文件。它包含有關(guān)模塊的信息。它需要出現(xiàn)在模塊的根部。以下代碼行演示了模塊描述符的結(jié)構(gòu):
module demomodule {
//optional directives
}
模塊描述符可以包含一些可選指令, 下表是其中的指令:
指令 | 描述 |
---|---|
Name | 指定模塊的名稱。 |
exports | 指定該模塊中將對其他模塊可用的包的名稱。 |
requires | 指定當(dāng)前模塊依賴的模塊的名稱。如果未指定這些模塊,則當(dāng)前模塊可能無法正常工作。 |
provides | 指定當(dāng)前模塊提供的服務(wù)。當(dāng)一個模塊作為服務(wù)提供者時,應(yīng)使用此指令。 |
uses | 指定當(dāng)前模塊消耗的服務(wù)。當(dāng)模塊是服務(wù)消費(fèi)者時,應(yīng)使用此指令。 |
open | 指定當(dāng)前模塊中的類可以通過Java反射訪問。 |
264. 包和模塊有什么區(qū)別?
包和模塊都是一個邏輯單元,都封裝了一些Java文件。然而,兩者之間存在以下幾個差異:
包直接來自Java的早期版本。另一個模塊則是在Java 9后增加的。
-
包可以避免名稱沖突,它們允許在不同包中擁有相同名稱的類。Java添加了模塊,以模塊化JDK并提高安全性。
-
一個包包含一組相關(guān)Java文件。另一方面,一個模塊包含一組相關(guān)包。
-
包不需要描述符(元數(shù)據(jù)),模塊需要一個名為module-info.java的模塊描述符。
-
包不能自行部署;模塊可以自行部署。
-
包中的類通過反射可見。除非在模塊描述符中明確指定了
open
指令,否則模塊中的類無法通過反射可見。
265. Java 9對JDK有哪些主要改進(jìn)?
Java 9利用模塊的優(yōu)點(diǎn)對JDK進(jìn)行了一些根本性的更改。在Java 9之前,在安裝JDK后,會創(chuàng)建一個名為jre\lib
的文件夾, 其中包含所有核心的jar文件。安裝Java 9時,不會再創(chuàng)建jre\lib
文件夾,而是在JDK安裝的根目錄中創(chuàng)建了一個名為jmods
的文件夾。 該文件夾包含所有與核心Java文件相對應(yīng)的模塊。因此,JDK 9沒有一個巨大rt.jar,而是一些單獨(dú)的模塊。
266. 如何將下面代碼作為模塊的一部分進(jìn)行部署?
package mypackage;
public class MyClass {
public void doSomething() {
}
}
上面的代碼定義了一個名為MyClass
的類,位于 mypackage
的包中。為了將上述代碼作為模塊的一部分部署,需要創(chuàng)建一個模塊描述符,如下所示:
module mymodule {
exports mypackage;
}
上述模塊描述符指定了一個名為mymodule
的模塊,使用exports
將包mypackage
導(dǎo)出, 表示mypackage
可用于其他模塊。
267. requires static
模塊指令有什么作用?
requires static
模塊指令用于指定可選的依賴項(xiàng),即在編譯時需要但在運(yùn)行時不需要的依賴項(xiàng)。假設(shè)已經(jīng)開發(fā)了一個模塊,并且需要一些第三方庫,而最終用戶永遠(yuǎn)不會需要這些庫 。在這種情況下, 可以在定義模塊時通過requires static
指令指定第三方庫, 在編譯時需要這些庫,運(yùn)行時不需要它。
268.Java 9在Stream接口上做了哪些改進(jìn)?
以下是Java 9在Stream接口上所做的一些改進(jìn):
-
增加了
Stream.ofNullable()
方法,用于創(chuàng)建一個值可能為空的流。 如果將非空值傳遞給此方法,它將創(chuàng)建一個流,否則創(chuàng)建一個空流。 -
增加了
takeWhile
和dropWhile
方法,用于獲取輸入流的子集。 -
增加了
Stream.iterate()
方法的重載版本,它接受謂詞,并在謂詞指定的條件為真時終止流。
269.下面的代碼有效嗎?如果沒有,可以做些什么來修復(fù)它?
Stream<String> strStream = Stream.of(null);
strStream.forEach(str–> System.out.println(str));
上面的代碼是有效的,不會導(dǎo)致任何編譯錯誤。然而,執(zhí)行時,會導(dǎo)致NullPointerException
異常。這是因?yàn)闊o法使用Stream.of()
方法創(chuàng)建具有空值的流。為了修復(fù)上述代碼,需要進(jìn)行以下更改:
Stream<String> strStream = Stream.ofNullable(null);
strStream.forEach(str–> System.out.println(str));
Java 9為流接口增加了ofNullable()
方法 ,可用來創(chuàng)建具有null
值的流。修改后的代碼不會導(dǎo)致NullPointerException
。
270.下面的代碼片段有什么問題,如何修復(fù)?
List<Integer> numbers = List.of(5,10,15); //Line 1
numbers.add(20); //Line 2
System.out.println(numbers); //Line 3
Java 9為所有集合接口添加了一個of()
靜態(tài)方法, ?用來創(chuàng)建一個無法修改的不可變集合。上面的代碼使用此方法在第1行創(chuàng)建了一個整數(shù)列表。 第2行試圖向該列表添加一個值,會導(dǎo)致運(yùn)行異常,因?yàn)?code>numbers是不可變的,不能夠修改。為了修復(fù)上面的代碼,需要按以下方式重寫代碼:
List<Integer> numbers = List.of(5,10,15,20); //Line 1
System.out.println(numbers); //Line 3
271. 可以使用Java 9的哪種方法創(chuàng)建字符串集合?
Java 9在Set
接口中增加了一個of()
靜態(tài)工廠方法, 可用
來創(chuàng)建 字符串值的集合。如下代碼所示:
Set<String> months = Set.of(“January”,”February”,”March”);
272. 下面代碼片段的輸出是什么?
Stream<Integer> oddNumbers = Stream.iterate(1, num–> num <= 20, num–> num+2);
oddNumbers.forEach(num–> System.out.print(num+” “));
在Java 9之前,Stream.iterate()
方法用于創(chuàng)建一個無限 流。Java 9增加了該方法的一個重載版本,用于創(chuàng)建一個有限流 , 這個重載接受一個額外的謂詞參數(shù), 并在謂詞為真時立即停止流。因此,上述代碼輸出一個有限流如下:
1 3 5 7 9 11 13 15 17 19
273.Java 9對接口進(jìn)行了哪些更改,為什么?
Java 9允許在接口中使用私有方法。在Java 8之前,接口只能有抽象方法。Java 8增加了對靜態(tài)和默認(rèn)接口方法的支持。默認(rèn)和靜態(tài)方法是帶有方法主體的接口。Java 9更進(jìn)一步,允許在接口中使用私有方法。私有接口方法允許重用代碼。因此,如果一個接口有幾個默認(rèn)和靜態(tài)方法,并且這些方法之間有一些通用代碼,則該代碼可以移動到私有方法。如下代碼所示:
public interface Sample {
default method1(){
//some code
doSomething();
}
default method2(){
//some code
doSomething();
}
private void doSomething(){
System.out.println(“Doing something..”);
}
}
上述代碼中,doSomething()
是一個私有接口方法,在默認(rèn)方法method1()
和method2()
中使用。
274.什么是JShell?
Jshell
上是一個命令行工具。允許編寫和運(yùn)行Java代碼,而無需創(chuàng)建類文件。通過在命令窗口鍵入jshell
來啟動。 啟動可以在其中鍵入任何Java代碼,JShell將顯示代碼的執(zhí)行結(jié)果。 例如,如果 鍵入以下內(nèi)容:
System.out.println(“Hello World”);
JShell將打印文本“Hello World”
JShell為Java添加了REPL支持。REPL代表Read Evaluate Print Loop
,Python等許多語言都提供REPL功能。
275. 下面代碼片段的輸出是什么?
Optional<Double> myDoubleOptional = Optional.of(10.0);
Optional<Double> defaultOptional = Optional.of(50.0);
double value = myDoubleOptional.or(()–> defaultOptional).get();
System.out.println(value);
Java 9在Optional
類上增加了一個名為or()
的新方法, 該接受一個 Supplier<Optional>
函數(shù)接口為參數(shù), 并返回一個Optional
。因此,如果調(diào)用它的可選項(xiàng)是非空的,則返回該可選項(xiàng),否則它將返回一個新的Optional
,該可選項(xiàng)由已傳遞的Supplier<Optional>
參數(shù)生成。在上面的代碼片段中,在myDoubleOptional
上調(diào)用or
方法,這是一個值為10的 Optional
,因?yàn)槭且粋€非空的可選項(xiàng),or
方法返回其值,而不是defaultOptional
,因此代碼打印以下輸出:
10.0
276.Java 9對try-with
語句進(jìn)行了哪些更改?
try-with
語句是Java 7增加的, 它允許在沒有明確關(guān)閉語句的情況下自動關(guān)閉資源。 例如,如果正在編寫文件寫代碼,如果使用try-with
語句,一旦try
語句完成,FileWriter
會自動關(guān)閉。這樣做的缺點(diǎn)是,需要自動關(guān)閉的資源必需是try
語句的一部分。因此,如果資源在try-with
語句之外聲明,則需要作為try-with
的一部分再次聲明,比較繁瑣。Java 9廢除了這一限制。 使用Java 9, 可以在try-with
語句之外聲明的資源,并自動關(guān)閉。
277.Java 9在Optional
類上增加的流方法有什么用處?
Java 9在Optional
上增加的stream()
方法可用于將Optional
轉(zhuǎn)換為流。從而允許在Optional
類上應(yīng)用流的所有操作。如下代碼示例 :
Optional<String> str = Optional.of(“Hello”);
Stream<String> strStream = str.stream();
上述代碼中, str
是一個字符串類型的Optional
, 其值是 Hello
,然后使用stream()
方法,將其轉(zhuǎn)換為具有一個String
流。 現(xiàn)在所有流操作,如map
、filter
等,都可以應(yīng)用于此流。
278. ProcessHandle
類的主要作用是什么?
Java 9增加了一個名為java.lang.ProcessHandle
的新類,用于管理與操作系統(tǒng)相關(guān)的進(jìn)程, 主要用途是方便與操作系統(tǒng)交互。該類的一些主要方法如下:
方法 | 描述 |
---|---|
current() | 這是一個靜態(tài)方法,返回當(dāng)前進(jìn)程對應(yīng)的 ProcessHandle 對象。 |
isAlive() | 返回一個布爾值,指示進(jìn)程是否存活。 |
pid() | 返回進(jìn)程的 ID。 |
children() | 返回一個流,其中包含當(dāng)前進(jìn)程的子進(jìn)程對應(yīng)的 ProcessHandle 對象。 |
279. 補(bǔ)充下面代碼中第1行, 使代碼具有下面的預(yù)期輸出 ?
Optional<Double> price = <code here>; //Line 1
price.ifPresentOrElse(val–> System.out.println(“Price is not null”), ()–> System.out.println(“Price not specified”));
預(yù)期輸出:
Price not specified
上面的代碼使用了Java 9在Optional
類上新增的ifPresentOrElse()
方法。該此方法接受Consumer
實(shí)例和Runnable
實(shí)例為參數(shù)。如果Optional
中存在值 ,則調(diào)用傳入的 Consumer
對其進(jìn)行處理 , 否則 ,它將執(zhí)行傳入Runnable
代碼。對于上述情況,因?yàn)樾枰蛴∥粗付▋r格的輸出。與此對應(yīng)的打印語句應(yīng)在Runnable
參數(shù)中指定,price
應(yīng)該是為空的Optional
。 因此,第1行代碼需要補(bǔ)充如下:
Optional<Double> price = Optional.empty();
280.Java 9引入的新HttpClient
有什么優(yōu)勢?
Java 9引入了一個新的HttpClient
類 ,用于通過Java代碼發(fā)出HTTP請求。在Java 9之前,UrlConnection
和HttpUrlConnection
類也可用于發(fā)出HTTP請求。與這些類相比,新的Java HttpClient
有下面幾個優(yōu)勢:
-
HttpUrlConnection
僅支持HTTP 1.1,這是一個非常古老的HTTP版本。HttpClient
則支持 Http 2.0,是HTTP的最新版本。 -
與通過
HttpUrlConnection
編寫的代碼相比,HttpClient
編寫的代碼要干凈得多。 -
HttpClient
通過CompletableFuture
支持異步處理,它有一個名為sendAsync
的方法,可以異步發(fā)送HTTP請求, 并返回一個CompletableFuture
,可用于在請求完成后立即獲取響應(yīng)。
281.解釋Java泛型。
Java 范型允許創(chuàng)建僅接受特定類型數(shù)據(jù)的集合,避免類型轉(zhuǎn)換。泛型的另一個優(yōu)點(diǎn)是, 可以創(chuàng)建適用于不同數(shù)據(jù)類型的通用算法或方法,而無需為每個數(shù)據(jù)類型單獨(dú)編程。
List<String> listGen = new ArrayList<String>(); // 定義ArrayList以存儲字符串對象.
listGen.add("hello"); // 增加一個字符串
String strGen = listGen.get(0); // ArrayList是字符串類型列表 ,因此不需要類型轉(zhuǎn)換.
在上述代碼中,如果增加以下行,會出現(xiàn)編譯錯誤:
listGen.add(21); // 編譯錯誤,因?yàn)?1不是字符串
282. 編寫一個程序來解釋范型方法。
下面程序展示了如何定義一個范型方法:
public class exampleForGenericMethod{
public static <E> void printArrayElements(E[] elementsVal) {
for ( E elementVal : elementsVal){
System.out.println(elementVal);
}
System.out.println();
}
public static void main( String abcs[] ) {
Integer[] myIntArray = { 15, 25, 35, 45, 55 };
Character[] myCharArray = { 'H', 'E', 'L', 'L', 'O','W','O','R','L','D' };
System.out.println( "The Integer Array is:" );
printArrayElements (myIntArray );
System.out.println( "The Character Array is: " );
printArrayElements ( myCharArray );
}
}
上面代碼使用了Java范型方法,避免了方法重載,既可以打印整數(shù)數(shù)組,也可以打印字符串?dāng)?shù)組。
283. List<? extends T>
和 List <? super T>
有什么區(qū)別?
Java范型中,符號?
是一種類型通配符,表示任何類型。? extends T
意味著List
將接受任何擴(kuò)展T
的類型,也就是T
的子類對象。 ? super T
意味著 List
將接受這樣一些類型的對象,它們是T的任何超級類。
284. 解釋以下代碼:
案例 1:
List listORTExample = new ArrayList(); // Line 1
listORTExample.add("abc"); // Line 2
listORTExample.add(123); // Line 3
String strItem = (String) listORTExample.get(0); // Line 4
strItem = (String) listORTExample.get(1); // Line 5
案例 2:
List<String> listOSExample = new ArrayList(); // Line 6
listOSExample.add("abcd"); // Line 7
listOSExample.add(1234); // Line 8
strItem = listOSExample.get(0); // Line 9
第3行- 編譯沒有問題,但運(yùn)行時將拋出異常。
第4行-必須要顯式轉(zhuǎn)換,因?yàn)榱斜碓仡愋惋@示聲明為字符串。
第5行-將拋出ClassCastException
,因?yàn)?code>Integer類型無法轉(zhuǎn)換為String
類型
第8行- 編譯時出現(xiàn)錯誤,因?yàn)榱斜硎褂昧朔缎吐暶鳛樽址斜?/p>
第9行-因?yàn)榱斜硪呀?jīng)聲明為字符串列表,因此不需要顯式轉(zhuǎn)換
上述兩段代碼時使用Java范型如何改進(jìn)程序的經(jīng)典示例。
285. 什么是泛型中的類型參數(shù)?
類型參數(shù)是參數(shù)類型的占位符。類型參數(shù)可用于方法的參數(shù)和方法的返回類型, 以及類型轉(zhuǎn)換中的目標(biāo)類型和參數(shù)化方法的開放類型參數(shù)。類型參數(shù)不能用于創(chuàng)建對象、數(shù)組或異常處理。它不能是靜態(tài)的,也不能與instanceOf
運(yùn)算符一起使用。它不能用作超類型或類的字面量。
Java有5種類型的類型參數(shù)。通常遵守如下約定:
T
表示一種類型
E
表示一種(集合中)元素(類型)
K
表示鍵(類型)
N
表示數(shù)值(類型)
V
表示值(類型)
286. 從集合中檢索元素時如何避免類型轉(zhuǎn)換?
使用范型集合可以避免類型轉(zhuǎn)換。舉例如下:
List<String> gList = new ArrayList<String>();
gList.add("str1");
gList.add("str2");
String g0 = gList.get(0); //無需類型轉(zhuǎn)換
287. 下面代碼會編譯嗎?能否正確運(yùn)行?
public static void main(String[] args) {
List<String> typeSafeList = newArrayList<String>();
typeSafeList.add(new String("string1"));
addElementsToList(typeSafeList);
String a = typeSafeList.get(1);
}
private static void addElementsToList(List list){
list.add(new Integer(10));
}
代碼編譯沒有問題,但運(yùn)行會出現(xiàn)如下類型轉(zhuǎn)換錯誤:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
288.在范型聲明中可以使用多個參數(shù)化類型嗎?
可以。如下示例:
public class UseTwo<T, X> { }
289. 如何定義泛型方法?
定義范型方法的語法有點(diǎn)棘手,需要在返回類型前聲明范型參數(shù)。下面是一個示例:
public <T> void makeList(T t) { }
289.可以實(shí)例化一個范型數(shù)組嗎?
可以聲明范型數(shù)組,但不能像普通數(shù)組一樣實(shí)例化 。否則會編譯錯誤,因?yàn)榫幾g器在編譯過程中還不知道數(shù)組的類型。 它必須使用 new
操作符和類型轉(zhuǎn)換為數(shù)組進(jìn)行實(shí)例化。
//聲明并初始化范型數(shù)組
arrType<String> [] abc = new arrType[50];//下面代碼錯誤
arrType2<xyz> [] abc = new arrType<xyz>[50];
290.什么是對象序列化? 如何實(shí)現(xiàn)序列化 ?
對象序列化是將對象的屬性和行為寫入字節(jié)流或文件, 對象中引用的的所有可序列化對象也都寫入文件中, 序列化操作保存了對象的瞬時狀態(tài) 。當(dāng)對象必須通過網(wǎng)絡(luò)發(fā)送時,通常會使用序列化。如果類實(shí)現(xiàn)了Externalizable
接口或者Serializable
接口 ,其對象便是可序列化的。前者必須實(shí)現(xiàn)readExternal()
和writeExternal()
方法,后者是一個標(biāo)記接口,沒有定義任何方法。 序列化的具體過程是,對象可以傳遞給ObjectOutputStream
,而ObjectOutputStream
又將其傳遞給文件輸出流。 。