最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Java基礎--2021Java面試題系列教程--大白話解讀

2021-01-27 22:40 作者:JavaPub  | 我要投稿

前言

序言

再高大上的框架,也需要扎實的基礎才能玩轉(zhuǎn),高頻面試問題更是基礎中的高頻實戰(zhàn)要點。

適合閱讀人群

Java 學習者和愛好者,有一定工作經(jīng)驗的技術人,準面試官等。

閱讀建議

本教程是系列教程,包含 Java 基礎,JVM,容器,多線程,反射,異常,網(wǎng)絡,對象拷貝,JavaWeb,設計模式,Spring-Spring MVC,Spring Boot / Spring Cloud,Mybatis / Hibernate,Kafka,RocketMQ,Zookeeper,MySQL,Redis,Elasticsearch,Lucene

微信搜:JavaPub,閱讀全套系列面試題教程


  • 前言

    • 序言

    • 適合閱讀人群

    • 閱讀建議

  • 題目

    • 1.JDK 和 JRE 有什么區(qū)別?談談你對 JVM 的理解

    • 2.== 和 equals 的區(qū)別是什么?

    • 3.兩個對象的 hashCode()相同,則 equals()也一定為 true,對嗎?

    • 4.final 在 java 中有什么作用?

    • 5.java 中的 Math.round(-1.5) 等于多少?

    • 6.String 屬于基礎的數(shù)據(jù)類型嗎?

    • 7.java 中操作字符串都有哪些類?它們之間有什么區(qū)別?

    • 8.String str="i"與 String str=new String(“i”)一樣嗎?

    • 9.如何將字符串反轉(zhuǎn)?

    • 10.String 類的常用方法都有那些?

    • 11.抽象類必須要有抽象方法嗎?

    • 12.普通類和抽象類有哪些區(qū)別?

    • 13.抽象類能使用 final 修飾嗎?

    • 14.接口和抽象類有什么區(qū)別?

    • 15.java 中 IO 流分為幾種?

    • 16.BIO、NIO、AIO 有什么區(qū)別?

    • 17.Files的常用方法都有哪些?


題目

1.JDK 和 JRE 有什么區(qū)別?談談你對 JVM 的理解

JDK 和 JRE

JDK(Java Development Kit)是Java開發(fā)運行環(huán)境,是java開發(fā)工具包,JDK包含了JRE的所有東西,同時還包含了編譯java源碼的編譯器javac,還包含了很多java程序調(diào)試和分析的工具:jconsole,jvisualvm等工具軟件,還包含了java程序編寫所需的文檔和demo例子程序。

JRE(Java Runtime Environment)它是Java運行環(huán)境,如果你不需要開發(fā)只需要運行Java程序,那么你可以安裝JRE。(但是在運行JSP程序時,我們還是需要JDK,因為應用服務器會將 JSP 轉(zhuǎn)換為 Java servlet,并且需要使用 JDK 編譯 servlet。)

如果你需要運行java程序,只需安裝JRE就可以了。如果你需要編寫java程序,需要安裝JDK。

JVM

JVM(Java Virtual Machine) 就是我們常說的 java 虛擬機是 JRE 的一部分,它是整個 java 實現(xiàn)跨平臺的最核心的部分,所有的 java 程序會首先被編譯為 .class 的類文件,這種類文件可以在虛擬機上執(zhí)行。

JVM 主要工作是解釋自己的指令集(即字節(jié)碼)并映射到本地的 CPU 指令集和 OS 的系統(tǒng)調(diào)用。Java 語言是跨平臺運行的,不同的操作系統(tǒng)會有不同的 JVM 映射規(guī)則,使之與操作系統(tǒng)無關,完成跨平臺性。

JVM是Java Virtual Machine(Java虛擬機)的縮寫,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。由一套字節(jié)碼指令集、一組寄存器、一個棧、一個垃圾回收堆和一個存儲方法域等組成。JVM屏蔽了與操作系統(tǒng)平臺相關的信息,使得Java程序只需要生成在Java虛擬機上運行的目標代碼(字節(jié)碼),就可在多種平臺上不加修改的運行,這也是Java能夠“一次編譯,到處運行的”原因。

附一張關系圖:

jdk-jre-jvm關系圖

