JavaSE面試題之基本IO流及面試官寫了個雙冒號考試答案[圖]

minemi發表於2020-12-09

一、JavaSE面試題之基本IO流
今天這篇是JavaSE系列的第十四篇,主要總結了Java中的IO流的問題,IO流分為兩篇來講,這篇是第一篇,主要是基本IO流,第二篇主要為網路IO流,在後續,會沿著第一篇開篇的知識線路一直總結下去,做到日更!如果我能做到百日百更,希望你也可以跟著百日百刷,一百天養成一個好習慣。
Q:
什麼是IO流?
它是一種資料的流從源頭流到目的地。比如檔案拷貝,輸入流和輸出流都包括了。輸入流從檔案中讀取資料儲存到程式(process)中,輸出流從程式中讀取資料然後寫入到目標檔案。

JavaSE面試題之基本IO流及面試官寫了個雙冒號考試答案[圖]

Q:
Java中有幾種型別的流?
按照流的方向:
輸入流(inputStream)
輸出流(outputStream)。
按照實現功能分:
節點流(可以從或向一個特定的地方(節點)讀寫資料。如FileReader)
處理流(是對一個已存在的流的連線和封裝,通過所封裝的流的功能呼叫實現資料讀寫。如BufferedReader。處理流的構造方法總是要帶一個其他的流物件做引數。一個流物件經過其他流的多次包裝,稱為流的連結。)
按照處理資料的單位:
位元組流
字元流
位元組流繼承於InputStream和OutputStream
字元流繼承於InputStreamReader和OutputStreamWriter
字元流.png
位元組流.png
Q:
位元組流和字元流的區別?
位元組流在JDK1.0中就被引進了,用於操作包含ASCII字元的檔案。JAVA也支援其他的字元如Unicode,為了讀取包含Unicode字元的檔案,JAVA語言設計者在JDK1.1中引入了字元流。ASCII作為Unicode的子集,對於英語字元的檔案,可以可以使用位元組流也可以使用字元流。
Q:
位元組流有了為什麼還要有字元流?
字元流是由Java虛擬機器將位元組轉換得到的,問題就出在這個過程還算是非常耗時,並且,如果我們不知道編碼型別就很容易出現亂碼問題。所以,I/O流就乾脆提供了一個直接操作字元的介面,方便我們平時對字元進行流操作。如果音訊檔案、圖片等媒體檔案用位元組流比較好,如果涉及到字元的話使用字元流比較好。
Q:
FileInputStream和FileOutputStream是什麼?
這是在拷貝檔案操作的時候,經常用到的兩個類。在處理小檔案的時候,它們效能表現還不錯,在大檔案的時候,最好使用BufferedInputStream(或BufferedReader)和BufferedOutputStream(或BufferedWriter)
Q:
Files的常用方法都有哪些?
Files.size():檢視檔案個數。
Files.read():讀取檔案。
Files.write():寫入檔案。
Files.exists():檢測檔案路徑是否存在。
Files.createFile():建立檔案。
Files.createDirectory():建立資料夾。
Files.delete():刪除一個檔案或目錄。
Files.copy():複製檔案。
Files.move():移動檔案。
Q:
什麼是java序列化,如何實現java序列化?
序列化:
是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化。可以對流化後的物件進行讀寫操作,也可將流化後的物件傳輸於網路之間。序列化是為了解決在對物件流進行讀寫操作時所引發的問題。
序列化的實現:
將需要被序列化的類實現
Serializable

