1,JDK和JRE有什麼區別? JRE:Java Runtime Environment( java 運行時環境)。即java程式的運行時環境,包含了 java 虛擬機,java基礎類庫。 JDK:Java Development Kit( java 開發工具包)。即java語言編寫的程式所需的開發 ...
1,JDK和JRE有什麼區別?
JRE:Java Runtime Environment( java 運行時環境)。即java程式的運行時環境,包含了 java 虛擬機,java基礎類庫。
JDK:Java Development Kit( java 開發工具包)。即java語言編寫的程式所需的開發工具包。JDK 包含了 JRE,同時還包括 java 源碼的編譯器 javac、監控工具 jconsole、分析工具 jvisualvm等。
2,==和equals的區別是什麼?
== 是關係運算符,equals() 是方法,結果都返回布爾值
Object 的 == 和 equals() 比較的都是地址,作用相同
== 作用:
基本類型,比較值是否相等
引用類型,比較記憶體地址值是否相等
不能比較沒有父子關係的兩個對象
equals()方法的作用:
JDK 中的類一般已經重寫了 equals(),比較的是內容
自定義類如果沒有重寫 equals(),將調用父類(預設 Object 類)的 equals() 方法,Object 的 equals() 比較使用了 this == obj
可以按照需求邏輯,重寫對象的 equals() 方法(重寫 equals 方法,一般須重寫 hashCode 方法)
3,==和equals的區別是什麼?
不屬於。
Java 中 8 種基礎的數據類型:byte、short、char、int、long、float、double、boolean
但是 String 類型卻是最常用到的引用類型。
4,普通類和抽象類有哪些區別?
抽象類不能被實例化
抽象類可以有抽象方法,抽象方法只需申明,無需實現
含有抽象方法的類必須申明為抽象類
抽象類的子類必須實現抽象類中所有抽象方法,否則這個子類也是抽象類
抽象方法不能被聲明為靜態
抽象方法不能用 private 修飾
抽象方法不能用 final 修飾
5,JDK、JRE、JVM之間的關係是什麼樣的?
JDK 是 JAVA 程式開發時用的開發工具包,包含 Java 運行環境 JRE
JDk、JRE 內部都包含 JAVA虛擬機 JVM
JVM 包含 Java 應用程式的類的解釋器和類載入器等
6,講講面向對象三大特征
封裝
封裝:就是隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。讓使用者知道的才暴露出來,不需要讓使用者知道的全部隱藏起來
封裝的好處:避免使用者直接操作屬性值,隱藏類的實現細節;讓使用者只能通過程式員規定的方法來訪問數據;可以方便的加入存取控制語句,限制不合理操作,提高程式安全性。
繼承
繼承是類與類之間的關係,與現實世界中的繼承(例如孩子繼承父母基因)類似。
繼承可以理解為一個類從另一個類獲取方法和屬性的過程。
例如:類B繼承於類A,那麼B就擁有A的部分方法和屬性(private修飾或不在同一個包default修飾的無法訪問)。
3.多態
多態是同一個行為具有多個不同表現形式或形態的能力。
多態分類和實現
編譯時多態(靜態多態):方法重載實現的多態
運行時多態(動態多態):類繼承/介面實現 + 重寫 + 向上轉型實現的多態
基於繼承/介面來實現的多態:面向介面的方式編程為的就是可以使用多態的特性讓編程變得更加靈活。
多態的優點:消除類型之間的耦合關係(可替換性,可擴充性,介面性,靈活性,簡化性)
7,什麼是泛型?為什麼要使用泛型?
泛型:
"參數化類型",將類型由具體的類型參數化,把類型也定義成參數形式(稱之為類型形參),然後在使用/調用時傳入具體的類型(類型實參)。
是 JDK 5 中引入的一個新特性,提供了編譯時類型安全監測機制,該機制允許程式員在編譯時監測非法的類型。
泛型的本質是把參數的類型參數化,也就是所操作的數據類型被指定為一個參數,這種參數類型可以用在類、介面和方法中。
為什麼要用泛型?
使用泛型編寫的程式代碼,要比使用 Object 變數再進行強制類型轉換的代碼,具有更好的安全性和可讀性。
多種數據類型執行相同的代碼使用泛型可以復用代碼。
比如集合類使用泛型,取出和操作元素時無需進行類型轉換,避免出現 java.lang.ClassCastException 異常
8,String、StringBuilder、StringBuffer的區別?
相同點:
都可以儲存和操作字元串
都使用 final 修飾,不能被繼承
提供的 API 相似
區別:
String 是只讀字元串,String 對象內容是不能被改變的
StringBuffer 和 StringBuilder 的字元串對象可以對字元串內容進行修改,在修改後的記憶體地址不會發生改變
StringBuilder 線程不安全;StringBuffer 線程安全
方法體內沒有對字元串的併發操作,且存在大量字元串拼接操作,建議使用 StringBuilder,效率較高。
9,&和&&的作用和區別
&
邏輯與,& 兩邊的表達式都會進行運算
整數的位運算符
&&
短路與,&& 左邊的表達式結果為 false 時,&& 右邊的表達式不參與計算
10,說一說你的對面向過程和麵向對象的理解
軟體開發思想,先有面向過程,後有面向對象
在大型軟體系統中,面向過程的做法不足,從而推出了面向對象
都是解決實際問題的思維方式
兩者相輔相成,巨集觀上面向對象把握複雜事物的關係;微觀上面向過程去處理
面向過程以實現功能的函數開發為主;面向對象要首先抽象出類、屬性及其方法,然後通過實例化類、執行方法來完成功能
面向過程是封裝的是功能;面向對象封裝的是數據和功能
面向對象具有繼承性和多態性;面向過程則沒有
11,說一說你的對面向過程和麵向對象的理解
垃圾回收機制,簡稱 GC
Java 語言不需要程式員直接控制記憶體回收,由 JVM 在後臺自動回收不再使用的記憶體
提高編程效率
保護程式的完整性
JVM 需要跟蹤程式中有用的對象,確定哪些是無用的,影響性能
特點
回收 JVM 堆記憶體里的對象空間,不負責回收棧記憶體數據
無法處理一些操作系統資源的釋放,如資料庫連接、輸入流輸出流、Socket 連接
垃圾回收發生具有不可預知性,程式無法精確控制垃圾回收機制執行
可以將對象的引用變數設置為 null,垃圾回收機制可以在下次執行時回收該對象。
JVM 有多種垃圾回收 實現演算法,表現各異
垃圾回收機制回收任何對象之前,會先調用對象的 finalize() 方法
可以通過 System.gc() 或 Runtime.getRuntime().gc() 通知系統進行垃圾回收,會有一些效果,但系統是否進行垃圾回收依然不確定
不要主動調用對象的 finalize() 方法,應該交給垃圾回收機制調用
12,說一說你的對面向過程和麵向對象的理解
記憶體溢出(out of memory):指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現 out of memory。
記憶體泄露(memory leak):指程式在申請記憶體後,無法釋放已申請的記憶體空間,記憶體泄露堆積會導致記憶體被占光。
memory leak 最終會導致 out of memory。
13,說一說你的對面向過程和麵向對象的理解
final 表示最終的、不可改變的。用於修飾類、方法和變數。final 修飾的類不能被繼承;final 方法也同樣只能使用,不能重寫,但能夠重載;final 修飾的成員變數必須在聲明時給定初值或者在構造方法內設置初始值,只能讀取,不可修改;final 修飾的局部變數必須在聲明時給定初值;final 修飾的變數是非基本類型,對象的引用地址不能變,但對象的屬性值可以改變
finally 異常處理的一部分,它只能用在 try/catch 語句中,表示希望 finally 語句塊中的代碼最後一定被執行(存在一些情況導致 finally 語句塊不會被執行,如 jvm 結束)
finalize() 是在 java.lang.Object 里定義的,Object 的 finalize() 方法什麼都不做,對象被回收時 finalize() 方法會被調用。Java 技術允許使用 finalize() 方法在垃圾收集器將對象從記憶體中清除出去之前做必要清理工作,在垃圾收集器刪除對象之前被調用的。一般情況下,此方法由JVM調用。特殊情況下,可重寫 finalize() 方法,當對象被回收的時候釋放一些資源,須調用 super.finalize() 。
14,return與finally的執行順序對返回值的影響
對於 try 和 finally 至少一個語句塊包含 return 語句的情況:
finally 語句塊會執行
finally 沒有 return,finally 對 return 變數的重新賦值修改無效
try 和 finally 都包含 return,return 值會以 finally 語句塊 return 值為準
如下麵的例子
如下麵的例子
public static void main(String[] args) {
System.out.println(getString());
}
public static String getString() {
String str = "A";
try {
str = "B";
return str;
} finally {
System.out.println("finally change return string to C");
str = "C";
}
}
列印
finally change return string to C
B
finally 語句塊中新增 return 語句
public static void main(String[] args) {
System.out.println(getString());
}
public static String getString() {
String str = "A";
try {
str = "B";
return str;
} finally {
System.out.println("finally change return string to C");
str = "C";
return str;
}
}
列印結果
finally change return string to C
C
15,Math.round(-1.5) 等於多少?
運行結果: -1
JDK 中的 java.lang.Math 類
ceil() :向上取整,返回小數所在兩整數間的較大值,返回類型是 double,如 -1.5 返回 -1.0
floor() :向下取整,返回小數所在兩整數間的較小值,返回類型是 double,如 -1.5 返回 -2.0
round() :朝正無窮大方向返回參數最接近的整數,可以換算為 參數 + 0.5 向下取整,返回值是 int 或 long,如 -1.5 返回 -1
16,抽象類能使用final修飾嗎?
不能,抽象類是被用於繼承的,final修飾代表不可修改、不可繼承的。
17,抽象類能使用final修飾嗎?
throw:
表示方法內拋出某種異常對象(只能是一個)
用於程式員自行產生並拋出異常
位於方法體內部,可以作為單獨語句使用
如果異常對象是非 RuntimeException 則需要在方法申明時加上該異常的拋出,即需要加上 throws 語句 或者 在方法體內 try catch 處理該異常,否則編譯報錯
執行到 throw 語句則後面的語句塊不再執行
throws:
方法的定義上使用 throws 表示這個方法可能拋出某些異常(可以有多個)
用於聲明在該方法內拋出了異常
必須跟在方法參數列表的後面,不能單獨使用
需要由方法的調用者進行異常處理
18,動態代理是什麼?應用場景?
動態代理:在運行時,創建目標類,可以調用和擴展目標類的方法。
Java 中實現動態的方式:
JDK 中的動態代理
Java類庫 CGLib
應用場景:
統計每個 api 的請求耗時
統一的日誌輸出
校驗被調用的 api 是否已經登錄和許可權鑒定
Spring的 AOP 功能模塊就是採用動態代理的機制來實現切麵編程
19,動態代理是什麼?應用場景?
final 語義是不可改變的。
被 final 修飾的類,不能夠被繼承
被 final 修飾的成員變數必須要初始化,賦初值後不能再重新賦值(可以調用對象方法修改屬性值)。對基本類型來說是其值不可變;對引用變數來說其引用不可變,即不能再指向其他的對象
被 final 修飾的方法不能重寫
20,finally語句塊一定執行嗎?
答案是不一定。存在很多特殊情況導致 finally 語句塊不執行。如:
直接返回未執行到 try-finally 語句塊
拋出異常未執行到 try-finally 語句塊
系統退出未執行到 finally 語句塊
21,String屬於基礎的數據類型嗎?
不屬於。
Java 中 8 種基礎的數據類型:byte、short、char、int、long、float、double、boolean
但是 String 類型卻是最常用到的引用類型。
22,面向對象和麵向過程的區別?
面向過程:
優點:性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般採用面向過程開發,性能是最重要的因素。
缺點:沒有面向對象易維護、易復用、易擴展。
面向對象:
優點:易維護、易復用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護。
缺點:性能比面向過程低。
23,面向對象和麵向過程的區別?
方法的重載和重寫都是實現多態的方式,區別在於前者實現的是編譯時的多態性,而後者實現的是運行時的多態性。
重寫發生在子類與父類之間, 重寫方法返回值和形參都不能改變,與方法返回值和訪問修飾符無關,即重載的方法不能根據返回類型進行區分。即外殼不變,核心重寫!
重載(overloading) 是在一個類裡面,方法名字相同,而參數不同。返回類型可以相同也可以不同。每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。最常用的地方就是構造器的重載。
24,抽象類和介面的區別是什麼?
語法層面上的區別:
抽象類可以提供成員方法的實現細節,而介面中只能存在public abstract 方法;
抽象類中的成員變數可以是各種類型的,而介面中的成員變數只能是public static final類型的;
介面中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法;
一個類只能繼承一個抽象類,而一個類卻可以實現多個介面。
設計層面上的區別:
抽象類是對一種事物的抽象,即對類抽象,而介面是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是介面卻是對類局部(行為)進行抽象。
設計層面不同,抽象類作為很多子類的父類,它是一種模板式設計。而介面是一種行為規範,它是一種輻射式設計。
25,java 創建對象有哪幾種方式?
java中提供了以下四種創建對象的方式:
new創建新對象
通過反射機制
採用clone機制
通過序列化機制
前兩者都需要顯式地調用構造方法。對於clone機制,需要註意淺拷貝和深拷貝的區別,對於序列化機制需要明確其實現原理,在java中序列化可以通過實現Externalizable或者Serializable來實現。
26,為什麼重寫 equals 方法必須重寫 hashcode 方法 ?
判斷的時候先根據hashcode進行的判斷,相同的情況下再根據equals()方法進行判斷。如果只重寫了equals方法,而不重寫hashcode的方法,會造成hashcode的值不同,而equals()方法判斷出來的結果為true。
在Java中的一些容器中,不允許有兩個完全相同的對象,插入的時候,如果判斷相同則會進行覆蓋。這時候如果只重寫了equals()的方法,而不重寫hashcode的方法,Object中hashcode是根據對象的存儲地址轉換而形成的一個哈希值。這時候就有可能因為沒有重寫hashcode方法,造成相同的對象散列到不同的位置而造成對象的不能覆蓋的問題。
27,包裝類型是什麼?基本類型和包裝類型有什麼區別?
Java 為每一個基本數據類型都引入了對應的包裝類型(wrapper class),int 的包裝類就是 Integer,從 Java 5 開始引入了自動裝箱/拆箱機制,把基本類型轉換成包裝類型的過程叫做裝箱(boxing);反之,把包裝類型轉換成基本類型的過程叫做拆箱(unboxing),使得二者可以相互轉換。
Java 為每個原始類型提供了包裝類型:
原始類型: boolean,char,byte,short,int,long,float,double
包裝類型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
基本類型和包裝類型的區別主要有以下 幾點:
包裝類型可以為 null,而基本類型不可以。它使得包裝類型可以應用於 POJO 中,而基本類型則不行。那為什麼 POJO 的屬性必須要用包裝類型呢?《阿裡巴巴 Java 開發手冊》上有詳細的說明, 資料庫的查詢結果可能是 null,如果使用基本類型的話,因為要自動拆箱(將包裝類型轉為基本類型,比如說把 Integer 對象轉換成 int 值),就會拋出 NullPointerException 的異常。
包裝類型可用於泛型,而基本類型不可以。泛型不能使用基本類型,因為使用基本類型時會編譯出錯。
List<int> list = new ArrayList<>(); // 提示 Syntax error, insert "Dimensions" to complete ReferenceType
List<Integer> list = new ArrayList<>();
因為泛型在編譯時會進行類型擦除,最後只保留原始類型,而原始類型只能是 Object 類及其子類——基本類型是個特例。
基本類型比包裝類型更高效。基本類型在棧中直接存儲的具體數值,而包裝類型則存儲的是堆中的引用。 很顯然,相比較於基本類型而言,包裝類型需要占用更多的記憶體空間。
28,int 和 Integer 有什麼區別?
Integer是int的包裝類;int是基本數據類型;
Integer變數必須實例化後才能使用;int變數不需要;
Integer實際是對象的引用,指向此new的Integer對象;int是直接存儲數據值 ;
Integer的預設值是null;int的預設值是0。
29,什麼是反射?反射機制的優缺點有哪些?
反射是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為 Java 語言的反射機制。
優點:能夠運行時動態獲取類的實例,提高靈活性;可與動態編譯結合Class.forName('com.mysql.jdbc.Driver.class');,載入MySQL的驅動類。
缺點:使用反射性能較低,需要解析位元組碼,將記憶體中的對象進行解析。其解決方案是:通過setAccessible(true)關閉JDK的安全檢查來提升反射速度;多次創建一個類的實例時,有緩存會快很多;ReflflectASM工具類,通過位元組碼生成的方式加快反射速度。
30,Java反射API有幾類?
反射 API 用來生成 JVM 中的類、介面或則對象的信息。
Class 類:反射的核心類,可以獲取類的屬性,方法等信息。
Field 類:Java.lang.reflec 包中的類,表示類的成員變數,可以用來獲取和設置類之中的屬性值。
Method 類:Java.lang.reflec 包中的類,表示類的方法,它可以用來獲取類中的方法信息或者執行方法。
Constructor 類:Java.lang.reflec 包中的類,表示類的構造方法。
31,Java序列化與反序列化是什麼?
Java序列化是指把Java對象轉換為位元組序列的過程,而Java反序列化是指把位元組序列恢復為Java對象的過程:
序列化:序列化是把對象轉換成有序位元組流,以便在網路上傳輸或者保存在本地文件中。核心作用是對象狀態的保存與重建。我們都知道,Java對象是保存在JVM的堆記憶體中的,也就是說,如果JVM堆不存在了,那麼對象也就跟著消失了。
而序列化提供了一種方案,可以讓你在即使JVM停機的情況下也能把對象保存下來的方案。就像我們平時用的U盤一樣。把Java對象序列化成可存儲或傳輸的形式(如二進位流),比如保存在文件中。這樣,當再次需要這個對象的時候,從文件中讀取出二進位流,再從二進位流中反序列化出對象。
反序列化:客戶端從文件中或網路上獲得序列化後的對象位元組流,根據位元組流中所保存的對象狀態及描述信息,通過反序列化重建對象。
32,為什麼需要序列化與反序列化?
簡要描述:對記憶體中的對象進行持久化或網路傳輸, 這個時候都需要序列化和反序列化
深入描述:
對象序列化可以實現分散式對象。
主要應用例如:RMI(即遠程調用Remote Method Invocation)要利用對象序列化運行遠程主機上的服務,就像在本地機上運行對象時一樣。
java對象序列化不僅保留一個對象的數據,而且遞歸保存對象引用的每個對象的數據。
可以將整個對象層次寫入位元組流中,可以保存在文件中或在網路連接上傳遞。利用對象序列化可以進行對象的"深複製",即複製對象本身及引用的對象本身。序列化一個對象可能得到整個對象序列。
序列化可以將記憶體中的類寫入文件或資料庫中。
比如:將某個類序列化後存為文件,下次讀取時只需將文件中的數據反序列化就可以將原先的類還原到記憶體中。也可以將類序列化為流數據進行傳輸。
總的來說就是將一個已經實例化的類轉成文件存儲,下次需要實例化的時候只要反序列化即可將類實例化到記憶體中並保留序列化時類中的所有變數和狀態。
對象、文件、數據,有許多不同的格式,很難統一傳輸和保存。
序列化以後就都是位元組流了,無論原來是什麼東西,都能變成一樣的東西,就可以進行通用的格式傳輸或保存,傳輸結束以後,要再次使用,就進行反序列化還原,這樣對象還是對象,文件還是文件。
33,為什麼需要序列化與反序列化?
java.lang.IllegalAccessError:違法訪問錯誤。當一個應用試圖訪問、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則拋出該異常。
java.lang.InstantiationError:實例化錯誤。當一個應用試圖通過Java的new操作符構造一個抽象類或者介面時拋出該異常.
java.lang.OutOfMemoryError:記憶體不足錯誤。當可用記憶體不足以讓Java虛擬機分配給一個對象時拋出該錯誤。
java.lang.StackOverflowError:堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導致堆棧溢出或者陷入死迴圈時拋出該錯誤。
java.lang.ClassCastException:類造型異常。假設有類A和B(A不是B的父類或子類),O是A的實例,那麼當強制將O構造為類B的實例時拋出該異常。該異常經常被稱為強制類型轉換異常。
java.lang.ClassNotFoundException:找不到類異常。當應用試圖根據字元串形式的類名構造類,而在遍歷CLASSPAH之後找不到對應名稱的class文件時,拋出該異常。
java.lang.ArithmeticException:算術條件異常。譬如:整數除零等。
java.lang.ArrayIndexOutOfBoundsException:數組索引越界異常。當對數組的索引值為負數或大於等於數組大小時拋出。
java.lang.IndexOutOfBoundsException:索引越界異常。當訪問某個序列的索引值小於0或大於等於序列大小時,拋出該異常。
java.lang.InstantiationException:實例化異常。當試圖通過newInstance()方法創建某個類的實例,而該類是一個抽象類或介面時,拋出該異常。
java.lang.NoSuchFieldException:屬性不存在異常。當訪問某個類的不存在的屬性時拋出該異常。
java.lang.NoSuchMethodException:方法不存在異常。當訪問某個類的不存在的方法時拋出該異常。
java.lang.NullPointerException:空指針異常。當應用試圖在要求使用對象的地方使用了null時,拋出該異常。譬如:調用null對象的實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語句拋出null等等。
java.lang.NumberFormatException:數字格式異常。當試圖將一個String轉換為指定的數字類型,而該字元串確不滿足數字類型要求的格式時,拋出該異常。
java.lang.StringIndexOutOfBoundsException:字元串索引越界異常。當使用索引值訪問某個字元串中的字元,而該索引值小於0或大於等於序列大小時,拋出該異常。
34,try-catch-finally 中哪個部分可以省略?
catch 可以省略。更為嚴格的說法其實是:try只適合處理運行時異常,try+catch適合處理運行時異常+普通異常。也就是說,如果你只用try去處理普通異常卻不加以catch處理,編譯是通不過的,因為編譯器硬性規定,普通異常如果選擇捕獲,則必須用catch顯示聲明以便進一步處理。而運行時異常在編譯時沒有如此規定,所以catch可以省略,你加上catch編譯器也覺得無可厚非。
理論上,編譯器看任何代碼都不順眼,都覺得可能有潛在的問題,所以你即使對所有代碼加上try,代碼在運行期時也只不過是在正常運行的基礎上加一層皮。但是你一旦對一段代碼加上try,就等於顯示地承諾編譯器,對這段代碼可能拋出的異常進行捕獲而非向上拋出處理。如果是普通異常,編譯器要求必須用catch捕獲以便進一步處理;如果運行時異常,捕獲然後丟棄並且+finally掃尾處理,或者加上catch捕獲以便進一步處理。
至於加上finally,則是在不管有沒捕獲異常,都要進行的“掃尾”處理。
35,JVM 是如何處理異常的?
在一個方法中如果發生異常,這個方法會創建一個異常對象,並轉交給 JVM,該異常對象包含異常名稱,異常描述以及異常發生時應用程式的狀態。創建異常對象並轉交給 JVM 的過程稱為拋出異常。可能有一系列的方法調用,最終才進入拋出異常的方法,這一系列方法調用的有序列表叫做調用棧。
JVM 會順著調用棧去查找看是否有可以處理異常的代碼,如果有,則調用異常處理代碼。當 JVM 發現可以處理異常的代碼時,會把發生的異常傳遞給它。如果 JVM 沒有找到可以處理該異常的代碼塊,JVM 就會將該異常轉交給預設的異常處理器(預設處理器為 JVM 的一部分),預設異常處理器列印出異常信息並終止應用程式。
36,Java的IO 流分為幾種?
按照流的方向:輸入流(inputStream)和輸出流(outputStream);
按照實現功能分:節點流(可以從或向一個特定的地方讀寫數據,如 FileReader)和處理流(是對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀寫, BufferedReader);
按照處理數據的單位: 位元組流和字元流。分別由四個抽象類來表示(每種流包括輸入和輸出兩種所以一共四個):InputStream,OutputStream,Reader,Writer。Java中其他多種多樣變化的流均是由它們派生出來的。
37,位元組流如何轉為字元流?
位元組輸入流轉字元輸入流通過 InputStreamReader 實現,該類的構造函數可以傳入 InputStream 對象。
位元組輸出流轉字元輸出流通過 OutputStreamWriter 實現,該類的構造函數可以傳入 OutputStream 對象。
38,字元流與位元組流的區別?
讀寫的時候位元組流是按位元組讀寫,字元流按字元讀寫。
位元組流適合所有類型文件的數據傳輸,因為電腦位元組(Byte)是電腦中表示信息含義的最小單位。字元流只能夠處理純文本數據,其他類型數據不行,但是字元流處理文本要比位元組流處理文本要方便。
在讀寫文件需要對內容按行處理,比如比較特定字元,處理某一行數據的時候一般會選擇字元流。
只是讀寫文件,和文件內容無關時,一般選擇位元組流。
39,BIO、NIO、AIO的區別?
BIO:同步並阻塞,在伺服器中實現的模式為一個連接一個線程。也就是說,客戶端有連接請求的時候,伺服器就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然這也可以通過線程池機制改善。BIO一般適用於連接數目小且固定的架構,這種方式對於伺服器資源要求比較高,而且併發局限於應用中,是JDK1.4之前的唯一選擇,但好在程式直觀簡單,易理解。
NIO:同步並非阻塞,在伺服器中實現的模式為一個請求一個線程,也就是說,客戶端發送的連接請求都會註冊到多路復用器上,多路復用器輪詢到有連接IO請求時才會啟動一個線程進行處理。NIO一般適用於連接數目多且連接比較短(輕操作)的架構,併發局限於應用中,編程比較複雜,從JDK1.4開始支持。
AIO:非同步並非阻塞,在伺服器中實現的模式為一個有效請求一個線程,也就是說,客戶端的IO請求都是通過操作系統先完成之後,再通知伺服器應用去啟動線程進行處理。AIO一般適用於連接數目多且連接比較長(重操作)的架構,充分調用操作系統參與併發操作,編程比較複雜,從JDK1.7開始支持。