總結(jié):使用JDK(調(diào)用JAVA API)開發(fā)JAVA程序后,通過JDK中的編譯程序(javac)將Java程序編譯為Java字節(jié)碼,在JRE上運行這些字節(jié)碼,JVM會解析并映射到真實操作系統(tǒng)的CPU指令集和OS的系統(tǒng)調(diào)用。

2.== 和 equals 的區(qū)別是什么?

equals 和 == 都是來判斷兩個對象是否相等

  1. equals 是方法,而 == 是操作符;

  2. 對于基本類型的變量來說(如 short、 int、 long、 float、 double),只能使用 == ,因為這些基本類型的變量沒有 equals 方法。對于基本類型變量的比較,使用 == 比較, 一般比較的是它們的值。

  3. 對于引用類型的變量來說(例如 String 類)才有 equals 方法,因為 String 繼承了 Object 類, equals 是 Object 類的通用方法。對于該類型對象的比較,默認情況下,也就是沒有復寫 Object 類的 equals 方法,使用 == 和 equals 比較是一樣效果的,都是比較的是它們在內(nèi)存中的存放地址。但是對于某些類來說,為了滿足自身業(yè)務需求,可能存在 equals 方法被復寫的情況,這時使用 equals 方法比較需要看具體的情況,例如 String 類,使用 equals 方法會比較它們的值;

  • 對于 equals 方法沒有被重寫的情況。如果類沒有重寫該方法,那么默認使用的就是 Object 類的方法,以下是 Object 類的 equals 方法:

??public?boolean?equals(Object?obj)?{
??????return?(this?==?obj);
??}

從源碼可以看出,里面使用的就是 == 比較,所以這種情況下比較的就是它們在內(nèi)存中的存放地址。

  • 對于 equals 方法被重寫的情況。以 String 類為例,以下是 String 類中的 equals 方法:

??@Override?
??public?boolean?equals(Object?other)?{
??if?(other?==?this)?{
????return?true;
??}
??if?(other?instanceof?String)?{
??????String?s?=?(String)other;
??????int?count?=?this.count;
??????if?(s.count?!=?count)?{
??????????return?false;
??????}
??????if?(hashCode()?!=?s.hashCode())?{
??????????return?false;
??????}
??????char[]?value1?=?value;
??????int?offset1?=?offset;
??????char[]?value2?=?s.value;
??????int?offset2?=?s.offset;
??????for?(int?end?=?offset1?+?count;?offset1?<?end;?)?{
??????????if?(value1[offset1]?!=?value2[offset2])?{
??????????????return?false;
??????????}
??????????offset1++;
??????????offset2++;
??????}
??????return?true;
??}?else?{
??????return?false;
??}
}

從源碼可以看出, String 類復寫了 equals 方法,當使用 == 比較內(nèi)存的存放地址不相等時,接下來會比較字符串的內(nèi)容是否 相等,所以 String 類中的 equals 方法會比較兩者的字符串內(nèi)容是否一樣。

3.兩個對象的 hashCode()相同,則 equals()也一定為 true,對嗎?

答案是不一定的

java.lang.Object類中有兩個非常重要的方法:

public?boolean?equals(Object?obj)
public?int?hashCode()

Object 類是類繼承結(jié)構的基礎,所以是每一個類的父類。所有的對象,包括數(shù)組,都實現(xiàn)了在 Object 類中定義的方法。

以下是Object對象API關于equal方法和hashCode方法的說明:

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

簡而言之,在集合查找時,hashcode能大大降低對象比較次數(shù),提高查找效率!

Java對象的eqauls方法和hashCode方法是這樣規(guī)定的:

  1. 相等(相同)的對象必須具有相等的哈希碼(或者散列碼)。

  2. 如果兩個對象的hashCode相同,它們并不一定相同。

對以上倆點的說明

  1. 關于第一點,相等(相同)的對象必須具有相等的哈希碼(或者散列碼),為什么?

想象一下,假如兩個Java對象A和B,A和B相等(eqauls結(jié)果為true),但A和B的哈希碼不同,則A和B存入HashMap時的哈希碼計算得到的HashMap內(nèi)部數(shù)組位置索引可能不同,那么A和B很有可能允許同時存入HashMap,顯然相等/相同的元素是不允許同時存入HashMap,HashMap不允許存放重復元素。

  1. 關于第二點,兩個對象的hashCode相同,它們并不一定相同