介面,該介面沒有需要實現的方法,implementsSerializable只是為了標註該物件是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(物件流)物件,接著,作文(https://www.isanxia.com)使用ObjectOutputStream物件的writeObject(Objectobj)方法就可以將引數為obj的物件寫出(即儲存其狀態),要恢復的話則用輸入流。

Q:
如何將一個java物件序列化到檔案裡?
在java中能夠被序列化的類必須先實現
Serializable
介面,該介面沒有任何抽象方法只是起到一個標記作用。
Q:
如何實現物件克隆?
兩種方式:
實現Cloneable介面並重寫Object類中的clone()方法;
實現Serializable介面,通過物件的序列化和反序列化實現克隆,可以實現真正的深度克隆。
注意:基於序列化和反序列化實現的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的物件是否支援序列化,這項檢查是編譯器完成的,不是在執行時丟擲異常,這種是方案明顯優於使用Object類的clone方法克隆物件。讓問題在編譯的時候暴露出來總是好過把問題留到執行時。
二、Java面試官寫了個雙冒號
一:簡潔
方法引用分為三種,方法引用通過一對雙冒號::來表示,方法引用是一種函式式介面的另一種書寫方式
靜態方法引用,通過類名::靜態方法名,如Integer::parseInt
例項方法引用,通過例項物件::例項方法,如str::substring
構造方法引用,通過類名::new,如User::new
二:方法引用
publicfinalclassInteger{
publicstaticintparseInt(Strings)throwsNumberFormatException{
returnparseInt(s,10);
}
}
通過方法引用,可以將方法的引用賦值給一個變數,通過賦值給Function,說明方法引用也是一種函式式介面的書寫方式,Lambda表示式也是一種函式式介面,Lambda表示式一般用於自己提供方法體,而方法引用一般直接引用現成的方法。
publicclassUser{
privateStringusername;
privateIntegerage;
publicUser(){
}
publicUser(Stringusername,Integerage){
this.username=username;
this.age=age;
}
@Override
publicStringtoString(){
return"User{"+
"username='"+username+'\''+
",age="+age+
'}';
}
//Getter&Setter
}
publicstaticvoidmain(String[]args){
//使用雙冒號::來構造靜態函式引用
Function<String,Integer>fun=Integer::parseInt;
Integervalue=fun.apply("123");
System.out.println(value);
//使用雙冒號::來構造非靜態函式引用
Stringcontent="HelloJDK8";
Function<Integer,String>func=content::substring;
Stringresult=func.apply(1);
System.out.println(result);
//建構函式引用
BiFunction<String,Integer,User>biFunction=User::new;
Useruser=biFunction.apply("mengday",28);
System.out.println(user.toString());
//函式引用也是一種函式式介面,所以也可以將函式引用作為方法的引數
sayHello(String::toUpperCase,"hello");
}
//方法有兩個引數,一個是
privatestaticvoidsayHello(Function<String,String>func,Stringparameter){
Stringresult=func.apply(parameter);
System.out.println(result);
}
三:Optional可選值
在GoogleGuava中就有Optional,在Swift語言中也有這樣類似的語法,在Swift中將可選值作為一種資料型別,地位和基本型別平齊平做,地位非常高。
packagejava.util;
importjava.util.function.Consumer;
importjava.util.function.Function;
importjava.util.function.Predicate;
importjava.util.function.Supplier;
/**
*@since1.8
*/
publicfinalclassOptional<T>{
privatestaticfinalOptional<?>EMPTY=newOptional<>();
privatefinalTvalue;
privateOptional(){
this.value=null;
}
//返回一個空的Optional例項
publicstatic<T>Optional<T>empty(){
@SuppressWarnings("unchecked")
Optional<T>t=(Optional<T>)EMPTY;
returnt;
}
privateOptional(Tvalue){
this.value=Objects.requireNonNull(value);
}
//返回具有Optional的當前非空值的Optional
publicstatic<T>Optional<T>of(Tvalue){
returnnewOptional<>(value);
}
//返回一個Optional指定值的Optional,如果非空,則返回一個空的Optional
publicstatic<T>Optional<T>ofNullable(Tvalue){
returnvalue==null?empty():of(value);
}
//如果Optional中有一個值,返回值,否則丟擲NoSuchElementException。
publicTget(){
if(value==null){
thrownewNoSuchElementException("Novaluepresent");
}
returnvalue;
}
//返回true如果存在值,否則為false
publicbooleanisPresent(){
returnvalue!=null;
}
//如果存在值,則使用該值呼叫指定的消費者,否則不執行任何操作。
publicvoidifPresent(Consumer<?superT>consumer){
if(value!=null)
consumer.accept(value);
}
//如果一個值存在,並且該值給定的謂詞相匹配時,返回一個Optional描述的值,否則返回一個空的Optional
publicOptional<T>filter(Predicate<?superT>predicate){
Objects.requireNonNull(predicate);
if(!isPresent())
returnthis;
else
returnpredicate.test(value)?this:empty();
}
//如果存在一個值,則應用提供的對映函式,如果結果不為空,則返回一個Optional結果的Optional。
public<U>Optional<U>map(Function<?superT,?extendsU>mapper){
Objects.requireNonNull(mapper);
if(!isPresent())
returnempty();
else{
returnOptional.ofNullable(mapper.apply(value));
}
}
//如果一個值存在,應用提供的Optional對映函式給它,返回該結果,否則返回一個空的Optional。
public<U>Optional<U>flatMap(Function<?superT,Optional<U>>mapper){
Objects.requireNonNull(mapper);
if(!isPresent())
returnempty();
else{
returnObjects.requireNonNull(mapper.apply(value));
}
}
//如果值存在,就返回值,不存在就返回指定的其他值
publicTorElse(Tother){
returnvalue!=null?value:other;
}
publicTorElseGet(Supplier<?extendsT>other){
returnvalue!=null?value:other.get();
}
public<XextendsThrowable>TorElseThrow(Supplier<?extendsX>exceptionSupplier)throwsX{
if(value!=null){
returnvalue;
}else{
throwexceptionSupplier.get();
}
}
}
關於of方法,現在好像很流行,就是提供一個static方法,方法名稱叫of,方法的返回值返回當前類,並且把建構函式設定為私有private,用靜態of方法來代替建構函式。
publicclassUser{
privateStringusername;
privateIntegerage;
privateUser(){
}
publicstaticUserof(){
returnnewUser();
}
privateUser(Stringusername,Integerage){
this.username=username;
this.age=age;
}
publicstaticUserof(Stringusername,Integerage){
returnnewUser(username,age);
}
}
Main
publicstaticvoidmain(String[]args){
//Optional類已經成為Java8類庫的一部分,在Guava中早就有了,可能Oracle是直接拿來使用了
//Optional用來解決空指標異常,使程式碼更加嚴謹,防止因為空指標NullPointerException對程式碼造成影響
Stringmsg="hello";
Optional<String>optional=Optional.of(msg);
//判斷是否有值,不為空
booleanpresent=optional.isPresent();
//如果有值,則返回值,如果等於空則拋異常
Stringvalue=optional.get();
//如果為空,返回else指定的值
Stringhi=optional.orElse("hi");
//如果值不為空,就執行Lambda表示式
optional.ifPresent(opt->System.out.println(opt));
}

相關文章