也就是說,不同對象的hashCode可能相同;假如兩個Java對象A和B,A和B不相等(eqauls結(jié)果為false),但A和B的哈希碼相等,將A和B都存入HashMap時會發(fā)生哈希沖突,也就是A和B存放在HashMap內(nèi)部數(shù)組的位置索引相同這時HashMap會在該位置建立一個鏈接表,將A和B串起來放在該位置,顯然,該情況不違反HashMap的使用原則,是允許的。當然,哈希沖突越少越好,盡量采用好的哈希算法以避免哈希沖突。

總而言之(all in all):

換句話說,equals()方法不相等的兩個對象,hashcode()有可能相等(我的理解是由于哈希碼在生成的時候產(chǎn)生沖突造成的)。反過來,hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

4.final 在 java 中有什么作用?

這是一個很基礎,很能體現(xiàn)你基礎是否扎實、是否有鉆研精神的知識點。

final關鍵字的字面意思是最終的, 不可修改的. 這似乎是一個看見名字就大概能知道怎么用的語法。

這三點必須要答出來:

  1. 被final修飾的類不可以被繼承

  2. 被final修飾的方法不可以被重寫

  3. 被final修飾的變量不可以被改變

要注意final類中的所有成員方法都會被隱式地指定為final方法。

第三點尤為重要

當final修飾的是一個基本數(shù)據(jù)類型數(shù)據(jù)時, 這個數(shù)據(jù)的值在初始化后將不能被改變; 當final修飾的是一個引用類型數(shù)據(jù)時, 也就是修飾一個對象時, 引用在初始化后將永遠指向一個內(nèi)存地址, 不可修改. 但是該內(nèi)存地址中保存的對象信息, 是可以進行修改的.

JavaPub參考巨人(有一些簡單例子,便于更好的理解final):https://www.cnblogs.com/dolphin0520/p/3736238.html

5.java 中的 Math.round(-1.5) 等于多少?

返回值:-1

四舍五入的原理是在參數(shù)上加0.5然后做向下取整。

一些案例:

public?class?test?{
?public?static?void?main(String[]?args){
??System.out.println(Math.round(1.3));???//1
??System.out.println(Math.round(1.4));???//1
??System.out.println(Math.round(1.5));???//2
??System.out.println(Math.round(1.6));???//2
??System.out.println(Math.round(1.7));???//2
??System.out.println(Math.round(-1.3));??//-1
??System.out.println(Math.round(-1.4));??//-1
??System.out.println(Math.round(-1.5));??//-1
??System.out.println(Math.round(-1.6));??//-2
??System.out.println(Math.round(-1.7));??//-2
?}
}

6.String 屬于基礎的數(shù)據(jù)類型嗎?

當然,每一個Java學習者都知道它不是基礎類型,但是你要知道更多細節(jié)。

Java中的數(shù)據(jù)類型分為兩大類,基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。

基本數(shù)據(jù)類型只有8種,可按照如下分類

  1. 整數(shù)類型:long、int、short、byte

  2. 浮點類型:float、double

  3. 字符類型:char

  4. 布爾類型:boolean

java基礎類型

引用數(shù)據(jù)類型非常多,大致包括:

類、 接口類型、 數(shù)組類型、 枚舉類型、 注解類型、 字符串型。

簡單來說,所有的非基本數(shù)據(jù)類型都是引用數(shù)據(jù)類型。

基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的區(qū)別

  1. 存儲位置

  • 基本變量類型

在方法中定義的非全局基本數(shù)據(jù)類型變量的具體內(nèi)容是存儲在棧中的

  • 引用變量類型

只要是引用數(shù)據(jù)類型變量,其具體內(nèi)容都是存放在堆中的,而棧中存放的是其具體內(nèi)容所在內(nèi)存的地址(引用/句柄)

ps:通過變量地址可以找到變量的具體內(nèi)容,就如同通過房間號可以找到房間一般

數(shù)據(jù)類型存儲
  1. 傳遞方式

  • 基本變量類型

在方法中定義的非全局基本數(shù)據(jù)類型變量,調(diào)用方法時作為參數(shù)是按數(shù)值傳遞的


//基本數(shù)據(jù)類型作為方法參數(shù)被調(diào)用

public?class?Main{

???public?static?void?main(String[]?args){

???????int?msg?=?100;

???????System.out.println("調(diào)用方法前msg的值:\n"+?msg);????//100

???????fun(msg);

???????System.out.println("調(diào)用方法后msg的值:\n"+?msg);????//100

???}

???public?static?void?fun(int?temp){

???????temp?=?0;

???}

}

基本變量類型傳遞方式
  • 引用變量類型

引用數(shù)據(jù)類型變量,調(diào)用方法時作為參數(shù)是按引用傳遞的


//引用數(shù)據(jù)類型作為方法參數(shù)被調(diào)用



class?Book{

????String?name;

????double?price;



????public?Book(String?name,double?price){

????????this.name?=?name;

????????this.price?=?price;

????}

????public?void?getInfo(){

????????System.out.println("圖書名稱:"+?name?+?",價格:"?+?price);

????}



????public?void?setPrice(double?price){

????????this.price?=?price;

????}

}



public?class?Main{

???public?static?void?main(String[]?args){

???????Book?book?=?new?Book("Java開發(fā)指南",66.6);

???????book.getInfo();??//圖書名稱:Java開發(fā)指南,價格:66.6

???????fun(book);

???????book.getInfo();??//圖書名稱:Java開發(fā)指南,價格:99.9

???}



???public?static?void?fun(Book?temp){

???????temp.setPrice(99.9);

???}

}

調(diào)用時為temp在棧中開辟新空間,并指向book的具體內(nèi)容,方法執(zhí)行完畢后temp在棧中的內(nèi)存被釋放掉

引用類型傳遞方式

其他(有關JVM)

  • java 中String 是個對象,是引用類型 ,基礎類型與引用類型的區(qū)別是,基礎類型只表示簡單的字符或數(shù)字,引用類型可以是任何復雜的數(shù)據(jù)結(jié)構,基本類型僅表示簡單的數(shù)據(jù)類型,引用類型可以表示復雜的數(shù)據(jù)類型,還可以操作這種數(shù)據(jù)類型的行為 。

  • java虛擬機處理基礎類型與引用類型的方式是不一樣的,對于基本類型,java虛擬機會為其分配數(shù)據(jù)類型實際占用的內(nèi)存空間,而對于引用類型變量,他僅僅是一個指向堆區(qū)中某個實例的指針

  • 基本類型存儲在棧中,因此它們的存取速度要快于存儲在堆中的對應包裝類的實例對象,從Java5.0(1.5)開始,JAVA虛擬機(Java Virtual Machine)可以完成基本類型和它們對應包裝類之間的自動轉(zhuǎn)換。因此我們在賦值、參數(shù)傳遞以及數(shù)學運算的時候像使用基本類型一樣使用它們的包裝類,但這并不意味著你可以通過基本類型調(diào)用它們的包裝類才具有的方法。另外,所有基本類型(包括void)的包裝類都使用了final修飾,因此我們無法繼承它們擴展新的類,也無法重寫它們的任何方法。

  • 基本類型的優(yōu)勢:數(shù)據(jù)存儲相對簡單,運算效率比較高。

  • 包裝類的優(yōu)勢:自帶方法豐富,集合的元素必須是對象類型,體現(xiàn)了Java一切皆是對象的思想。

JavaPub參考巨人:https://blog.csdn.net/py1215/article/details/107524483

7.java 中操作字符串都有哪些類?它們之間有什么區(qū)別?

String、StringBuffer、StringBuilder

  • String : final修飾,String類的方法都是返回new String。即對String對象的任何改變都不影響到原對象,對字符串的修改操作都會生成新的對象。

  • StringBuffer : 對字符串的操作的方法都加了synchronized,保證線程安全。

  • StringBuilder : 不保證線程安全,在方法體內(nèi)需要進行字符串的修改操作,可以new StringBuilder對象,調(diào)用StringBuilder對象的append、replace、delete等方法修改字符串。

8.String str="i"與 String str=new String(“i”)一樣嗎?

答:不一樣。

因為內(nèi)存的分配方式不一樣。String str="i"的方式,Java 虛擬機會將其分配到常量池中;而 String str=new String(“i”)方式,則會被分到堆內(nèi)存中。

?String?str1?=?"i";
?String?str2?=?"i";
?String?str3?=?new?String("i");
?System.out.println(str1?==?str2);//ture
?System.out.println(str2?==?str3);//false

解釋:

  1. Java 虛擬機會將其分配到常量池中:常量池不會重復創(chuàng)建對象。

在String str1="i"中,把i值存在常量池,地址賦給str1。假設再寫一個String str2="i",則會把i的地址賦給str2,但是i對象不會重新創(chuàng)建,他們引用的是同一個地址值,共享同一個i內(nèi)存。(需要注意的是:String str="i"; 因為String 是final類型的,所以“i”應該是在常量池。)

  1. 分到堆內(nèi)存中:堆內(nèi)存會創(chuàng)建新的對象。

假設再寫一個String str3=new String(“i”),則會創(chuàng)建一個新的i對象,然后將新對象的地址值賦給str3。雖然str3和str1的值相同但是地址值不同。(而new String("i");則是新建對象放到堆內(nèi)存中。)

拓展知識

  • 堆內(nèi)存用來存放由new創(chuàng)建的對象和數(shù)組。在堆中分配的內(nèi)存,由Java虛擬機的自動垃圾回收器來管理。

  • 常量池指的是在編譯期被確定,并被保存在已編譯的.class文件中的一些數(shù)據(jù)。

  • == :引用數(shù)據(jù)類型比較地址值;

  • equals:引用類型,重寫前比較兩個對象地址值,重寫后比較屬性值。

9.如何將字符串反轉(zhuǎn)?

倆種辦法:

  1. 使用 StringBuilder 或 StringBuffer 的 reverse 方法,本質(zhì)都調(diào)用了它們的父類 AbstractStringBuilder 的 reverse 方法實現(xiàn)。(JDK1.8)

  2. 不考慮字符串中的字符是否是 Unicode 編碼,自己實現(xiàn)。

public?static?void?main(String[]?args)?{
????String?str?=?"ABCDE";
????System.out.println(reverseStringByStringBuilderApi(str));
????System.out.println(reverseString(str));
}

/**
?*?和StringBuffer()一樣,都用了Java自實現(xiàn)的方法,使用位移來實現(xiàn)
?*?@param
?*?@return
?*/

public?static?String?reverseStringByStringBuilderApi(String?str)?{
????if?(str?!=?null?&&?str.length()?>?0)?{
????????return?new?StringBuilder(str).reverse().toString();
????}
????return?str;
}

public?static?String?reverseString(String?str)?{
????if?(str?!=?null?&&?str.length()?>?0)?{
????????int?len?=?str.length();
????????char[]?chars?=?new?char[len];
????????for?(int?i?=?len?-?1;?i?>=?0;?i--)?{
????????????chars[len?-?1?-?i]?=?str.charAt(i);
????????}
????????return?new?String(chars);
????}
????return?str;
}

更多交換方式參考:https://blog.csdn.net/py1215/article/details/107549222

10.String 類的常用方法都有那些?

下面列舉了20個常用方法。格式:返回類型 方法名 作用。

  1. 和長度有關:

  • int length() 得到一個字符串的字符個數(shù)

  1. 和數(shù)組有關:

  • byte[] getByte() ) 將一個字符串轉(zhuǎn)換成字節(jié)數(shù)組

  • char[] toCharArray() 將一個字符串轉(zhuǎn)換成字符數(shù)組

  • String split(String) 將一個字符串按照指定內(nèi)容劈開

  1. 和判斷有關:

  • boolean equals() 判斷兩個字符串的內(nèi)容是否一樣

  • boolean equalsIsIgnoreCase(String) 忽略太小寫的比較兩個字符串的內(nèi)容是否一樣

  • boolean contains(String) 判斷一個字符串里面是否包含指定的內(nèi)容

  • boolean startsWith(String) 判斷一個字符串是否以指定的內(nèi)容開頭

  • boolean endsWith(String) 判斷一個字符串是否以指定的內(nèi)容結(jié)尾

  1. 和改變內(nèi)容有關:

  • String toUpperCase() 將一個字符串全部轉(zhuǎn)換成大寫

  • String toLowerCase() 將一個字符串全部轉(zhuǎn)換成小寫

  • String replace(String,String) 將某個內(nèi)容全部替換成指定內(nèi)容

  • String replaceAll(String,String) 將某個內(nèi)容全部替換成指定內(nèi)容,支持正則

  • String repalceFirst(String,String) 將第一次出現(xiàn)的某個內(nèi)容替換成指定的內(nèi)容

  • String substring(int) 從指定下標開始一直截取到字符串的最后

  • String substring(int,int) 從下標x截取到下標y-1對應的元素

  • String trim() 去除一個字符串的前后空格

  1. 和位置有關:

  • char charAt(int) 得到指定下標位置對應的字符

  • int indexOf(String) 得到指定內(nèi)容第一次出現(xiàn)的下標

  • int lastIndexOf(String) 得到指定內(nèi)容最后一次出現(xiàn)的下標

11.抽象類必須要有抽象方法嗎?

答案是:不必須

這道題考察的是抽象類的知識:

  1. 抽象類必須有關鍵字 abstract 來修飾。

  2. 抽象類可以不含有抽象方法

  3. 如果一個類包含抽象方法,則該類必須是抽象類

抽象類的特性和使用:

  • 抽象類不能被實例化。因為抽象類中方法未具體化,這是一種不完整的類,所以直接實例化也就沒有意義了。

  • 抽象類的使用必須有子類,使用extends繼承,一個子類只能繼承一個抽象類。

  • 子類(如果不是抽象類)則必須覆寫抽象類之中的全部抽象方法(如果子類沒有實現(xiàn)父類的抽象方法,則必須將子類也定義為為abstract類。)。

  • 抽象類可以不包含抽象方法,但如果類中包含抽象方法,就必須將該類聲明為抽象類。

抽象類的基本使用示例:

//定義一個抽象類
abstract?class?A{

????//普通方法
????public?void?fun(){
????????System.out.println("存在方法體的方法");
????}

????//抽象方法,沒有方法體,有abstract關鍵字做修飾
????public?abstract?void?print();
}

//單繼承
//B類是抽象類的子類,是一個普通類
class?B?extends?A{

????//強制要求覆寫
????@Override
????public?void?print()?{
????????System.out.println("Hello?World?!");
????}

}
public?class?TestDemo?{

????public?static?void?main(String[]?args)?{
????????//向上轉(zhuǎn)型
????????A?a?=?new?B();

????????//被子類所覆寫的過的方法
????????a.print();
????}
}

JavaPub參考巨人:https://www.jianshu.com/p/0530e14192b4

12.普通類和抽象類有哪些區(qū)別?

包含抽象方法的類稱為抽象類,但并不意味著抽象類中只能有抽象方法,它和普通類一樣,同樣可以擁有成員變量和普通的成員方法。注意,抽象類和普通類的主要有三點區(qū)別:

  1. 抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現(xiàn)該方法),缺省情況下默認為public。

  2. 抽象類不能用來創(chuàng)建對象;

  3. 如果一個類繼承于一個抽象類,則子類必須實現(xiàn)父類的抽象方法。如果子類沒有實現(xiàn)父類的抽象方法,則必須將子類也定義為為abstract類。

13.抽象類能使用 final 修飾嗎?

不能,抽象類是被用于繼承的,final修飾代表不可修改、不可繼承的。

這個在前面幾題有過介紹。

14.接口和抽象類有什么區(qū)別?

語法層面上的區(qū)別,也是我們?nèi)粘9俜降囊恍┱f法:

  1. 抽象類可以提供成員方法的實現(xiàn)細節(jié),而接口中只能存在public abstract 方法;

  2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的;

  3. 接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法,而抽象類可以有靜態(tài)代碼塊和靜態(tài)方法;

  4. 一個類只能繼承一個抽象類,而一個類卻可以實現(xiàn)多個接口。

接口的設計目的,是對類的行為進行約束。而抽象類的設計目的,是代碼復用??偨Y(jié)來說,繼承是一個 "是不是"的關系,而 接口 實現(xiàn)則是 "有沒有"的關系。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實現(xiàn)則是有沒有、具備不具備的關系。

抽象和繼承是 Java 中非常重要的東西,深入理解可以讓我們對 Java 技術理解更深刻,參考的這篇知乎博文非常好。

JavaPub參考巨人:https://www.zhihu.com/question/20149818

15.java 中 IO 流分為幾種?

Java中的流分為兩種,一種是字節(jié)流,另一種是字符流,分別由四個抽象類來表示(每種流包括輸入和輸出兩種所以一共四個):InputStream,OutputStream,Reader,Writer。Java中其他多種多樣變化的流均是由它們派生出來的.

字符流和字節(jié)流是根據(jù)處理數(shù)據(jù)的不同來區(qū)分的。字節(jié)流按照8位傳輸,字節(jié)流是最基本的,所有文件的儲存是都是字節(jié)(byte)的儲存,在磁盤上保留的并不是文件的字符而是先把字符編碼成字節(jié),再儲存這些字節(jié)到磁盤。

  1. 字節(jié)流可用于任何類型的對象,包括二進制對象,而字符流只能處理字符或者字符串;

  2. 節(jié)流提供了處理任何類型的IO操作的功能,但它不能直接處理Unicode字符,而字符流就可以。

讀文本的時候用字符流,例如txt文件。讀非文本文件的時候用字節(jié)流,例如mp3。理論上任何文件都能夠用字節(jié)流讀取,但當讀取的是文本數(shù)據(jù)時,為了能還原成文本你必須再經(jīng)過一個轉(zhuǎn)換的工序,相對來說字符流就省了這個麻煩,可以有方法直接讀取。

字符流處理的單元為2個字節(jié)的Unicode字符,分別操作字符、字符數(shù)組或字符串,而字節(jié)流處理單元為1個字節(jié), 操作字節(jié)和字節(jié)數(shù)組。所以字符流是由Java虛擬機將字節(jié)轉(zhuǎn)化為2個字節(jié)的Unicode字符為單位的字符而成的,所以它對多國語言支持性比較好!

  • 按操作方式分類結(jié)構圖:

按操作方式分類結(jié)構圖
  • 按操作對象分類結(jié)構圖:

按操作對象分類結(jié)構圖

代碼Demo參考:https://www.yisu.com/zixun/128625.html

16.BIO、NIO、AIO 有什么區(qū)別?

BIO

BIO全稱是Blocking IO,是JDK1.4之前的傳統(tǒng)IO模型,本身是同步阻塞模式。 線程發(fā)起IO請求后,一直阻塞IO,直到緩沖區(qū)數(shù)據(jù)就緒后,再進入下一步操作。針對網(wǎng)絡通信都是一請求一應答的方式,雖然簡化了上層的應用開發(fā),但在性能和可靠性方面存在著巨大瓶頸,試想一下如果每個請求都需要新建一個線程來專門處理,那么在高并發(fā)的場景下,機器資源很快就會被耗盡。

NIO

NIO也叫Non-Blocking IO 是同步非阻塞的IO模型。線程發(fā)起io請求后,立即返回(非阻塞io)。同步指的是必須等待IO緩沖區(qū)內(nèi)的數(shù)據(jù)就緒,而非阻塞指的是,用戶線程不原地等待IO緩沖區(qū),可以先做一些其他操作,但是要定時輪詢檢查IO緩沖區(qū)數(shù)據(jù)是否就緒。Java中的NIO 是new IO的意思。其實是NIO加上IO多路復用技術。普通的NIO是線程輪詢查看一個IO緩沖區(qū)是否就緒,而Java中的new IO指的是線程輪詢地去查看一堆IO緩沖區(qū)中哪些就緒,這是一種IO多路復用的思想。IO多路復用模型中,將檢查IO數(shù)據(jù)是否就緒的任務,交給系統(tǒng)級別的select或epoll模型,由系統(tǒng)進行監(jiān)控,減輕用戶線程負擔。 NIO主要有buffer、channel、selector三種技術的整合,通過零拷貝的buffer取得數(shù)據(jù),每一個客戶端通過channel在selector(多路復用器)上進行注冊。服務端不斷輪詢channel來獲取客戶端的信息。channel上有connect,accept(阻塞)、read(可讀)、write(可寫)四種狀態(tài)標識。根據(jù)標識來進行后續(xù)操作。所以一個服務端可接收無限多的channel。不需要新開一個線程。大大提升了性能。

AIO

AIO是真正意義上的異步非阻塞IO模型。 上述NIO實現(xiàn)中,需要用戶線程定時輪詢,去檢查IO緩沖區(qū)數(shù)據(jù)是否就緒,占用應用程序線程資源,其實輪詢相當于還是阻塞的,并非真正解放當前線程,因為它還是需要去查詢哪些IO就緒。而真正的理想的異步非阻塞IO應該讓內(nèi)核系統(tǒng)完成,用戶線程只需要告訴內(nèi)核,當緩沖區(qū)就緒后,通知我或者執(zhí)行我交給你的回調(diào)函數(shù)。 AIO可以做到真正的異步的操作,但實現(xiàn)起來比較復雜,支持純異步IO的操作系統(tǒng)非常少,目前也就windows是IOCP技術實現(xiàn)了,而在Linux上,底層還是是使用的epoll實現(xiàn)的。

資料

BIO (Blocking I/O): 同步阻塞I/O模式,數(shù)據(jù)的讀取寫入必須阻塞在一個線程內(nèi)等待其完成。在活動連接數(shù)不是特別高(小于單機1000)的情況下,這種模型是比較不錯的,可以讓每一個連接專注于自己的 I/O 并且編程模型簡單,也不用過多考慮系統(tǒng)的過載、限流等問題。線程池本身就是一個天然的漏斗,可以緩沖一些系統(tǒng)處理不了的連接或請求。但是,當面對十萬甚至百萬級連接的時候,傳統(tǒng)的 BIO 模型是無能為力的。因此,我們需要一種更高效的 I/O 處理模型來應對更高的并發(fā)量。

NIO (New I/O): NIO是一種同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,對應 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解為Non-blocking,不單純是New。它支持面向緩沖的,基于通道的I/O操作方法。 NIO提供了與傳統(tǒng)BIO模型中的 Socket 和 ServerSocket 相對應的 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實現(xiàn),兩種通道都支持阻塞和非阻塞兩種模式。阻塞模式使用就像傳統(tǒng)中的支持一樣,比較簡單,但是性能和可靠性都不好;非阻塞模式正好與之相反。對于低負載、低并發(fā)的應用程序,可以使用同步阻塞I/O來提升開發(fā)速率和更好的維護性;對于高負載、高并發(fā)的(網(wǎng)絡)應用,應使用 NIO 的非阻塞模式來開發(fā)

AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改進版 NIO 2,它是異步非阻塞的IO模型。異步 IO 是基于事件回調(diào)機制實現(xiàn)的,也就是應用操作之后會直接返回,不會堵塞在那里,當后臺處理完成,操作系統(tǒng)會通知相應的線程進行后續(xù)的操作。AIO 是異步IO的縮寫,雖然 NIO 在網(wǎng)絡操作中,提供了非阻塞的方法,但是 NIO 的 IO 行為還是同步的。對于 NIO 來說,我們的業(yè)務線程是在 IO 操作準備好時,得到通知,接著就由這個線程自行進行 IO 操作,IO操作本身是同步的。查閱網(wǎng)上相關資料,我發(fā)現(xiàn)就目前來說 AIO 的應用還不是很廣泛,Netty 之前也嘗試使用過 AIO,不過又放棄了。

17.Files的常用方法都有哪些?

Files.exists():檢測文件路徑是否存在。

Files.createFile():創(chuàng)建文件。

Files.createDirectory():創(chuàng)建文件夾。

Files.delete():刪除一個文件或目錄。

Files.copy():復制文件。

Files.move():移動文件。

Files.size():查看文件個數(shù)。

Files.read():讀取文件。

Files.write():寫入文件。

微信關注:JavaPub ,帶走全套寶典

目錄圖片


Java基礎--2021Java面試題系列教程--大白話解讀的評論 (共 條)

分享到微博請遵守國家法律
苍南县| 麦盖提县| 莫力| 石河子市| 宜兴市| 泰兴市| 天门市| 应城市| 繁昌县| 宁夏| 岳阳县| 阳山县| 辽阳市| 北京市| 盐山县| 威远县| 丹巴县| 叙永县| 罗平县| 大足县| 庐江县| 蓬溪县| 台北市| 西安市| 田东县| 金溪县| 岑溪市| 渭南市| 惠来县| 凤山县| 正阳县| 沙坪坝区| 启东市| 绍兴市| 南宁市| 临邑县| 中方县| 日喀则市| 呼玛县| 电白县| 大余县|