Java基础面试典籍60+ | 大别山码将
java基礎
面向對象和面向過程的區別
面向過程:比面向對象性能高;面向過程以步驟劃分問題,就是分析出解決問題所需要的步驟,然后用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了(蛋炒飯)
面向對象:比面向過程易維護,易復用,易拓展;面向對象以功能劃分問題,是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為。(蓋澆飯)
面向過程
優點:性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、
Linux/Unix等一般采用面向過程開發,性能是最重要的因素。 缺點:沒有面向對象易維護、易復用、易擴展
面向對象
優點:易維護、易復用、易擴展,由于面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統 更加靈活、更加易于維護
缺點:性能比面向過程低
java語言有哪些特點
-
簡單易學;
-
?向對象(封裝,繼承,多態);
-
平臺?關性( Java 虛擬機實現平臺?關性);
-
可靠性;
-
安全性;
-
?持多線程( C++ 語?沒有內置的多線程機制,因此必須調?操作系統的多線程功能來進?多線程程序設計,? Java 語?卻提供了多線程?持);
-
?持?絡編程并且很?便( Java 語?誕?本身就是為簡化?絡編程設計的,因此 Java 語?不僅?持?絡編程?且很?便);
-
編譯與解釋并存;
java如何實現平臺無關
平臺無關性就是一種語言在計算機上的運行不受平臺的約束,一次編譯,到處執行。Java減少了開發和部署到多個平臺的成本和時間
- Java語言規范
- 通過規定Java語言中基本數據類型的取值范圍和行為
- Class文件
- 所有Java文件要編譯成統一的Class文件
- Java虛擬機
- 通過Java虛擬機將Class文件轉成對應平臺的二進制文件等
java文件-》class文件-》二進制文件
JVM: Java編譯器可生成與計算機體系結構無關的字節碼指令,.class 字節碼文件面向虛擬機,不面向任何具體操作系統。所以.class字節碼文件不僅可以輕易地在任何機器上解釋執行,還可以動態地轉換成本地機器代碼,轉換是由 JVM 實現的,JVM 是平臺相關的,屏蔽了不同操作系統的差異。
java的安全性體現在哪里?
1、Java 不提供指針來直接訪問內存,使用引用取代了指針,程序內存更加安全
2、擁有一套異常處理機制,使用關鍵字 throw、throws、try、catch、finally
3、強制類型轉換需要符合一定規則
4、字節碼傳輸使用了加密機制
5、運行環境提供保障機制:字節碼校驗器->類裝載器->運行時內存布局->文件訪問限制
6、不用程序員顯示控制內存釋放,JVM 有垃圾回收機制
JVM,JDK和JRE之間的區別
首先說明三者的關系是:
JDK(Java Develepment Kit)Java開發工具包
JRE(Java RunTime Environment)Java運行時環境
JVM(Java Virtual Machine)Java虛擬機
JDK = JRE + Java工具s + Java基礎類庫
JRE = JVM + JVM工作所需的類庫
JVM是運? Java 字節碼的虛擬機。JVM 有針對不同系統的特定實現(Windows,Linux,macOS),?的是使?相同的字節碼,它們都會給出相同的結果。字節碼和不同系統的 JVM 實現是 Java 語?“?次編譯,隨處可以運?”的關鍵所在。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KDE1ek6O-1632494423932)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831091740889.png)]
JRE是運行基于Java語言編寫的程序所不可缺少的運行環境。也是通過它,Java的開發者才得以將自己開發的程序發布到用戶手中,讓用戶使用。
如果你只是為了運??下 Java 程序的話,那么你只需要安裝 JRE 就可以了。如果你需要進??些 Java 編程??的?作,那么你就需要安裝 JDK 了。但是,這不是絕對的。有時,即使您不打算在計算機上進?任何 Java 開發,仍然需要安裝 JDK。例如,如果要使? JSP 部署 Web 應?程序,那么從技術上講,您只是在應?程序服務器中運? Java 程序。那你為什么需要 JDK 呢?因為應?程序服務器會將 JSP 轉換為 Java servlet,并且需要使? JDK 來編譯 servlet。
JDK是Java開發工具包,JDK是整個JAVA的核心,包括了Java運行環境JRE(Java Runtime Envirnment)、一堆Java工具(javac/java/jdb等)和Java基礎的類庫(即Java API 包括rt.jar)。它能夠創建和編譯程序。
Oracle JDK和OpenJDK對比
- OpenJDK 是?個參考模型并且是完全開源的,? Oracle JDK 是 OpenJDK 的?個實現,并不是完全開源的;
- Oracle JDK ? OpenJDK 更穩定。OpenJDK 和 Oracle JDK 的代碼?乎相同,但 OracleJDK 有更多的類和?些錯誤修復。因此,如果您想開發企業/商業軟件,我建議您選擇Oracle JDK,因為它經過了徹底的測試和穩定。某些情況下,有些?提到在使? OpenJDK可能會遇到了許多應?程序崩潰的問題,但是,只需切換到 Oracle JDK 就可以解決問題;
- 在響應性和 JVM 性能??,Oracle JDK 比 OpenJDK 相?性能更好;
- Oracle JDK 不會為即將發布的版本提供?期?持,?戶每次都必須通過更新到最新版本獲得?持來獲取最新版本;
- Oracle JDK 根據?進制代碼許可協議獲得許可,? OpenJDK 根據 GPL v2 許可獲得許可。
java和c++區別
- 都是?向對象的語?,都?持封裝、繼承和多態
- Java 不提供指針來直接訪問內存,程序內存更加安全
- Java 的類是單繼承的,C++ ?持多重繼承;雖然 Java 的類不可以多繼承,但是接?可以多繼承。
- Java 有?動內存管理機制,不需要程序員?動釋放??內存
- 在 C 語?中,字符串或字符數組最后都會有?個額外的字符‘\0’來表示結束。但是,Java 語?中沒有結束符這?概念。
字符型常量和字符串常量區別
-
形式上: 字符常量是單引號引起的?個字符; 字符串常量是雙引號引起的若?個字符
-
含義上: 字符常量相當于?個整型值( ASCII 值), 字符串常量代表?個地址值(該字符串在內存中存放位置)
-
字符常量只占 2 個字節; 字符串常量占若?個字節
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6AkzKylu-1632494423957)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831093557593.png)]
什么是反射?
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法,對于任意一個對象,都能夠調用它的任意一個方法和屬性,這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。在 java 中,只要給定類的名字, 那么就可以通過反射機制來獲得類的所有信息。
- Java 的動態就體現在這。通過反射我們可以實現動態裝配,降低代碼的耦合度;動態代理等。反射的過度使用會嚴重消耗系統資源。
**JDK 中 java.lang.Class 類,就是為了實現反射提供的核心類之一。**反射使用的不當,對性能影響比較大,一般項目中直接使用較少。
反射主要用于底層的框架中,Spring 中就大量使用了反射,比如:
- 用 IoC 來注入和組裝 bean
- 動態代理、面向切面、bean 對象中的方法替換與增強,也使用了反射
- 定義的注解,也是通過反射查找
還用于:在編譯時無法知道該對象或類可能屬于哪些類,用作程序在運行時獲取對象和類的信息
優點:提高了 Java 程序的靈活性和擴展性,降低耦合性,提高自適應能力。
缺點
使用反射的性能較低。 java 反射是要解析字節碼,將內存中的對象進行解析。
-
性能問題:反射是一種解釋操作,遠慢于直接代碼。因此反射機制主要用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用
-
模糊程序內部邏輯:反射繞過了源代碼,無法再源代碼中看到程序的邏輯,會帶來維護問題
-
增大了復雜性:反射代碼比同等功能的直接代碼更復雜
解決方案:
???? 1.由于 JDK 的安全檢查耗時較多,所以通過 setAccessible(true)的方式關閉安全檢查 來(取消對訪問控制修飾符的檢查)提升反射速度。
???? 2.需要多次動態創建一個類的實例的時候,有緩存的寫法會比沒有緩存要快很多:
???? 3.ReflectASM 工具類 ,通過字節碼生成的方式加快反射速度。
(2)使用反射相對來說不安全,破壞了類的封裝性,可以通過反射獲取這個 類的私有方法和屬性。
反射的實現方式:
在 Java 中實現反射最重要的一步, 也是第一步就是獲取 Class 對象, 得到Class 對象后可以通過該對象調用相應的方法來獲取該類中的屬性、方法以及調用該類中的方法。
???? 有 4 種方法可以得到 Class 對象:
???? 1.Class.forName(“類的路徑”);
???? 2.類名.class。
???? 3.對象名.getClass()。
???? 4.如果是基本類型的包裝類,則可以通過調用包裝類的 Type 屬性來獲得該包裝類的 Class 對象。
???? 例如: Class<?> clazz = Integer.TYPE;
Class類的作用是什么?如何獲取Class對象?
Class 類是 Java 反射機制的起源和入口,用于獲取與類相關的各種信息,提供了獲取類信息的相關方法。
什么是泛型?為什么要使用泛型?
參數化類型,將類型由具體的類型參數化,具有在多種數據類型上皆可操作的含意,與模板有些相似。
為什么要用泛型?
- 使用泛型編寫的程序代碼,要比使用 Object 變量再進行強制類型轉換的代碼,具有更好的安全性和可讀性。
- 多種數據類型執行相同的代碼使用泛型可以復用代碼。
比如集合類使用泛型,取出和操作元素時無需進行類型轉換,避免出現 java.lang.ClassCastException 異常
String s = new String(“xyz”);創建幾個String對象?
兩個或一個
- 第一次調用 new String(“xyz”); 時,會在堆內存中創建一個字符串對象,同時在字符串常量池中創建一個對象 “xyz”
- 第二次調用 new String(“xyz”); 時,只會在堆內存中創建一個字符串對象,指向之前在字符串常量池中創建的 “xyz”
構造器Constructor是否可被override(重寫)?
Constructor 不能被 override(重寫),但是可以 overload(重載),所以你可以看到?個類中有多個構造函數的情況。
重載和重寫的區別
重載就是同一個類中多個同名方法根據不同的傳參來執行不同的邏輯處理,是一個類中多態性的一種表現。有不同的參數列表(靜態多態性)。多個用戶使用一個非開源項目,每個用戶使用它做不同的事情
重寫就是子類對父類方法的重新改造,外部樣子不能改變,內部邏輯可以改變, 是父類與子類之間多態性的一種表現。相同參數,不同實現(動態多態性)。多個用戶使用一個開源項目,每個用戶都可以對其進行修改
?法的重寫要遵循“兩同兩???”:
- “兩同”即?法名相同、形參列表相同;
- “兩?”指的是?類?法返回值類型應??類?法返回值類型更?或相等,?類?法聲明拋出的異常類應??類?法聲明拋出的異常類更?或相等;
- “??”指的是?類?法的訪問權限應??類?法的訪問權限更?或相等
構造方法可以重載,不可重寫
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-a0UJpWuG-1632494423962)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210831093854285.png)]
靜態成員變量和非靜態成員變量
-
別名不同:非靜態成員變量也稱為實例變量;靜態變量稱為類變量
-
生命周期不同:非靜態成員變量隨著對象的創建而存在;靜態成員變量隨著類的加載而存在
-
調用方式不同:非靜態成員變量用 對象名.變量名 調用;靜態成員變量用 類名.變量名,JDK1.7 以后也能用對象名.變量名調用
-
數據存儲位置不同:成員變量數據存儲在堆內存的對象中,對象的特有數據;JDK1.6 靜態變量數據存儲在方法區(共享數據區)的靜態區,對象的共享數據,JDK1.7 靜態變量移到堆中存儲
Java面向對象編程三大特性:封裝,繼承,多態
封裝:是把?個對象的屬性私有化,同時提供?些可以被外界訪問的屬性的?法,如果屬性不想被外界訪問,我們?可不必提供?法給外界訪問。
繼承:是使?已存在的類的定義作為基礎建?新類的技術,新類的定義可以增加新的數據或新的功能,也可以??類的功能,但不能選擇性地繼承?類。通過使?繼承我們能夠?常?便地復?以前的代碼。
關于繼承如下 3 點請記住:
- ?類擁有?類對象所有的屬性和?法(包括私有屬性和私有?法),但是?類中的私有屬性和?法?類是?法訪問,只是擁有。
- ?類可以擁有??屬性和?法,即?類可以對?類進?擴展。
- ?類可以???的?式實現?類的?法。
多態:多態是同一個行為具有多個不同表現形式或形態的能力。多態就是同一個接口,使用不同的實例而執行不同操作。(比如打印機都會打印這個行為,而使用黑白打印機打印會打印出黑白的圖文,使用彩色打印機打印則會打印出彩色的圖文。)(再比如地震來臨前都會引發動物叫,如果是狗就會吠叫,如果是雞就會啼叫)。在 Java 中有兩種形式可以實現多態:繼承(多個?類對同??法的重寫)和接?(實現接?并覆蓋接?中同??法)。
String,StringBuffer和StringBuilder三者區別
String 是 Java 語言非?;A和重要的類,提供了構造和管理字符串的各種基本邏輯。String 中的對象是不可變的,也就可以理解為常量,保證了線程安全。
StringBuffer 對?法加了同步鎖,所以是線程安全的。性能低
StringBuilder 并沒有對?法進?加同步鎖,所以是**?線程安全的。**性能高,有效減小了開銷
對于三者使?的總結:
-
操作少量的數據: 適? String
-
單線程操作字符串緩沖區下操作?量數據: 適? StringBuilder
-
多線程操作字符串緩沖區下操作?量數據: 適? StringBuffer
StringBuffer、StringBuilder和String一樣,也用來代表字符串。String類是不可變類,任何對String的改變都會引發新的String對象的生成。不同的是StringBuffer 每次都會對 StringBuffer 對象本身進?操作,而StringBuffer?成新的對象并改變對象引?。相同情況下使? StringBuilder 相?使? StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的?險。
String、StringBuffer和StringBuilder類都是CharSequence接口的子類
String類通過apend()方法轉換成StringBuilder和StringBuffer類。
StringBuffer類和StringBuilder類通過to.String()方法轉換成String類型
String 為什么是不可變的?
簡單的來說:String 類中使? final 關鍵字修飾字符數組來保存字符串, private final char value[] ,所以 String 對象是不可變的。(在 Java 9 之后,String 類的實現改? byte 數組存儲字符串private final byte[] value)
為什么String類被設計用final修飾?
- String 類是最常用的類之一,為了效率,禁止被繼承和重寫
- 為了安全。String 類中有很多調用底層的本地方法,調用了操作系統的 API,如果方法可以重寫,可能被植入惡意代碼,破壞程序。Java 的安全性也體現在這里。
為了實現修改字符序列的目的,StringBuffer 和 StringBuilder 底層都是利用可修改的(char,JDK 9 以后是 byte)數組,二者都繼承了 AbstractStringBuilder,里面包含了基本操作,區別僅在于最終的方法是否加了 synchronized, StringBuffer 它的線程安全是通過把各種修改數據的方法都加上 synchronized 關鍵字實現。另外,這個**內部數組應該創建成多大的呢?**如果太小,拼接的時候可能要重新創建足夠大的數組;如果太大,又會浪費空間。目前的實現是,構建時初始字符串長度加 16
自動拆箱與裝箱
裝箱:將基本類型?它們對應的引?類型包裝起來;
拆箱:將包裝類型轉換為基本數據類型;
裝箱過程是通過調用包裝器的valueOf方法(-128,128]實現的,而拆箱過程是通過調用包裝器的 xxxValue方法實現的(xxx代表對應的基本數據類型)。
裝箱的過程會創建對應的對象,這個會消耗內存,所以裝箱的過程會增加內存的消耗,影響性能
int和Integer區別,談談Integer值緩存范圍
int 是我們常說的整形數字,是 Java 的 8 個原始數據類型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。
Integer 是 int 對應的包裝類,它有一個 int 類型的字段存儲數據,并且提供了基本操作,比如數學運算、int 和字符串之間轉換等。構建 Integer 對象的傳統方式是直接調用構造器,直接 new 一個對象。這個值默認緩存是**-128 到 127 之間**
- 基本數據類型方便、簡單、高效,但泛型不支持、集合元素不支持
- 不符合面向對象思維
- **包裝類提供很多方法,方便使用,**如 Integer 類 toHexString(int i)、parseInt(String s) 方法等等
我們知道 Java 的對象都是引用類型,如果是一個原始數據類型數組,它在內存里是一段連續的內存,而對象數組則不然,數據存儲的是引用,對象往往是分散地存儲在堆的不同位置。這種設計雖然帶來了極大靈活性,但是也導致了數據操作的低效,尤其是無法充分利用現代 CPU 緩存機制。Java 為對象內建了各種多態、線程安全等方面的支持。但有些始數據類型操作不能保證線程安全如float,double
,繼續深挖緩存,Integer 的緩存范圍雖然默認是 -128 到 127,但是在特別的應用場景,比如我們明確知道應用會頻繁使用更大的數值,這時候應該怎么辦呢?緩存上限值實際是可以根據需要調整的,JVM 提供了參數設置-XX:AutoBoxCacheMax=N
什么是包裝類?為什么要有包裝類?
在一個靜態方法內調用一個非靜態成員為什么是非法的?
類的靜態成員(變量或方法)屬于類本身,在類加載的時候就會分配內存,可以通過類名直接訪問
非靜態成員屬于類的對象,只有在類的對象產生(實例化)時才會分配內存,然后通過類的對象(實例)去訪問
由于靜態?法可以不通過對象進?調?,所以,如果一個類的靜態方法去調用非靜態成員的時候,類的非靜態成員可能不存在,訪問一個內存中不存在的東西當然會出錯因此在靜態?法?,不能調?其他?靜態變量,也不可以訪問?靜態變量成員。
在Java中定義一個不做事且沒有參數的構造方法的作用
Java 程序在執??類的構造?法之前,需要調用父類的構造方法(如果沒有? super() 來調??類特定的構造?法,則會調??類中“沒有參數的構造?法”)。
因此,如果?類中只定義了有參數的構造?法,?在?類的構造?法中?沒有? super() 來調??類中特定的構造?法,因為 Java 程序在?類中找不到沒有參數的構造?法可供執?,則編譯時發?錯誤。解決辦法是在?類?加上?個不做事且沒有參數的構造?法以防萬一。
接口和抽象類的區別
接口:
Java中接口使用interface關鍵字修飾,接?的?法默認是 public ,所有?法在接?中不能有實現(Java 8 開始接??法可以有默認實現)
接口可以包含變量、方法;變量被隱士指定為public static final,方法被隱士指定為public abstract(JDK1.8之前);
接口支持多繼承,一個類可以實現多個接口
接口沒有構造函數
- 接口中的訪問權限修飾符只能是 public 或 default
- 接口中的方法必須要實現類實現,所以不能使用 final
- 接口中所有的方法默認都是 abstract,通常 abstract 省略不寫
抽象類:
抽象類使用abstract關鍵字修飾,被abstract關鍵字修飾的方法稱為抽象方法,抽象方法只有方法的聲明,沒有方法體
抽象類不能被實例化,允許被繼承但不允許多繼承(一個類只能繼承一個抽象類,但可以實現多個接口)
抽象類可以包含屬性、方法、構造方法,但是構造方法不能用于實例化,主要用途是被子類調用。
抽象類可以實現接口
除了不能被實例化外,它和普通Java類沒有任何區別
區別:
抽象類有構造方法,接口無構造方法,都不能被實例化,
抽象類可以有非抽象方法,而接口中的方法都是抽象方法
接口比抽象類速度要慢,因為它需要時間去尋找在類中實現的方法
實現接口的關鍵字為implements,繼承抽象類的關鍵字為extends。一個類可以實現多個接口,但一個類只能繼承一個抽象類
接口成員變量默認為public static final,必須賦初值,不能被修改;其所有的成員方法都是public、abstract的。抽象類中成員變量默認default,可在子類中被重新定義,也可被重新賦值;抽象方法被abstract修飾,不能被private、static、synchronized和native等修飾,必須以分號結尾,不帶花括號。
接口只能是功能的定義,而抽象類既可以為功能的定義也可以為功能的實現。
設計層面上的區別:
抽象類是對一種事物的抽象,即對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象。舉個簡單的例子,飛機和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那么在設計的時候,可以將飛機設計為一個類Airplane,將鳥設計為一個類Bird,但是不能將 飛行 這個特性也設計為類,因此它只是一個行為特性,并不是對一類事物的抽象描述。此時可以將 飛行 設計為一個接口Fly,包含方法fly( ),然后Airplane和Bird分別根據自己的需要實現Fly這個接口。然后至于有不同種類的飛機,比如戰斗機、民用飛機等直接繼承Airplane即可,對于鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這里可以看出,繼承是一個 "是不是"的關系,而 接口 實現則是 "有沒有"的關系。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實現則是有沒有、具備不具備的關系,比如鳥是否能飛(或者是否具備飛行這個特點),能飛行則可以實現這個接口,不能飛行就不實現這個接口。
子類初始化的順序
① 父類靜態代碼塊和靜態變量。
② 子類靜態代碼塊和靜態變量。
③ 父類普通代碼塊和普通變量。
④ 父類構造方法。
⑤ 子類普通代碼塊和普通變量。
⑥ 子類構造方法。
成員變量與局部變量的區別有哪些?
-
從語法形式上看:成員變量是在類中定義的,?局部變量是在?法中定義的或是?法的參數;成員變量可以被 public , private , static 等修飾符所修飾,?局部變量不能被訪問控制修飾符及 static 所修飾;但是,成員變量和局部變量都能被 final 所修飾。
-
從變量在內存中的存儲?式來看:成員變量是對象的一部分,對象存于堆內存;如果局部變量類型為基本數據類型,那么存儲在棧內存,如果為引?數據類型,那存放的是指向堆內存對象的引?或者是指向常量池中的地址。
-
從變量在內存中的?存時間上看:成員變量是對象的?部分,它隨著對象的創建?存在,?局部變量隨著?法的調???動消失。
-
成員變量如果沒有被賦初值:則會?動以類型的默認值?賦值(?種情況例外:被 final 修飾的成員變量也必須顯式地賦值),?局部變量則不會?動賦值。
創建一個對象用什么運算符?對象實例與對象引用有何不同?
new運算符
new 創建對象實例(對象實例在堆內存中),對象引?指向對象實例(對象引?存放在棧內存中)。?個對象引?可以指向 0 個或 1 個對象(?根繩?可以不系?球,也可以系?個?球);?個對象可以有 n 個引?指向它(可以? n 條繩?系住?個?球)
什么是方法的返回值?返回值在類的方法里有什么作用?
?法的返回值是指我們獲取到的某個?法體中的代碼執?后產?的結果!
返回值的作?:接收出結果,使得它可以?于其他的操作
?個類的構造?法的作?是什么? 若?個類沒有聲明構造?法,該程序能正確執?嗎? 為什么?
主要作?是完成對類對象的初始化?作。
可以執?,因為?個類即使沒有聲明構造?法也會有默認的不帶參數的構造?法
構造方法有哪些特性
- 名字與類名相同。
- 構造方法無返回值類型(void也不行)
- ?成類的對象時?動執?,?需調?
- 構造方法不能被繼承
- 構造方法可以沒有(默認一個無參構造方法),也可以有多個構造方法。他們之間構成重載關系
- 構造方法可以重載,不可重寫
作用:
(1)初始化對象,為對象賦初值。
(2)簡化我們為類字段賦值的代碼。
靜態方法和實例方法有何不同
-
在外部調?靜態?法時,可以使?"類名.?法名"的?式,也可以使?"對象名.?法名"的?式。?實例?法只有后?這種?式。也就是說,調?靜態?法可以?需創建對象。
-
靜態?法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變量和靜態?法),?不允許訪問實例成員變量和實例?法;實例?法則?此限制。
對象的相等和指向它們的應用相等,兩者有什么不同?
對象的相等,?的是內存中存放的內容是否相等。
?引?相等,?的是他們指向的內存地址是否相等
在調用子類構造方法之前會先調用父類沒有參數的構造方法,其目的是?
幫助?類做初始化?作
在初始化子類的時候,一定要使父類已經存在了(所以要先初始化父類對象,即要調用沒有參數的構造方法來初始化對象).不然沒辦法調用父類的構造函數.父類必須在子類初始化之前就已經準備好.
Object類有哪些方法?
equals:檢測對象是否相等,默認使用 == 比較對象引用,可以重寫 equals 方法自定義比較規則。equals 方法規范:自反性、對稱性、傳遞性、一致性、對于任何非空引用 x,x.equals(null) 返回 false。
hashCode:散列碼是由對象導出的一個整型值,沒有規律,每個對象都有默認散列碼,值由對象存儲地址得出。字符串散列碼由內容導出,值可能相同。為了在集合中正確使用,一般需要同時重寫 equals 和 hashCode,要求 equals 相同 hashCode 必須相同,hashCode 相同 equals 未必相同,因此 hashCode 是對象相等的必要不充分條件。
toString:打印對象時默認的方法,如果沒有重寫打印的是表示對象值的一個字符串。
clone:clone 方法聲明為 protected,類只能通過該方法克隆它自己的對象,如果希望其他類也能調用該方法必須定義該方法為 public。如果一個對象的類沒有實現 Cloneable 接口,該對象調用 clone 方拋出一個 CloneNotSupport 異常。默認的 clone 方法是淺拷貝,一般重寫 clone 方法需要實現 Cloneable 接口并指定訪問修飾符為 public。
finalize:確定一個對象死亡至少要經過兩次標記,如果對象在可達性分析后發現沒有與 GC Roots 連接的引用鏈會被第一次標記,隨后進行一次篩選,條件是對象是否有必要執行 finalize 方法。假如對象沒有重寫該方法或方法已被虛擬機調用,都視為沒有必要執行。如果有必要執行,對象會被放置在 F-Queue 隊列,由一條低調度優先級的 Finalizer 線程去執行。虛擬機會觸發該方法但不保證會結束,這是為了防止某個對象的 finalize 方法執行緩慢或發生死循環。只要對象在 finalize 方法中重新與引用鏈上的對象建立關聯就會在第二次標記時被移出回收集合。由于運行代價高昂且無法保證調用順序,在 JDK 9 被標記為過時方法,并不適合釋放資源。
getClass:返回包含對象信息的類對象。
wait / notify / notifyAll:阻塞或喚醒持有該對象鎖的線程。
==與equals區別(重要)
== : 它的作?是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同?個對象(基本數據類型?較的是值,引?數據類型?較的是內存地址)。
equals() : 它的作?也是判斷兩個對象是否相等。但它?般有兩種使?情況:
情況 1:類沒有覆蓋 equals() ?法。則通過 equals() ?較該類的兩個對象時,等價于通過“==”?較這兩個對象。
情況 2:類覆蓋了 equals() ?法。?般,我們都覆蓋 equals() ?法來?較兩個對象的內容是否相等;若它們的內容相等,則返回 true (即,認為這兩個對象相等)
說明:
String 中的 equals ?法是被重寫過的,因為 object 的 equals ?法是??的對象的內存地址,? String 的 equals ?法??的是對象的值。
當創建 String 類型的對象時,虛擬機會在常量池中查找有沒有已經存在的值和要創建的值相同的對象,如果有就把它賦給當前引?。如果沒有就在常量池中重新創建?個 String 對象。
hashCode與equals區別(重要)
hashCode()介紹:
hashCode() 的作?是獲取哈希碼,也稱為散列碼;它實際上是返回?個 int 整數。這個哈希碼的作?是確定該對象在哈希表中的索引位置。
hashCode() 定義在 JDK 的 Object 類中,這就意味著 Java 中的任何類都包含有 hashCode() 函數。另外需要注意的是: Object 的 hashcode ?法是本地?法,也就是? c 語?或 c++ 實現的,該?法通常?來將對象的 內存地址 轉換為整數之后返回。
散列表存儲的是鍵值對(key-value),它的特點是:能根據“鍵”快速的檢索出對應的“值”。這其中就利?到了散列碼!(可以快速找到所需要的對象)
為什么要有hashCode:
當你把對象加? HashSet 時, HashSet 會先計算對象的 hashcode 值來判斷對象加?的位置,同時也會與其他已經加?的對象的 hashcode 值作?較,如果沒有相符的 hashcode, HashSet會假設對象沒有重復出現。但是如果發現有相同 hashcode 值的對象,這時會調? equals() ?法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同, HashSet 就不會讓其加?操作成功。如果不同的話,就會重新散列到其他位置。這樣我們就??減少了 equals 的次數,相應就??提?了執?速度。
為什么重寫equals 時必須重寫 hashCode?法:
如果兩個對象相等,則 hashcode ?定也是相同的。兩個對象相等,對兩個對象分別調? equals?法都返回 true。但是,兩個對象有相同的 hashcode 值,這兩個對象不?定是相等的 。因此,equals?法被覆蓋過,則 hashCode ?法也必須被覆蓋。
為什么兩個對象有相同的hashcode值,它們也不?定是相等的:
因為 hashCode() 所使?的雜湊算法也許剛好會讓多個對象傳回相同的雜湊值。越糟糕的雜湊算法越容易碰撞,但這也與數據值域分布的特性有關(所謂碰撞也就是指的是不同的對象得到相同的 hashCode 。我們剛剛也提到了 HashSet ,如果 HashSet 在對?的時候,同樣的 hashcode 有多個對象,它會使? equals() 來判斷是否真的相同。也就是說 hashcode 只是?來縮?查找成本。
訪問權限控制符有哪些?
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dnV1eniR-1632494423973)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210909131559139.png)]
-
private:表示私有的,作用范圍是當前類(類可見性)。
-
default:表示沒有修飾符修飾,作用范圍是當前類+當前包(包可見型)。
-
protected:表示受保護的,作用范圍是當前類+當前包+包外的子類(子類可見性)。
-
public:表示公開的,作用范圍是是當前類+當前包+其它包(項目可見性)。
訪問權限控制符不能修飾局部變量
為什么Java中只有值傳遞?
Java程序設計語?總是采?按值調?。也就是說,?法得到的是所有參數值的?個拷?,也就是說,?法不能修改傳遞給它的任何參數變量的內容。
簡述線程,程序,進程的基本概念,以及他們之間關系是什么?
進程:
-
程序由指令和數據組成,但這些指令要運行,數據要讀寫,就必須將指令加載至CPU,數據加載至內存,在指令進行運行過程中還需要用到磁盤,網絡等設備。進程就是用來加載指令,管理內存,管理IO的
-
當一個程序被運行,從磁盤加載這個程序的代碼至內存,這時就開啟了一個進程
進程是程序的?次執?過程,是系統運?程序的基本單位,因此進程是動態的。系統運??個程序即是?個進程從創建,運?到消亡的過程。簡單來說,?個進程就是?個執?中的程序,它在計算機中?個指令接著?個指令地執?著,同時,每個進程還占有某些系統資源如 CPU 時間,內存空間,?件,輸?輸出設備的使?權等等。換句話說,當程序在執?時,將會被操作系統載?內存中。
線程:
- 一個進程可以分為一到多個線程
- 一個線程就是一個指令流,將指令流中的一條條指令以一定的順序交給CPU執行
- Java中,線程作為最小調度單位,進程作為資源分配的最小單位,在windows中進程是不活動的,只是作為線程的容器
二者對比:
- 進程基本上是相互獨立的,而線程存在于進程內,是進程的一個子集
- 進程擁有共享的資源,如內存空間等,供其內部的線程共享
- 與進程不同的是同類的多個線程共享同?塊內存空間和?組系統資源,所以系統在產??個線程,或是在各個線程之間作切換?作時,負擔要?進程?得多,也正因為如此,線程也被稱為輕量級進程
- 進程間通信較為復雜
? 同一臺計算機的進程通信稱為IPC
? 不同計算機之間的進程通信,需要通過網絡,并遵守共同的協議,例如HTTP
- 線程通信相對簡單,因為他們共享進程內的內存,一個例子是多個線程可以訪問同一個共享變量
- 線程更輕量,線程上下文切換成本一般要比進程上下文低
線程有哪些基本狀態
Java 線程在運?的?命周期中的指定時刻只可能處于下? 6 種狀態的其中?個狀態:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qleWUhTu-1632494423975)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901090110364.png)]
線程創建之后它將處于 NEW(新建) 狀態,調? start() ?法后開始運?,線程這時候處于READY(可運?)狀態??蛇\?狀態的線程獲得了 cpu 時間?(timeslice)后就處于RUNNING(運?) 狀態。
當線程執? wait() ?法之后,線程進? WAITING**(等待)狀態。進?等待狀態的線程需要依靠其他線程的通知才能夠返回到運?狀態,? TIME_WAITING(超時等待) 狀態相當于在等待狀態的基礎上增加了超時限制,?如通過 sleep(long millis) ?法或 wait(long millis) ?法可以將Java 線程置于 TIMED WAITING 狀態。當超時時間到達后 Java 線程將會返回到 RUNNABLE 狀態。
當線程調?同步?法時,在沒有獲取到鎖的情況下,線程將會進?BLOCKED(阻塞)狀態。線程在執? Runnable 的 run() ?法之后將會進?到 TERMINATED(終?) 狀態。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9XW2O2TL-1632494423978)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901090757562.png)]
final關鍵字
-
當? final 修飾?個類時,表明這個類不能被繼承。final 類中的所有成員?法都會被隱式地指定為 final ?法。
-
使? final ?法的原因有兩個。第?個原因是把?法鎖定,以防任何繼承類修改它的含義;第?個原因是效率。在早期的 Java 實現版本中,會將 final ?法轉為內嵌調?。但是如果?法過于龐?,可能看不到內嵌調?帶來的任何性能提升(現在的 Java 版本已經不需要使?final ?法進?這些優化了)。類中所有的 private ?法都隱式地指定為 final。
-
修飾變量是final用得最多的地方,對于一個final變量,如果是基本數據類型的變量,則其數值一旦在初始化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不能再讓其指向另一個對象。但是它指向的對象的內容是可變的。
.類的final變量和普通變量有什么區別?
當用final作用于類的成員變量時,成員變量必須在定義時或者構造器中進行初始化賦值,而且final變量一旦被初始化賦值之后,就不能再被賦值了。
我們可以將方法或者類聲明為 final,這樣就可以明確告知別人,這些行為是不許修改的。如果你關注過 Java 核心類庫的定義或源碼, 有沒有發現 java.lang 包下面的很多類,相當一部分都被聲明成為 final class?在第三方類庫的一些基礎類中同樣如此,這可以有效避免API 使用者更改基礎功能,某種程度上,這是保證平臺安全的必要手段。使用 final 修飾參數或者變量,也可以清楚地避免意外賦值導致的編程錯誤,甚至,有人明確推薦將所有方法參數、本地變量、成員變量聲明成 final。final 變量產生了某種程度的不可變(immutable)的效果,所以,可以用于保護只讀數據,尤其是在并發編程中,因為明確地不能再賦值 final 變量,有利于減少額外的同步開銷,也可以省去一些防御性拷貝的必要。final 也許會有性能的好處,很多文章或者書籍中都介紹了可在特定場景提高性能,比如,利用 final 可能有助于 JVM 將方法進行內聯,可以改善編譯器進行條件編譯的能力等等。坦白說,很多類似的結論都是基于假設得出的,比如現代高性能 JVM(如 HotSpot)判斷內聯未必依賴 final 的提示,要相信 JVM 還是非常智能的。類似的,final 字段對性能的影響,大部分情況下,并沒有考慮的必要。
public class Test {public static void main(String[] args) {String a = "hello2"; final String b = "hello";String d = "hello";String c = b + 2; String e = d + 2;System.out.println((a == c));//trueSystem.out.println((a == e));//false}
}
final與static的區別?
java中的異常處理
體檢java平臺設計者對不同異常的分類。
在 Java 中,所有的異常都有?個共同的祖先 java.lang 包中的 Throwable 類。 Throwable 類有兩個重要的?類 Exception (異常)和 Error (錯誤)。 Exception 能被程序本身處理( try_catch ), Error 是?法處理的(只能盡量避免)。
Exception 和 Error ?者都是 Java 異常處理的重要?類,各?都包含?量?類。
Exception:程序本身可以處理的異常,是程序運行過程中常見的可以預料的情況,可以通過 catch 來進?捕獲并進行相應的處理。 Exception ?可以分為 受檢查異常(必須處理) 和 不受檢查異常(可以不處理)。
- 受檢查異常:Java 代碼在編譯過程中,如果受檢查異常沒有被 catch / throw 處理的話,就沒辦法通過編譯,Exception 類及其?類都屬于檢查異常;常?的受檢查異常有: IO 相關的異常、 ClassNotFoundException 、 SQLException …
- 不受檢查異常(就是所謂的運行時異常):Java 代碼在編譯過程中 ,我們即使不處理不受檢查異常也可以正常通過編譯。RuntimeException 及其?類都統稱為?受檢查異常,例如: NullPointExecrption 、 NumberFormatException (字符串轉換為數字)、 ArrayIndexOutOfBoundsException (數組越界)、 ClassCastException (類型轉換錯誤)、 ArithmeticException (算術錯誤)等。
Error : **Error 屬于程序?法處理的錯誤 ,是正常情況下不太可能出現的情況。**我們沒辦法通過 catch 來進?捕獲 。例如,Java 虛擬機運?錯誤( Virtual MachineError )、虛擬機內存不夠錯誤( OutOfMemoryError )、類定義錯誤( NoClassDefFoundError )等 。這些異常發?時,Java虛擬機(JVM)?般會選擇線程終?。受檢查異常
- 捕獲異常后,不要生吞(swallow)異常。這是異常處理中要特別注意的事情,因為很可能會導致非常難以診斷的詭異情況。生吞異常,往往是基于假設這段代碼可能不會發生,或者感覺忽略異常是無所謂的,但是千萬不要在產品代碼做這種假設!如果我們不把異常拋出來,或者也沒有輸出到日志(Logger)之類,程序可能在后續代碼以不可控的方式結束。沒人能夠輕易判斷究竟是哪里拋出了異常,以及是什么原因產生了異常
- 有的時候,我們會根據需要自定義異常。一個重要考量就是信息安全。比如,用戶數據一般是不可以輸出到日志里面的
- 我們從性能角度來審視一下 Java 的異常處理機制,這里有兩個可能會相對昂貴的地方。try-catch 代碼段會產生額外的性能開銷,或者換個角度說,它往往會影響 JVM 對代碼進行優化,所以建議僅捕獲有必要的代碼段,盡量不要一個大的 try 包住整段的代碼。Java 每實例化一個 Exception,都會對當時的棧進行快照,這是一個相對比較重的操作。如果發生的非常頻繁,這個開銷可就不能被忽略了。當我們的服務出現反應變慢、吞吐量下降的時候,檢查發生最頻繁的 Exception 也是一種思路。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2TowOvjc-1632494423980)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901093446188.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DBkS73Qc-1632494423983)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901093500668.png)]
Throwable類常用方法:
public string getMessage() :返回異常發?時的簡要描述
public string toString() :返回異常發?時的詳細信息
public string getLocalizedMessage() :返回異常對象的本地化信息。使?Throwable 的?類覆蓋這個?法,可以?成本地化信息。如果?類沒有覆蓋該?法,則該?法返回的信息與getMessage() 返回的結果相同
public void printStackTrace() :在控制臺上打印 Throwable 對象封裝的異常信息
異常處理總結:
try塊: ?于捕獲異常。其后可接零個或多個 catch 塊,如果沒有 catch 塊,則必須跟?個 finally 塊。
catch 塊: ?于處理 try 捕獲到的異常。
finally 塊: ?論是否捕獲或處理異常, finally 塊?的語句都會被執?。當在 try 塊或
catch 塊中遇到 return 語句時, finally 語句塊將在?法返回之前被執?。當 try 語句和 finally 語句中都有 return 語句時,在?法返回之前,finally 語句的內容將被執?,并且 finally 語句的返回值將會覆蓋原始的返回值
在以下 3 種特殊情況下, finally 塊不會被執?:
-
在 try 或 finally 塊中?了 System.exit(int) 退出程序。但是,如果 System.exit(int) 在異常語句之后, finally 還是會被執?
-
程序所在的線程死亡。
-
關閉 CPU。
java序列化中如果有些字段不想進行序列化怎么辦?
java序列化:即寫文件,將對象轉化為字節序列方便存儲在文件中
java反序列化:即讀文件,將字節序列轉化為對象
對于不想進?序列化的變量,使? transient 關鍵字修飾。transient 關鍵字的作?是:阻?實例中那些?此關鍵字修飾的的變量序列化;當對象被反序列化時,被 transient 修飾的變量值不會被持久化和恢復。transient 只能修飾變量,不能修飾類和?法。
獲取用鍵盤輸入的兩種常用方法
通過Scanner:
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
通過BufferedReader:
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
java中的IO流
IO流:數據傳輸是需要通道的,而IO流就是數據傳輸的通道。IO流可以形象的比喻為運送貨物的傳輸帶。
java中的IO流分為幾種
- 按照流的流向分,可以分為輸?流和輸出流;
- 按照操作單元劃分,可以劃分為字節流和字符流;
- 按照流的??劃分為節點流和處理流。
InputStream/Reader: 所有的輸?流的基類,前者是字節輸?流,后者是字符輸?流。
OutputStream/Writer: 所有輸出流的基類,前者是字節輸出流,后者是字符輸出流。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TYgB12wq-1632494423986)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901104125545.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gBiCQC4i-1632494423988)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901103711639.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1PoZeikQ-1632494423990)(C:\Users\LENOVO-LX\AppData\Roaming\Typora\typora-user-images\image-20210901101837461.png)]
有字節流為什么還要有字符流
問題本質想問:不管是?件讀寫還是?絡發送接收,信息的最?存儲單元都是字節,那為什么****I/O 流操作要分為字節流操作和字符流操作呢?
回答:字符流是由 Java 虛擬機將字節轉換得到的,問題就出在這個過程?常耗時,并且,如果我們不知道編碼類型就很容易出現亂碼問題。所以, I/O 流就?脆提供了?個直接操作字符的接?,?便我們平時對字符進?流操作。如果?頻?件、圖?等媒體?件?字節流?較好,如果涉及到字符的話使?字符流?較好。
BIO,NIO和AIO區別
BIO (Blocking I/O): 同步阻塞 I/O 模式,數據的讀取寫?必須阻塞在?個線程內等待其完成。在活動連接數不是特別?(?于單機 1000)的情況下,這種模型是?較不錯的,可以讓每?個連接專注于??的 I/O 并且編程模型簡單,也不?過多考慮系統的過載、限流等問題。但是,當?對?萬甚?百萬級連接的時候,傳統的 BIO 模型是?能為?的。
我們建立網絡連接的時候采用BIO模式,需要先在服務端啟動一個ServerSocket,然后在客戶端啟動Socket來對服務端進行通信,默認情況下服務端需要對每個請求建立一堆線程等待請求,而客戶端發送請求后,先咨詢服務端是否有線程相應,如果沒有則會一直等待或者遭到拒絕請求,如果有的話,客戶端會線程會等待請求結束后才繼續執行。
NIO (Non-blocking/New I/O): 同步?阻塞的 I/O 模型,NIO 提供?持阻塞和?阻塞兩種模式。阻塞模式使?就像傳統中的?持?樣,?較簡單,但是性能和可靠性都不好;?阻塞模式對于?負載、?并發的(?絡)應?,應使? NIO 的?阻塞模式來開發
NIO本身是基于事件驅動思想來完成的,其主要想解決的是BIO的大并發問題: 在使用同步I/O的網絡應用中,如果要同時處理多個客戶端請求,或是在客戶端要同時和多個服務器進行通訊,就必須使用多線程來處理。也就是說,將每一個客戶端請求分配給一個線程來單獨處理。這樣做雖然可以達到我們的要求,但同時又會帶來另外一個問題。由于每創建一個線程,就要為這個線程分配一定的內存空間(也叫工作存儲器),而且操作系統本身也對線程的總數有一定的限制。如果客戶端的請求過多,服務端程序可能會因為不堪重負而拒絕客戶端的請求,甚至服務器可能會因此而癱瘓。使用BIO的時候往往會引入多線程,每個連接一個單獨的線程,實現異步處理,降低服務器壓力
AIO (Asynchronous I/O): (即 NIO 2)異步?阻塞的 IO 模型。AIO 是異步 IO 的縮寫,雖然 NIO 在?絡操作中,提供了?阻塞的?法,但是 NIO 的 IO ?為還是同步的。對于 NIO 來說,我們的業務線程是在 IO 操作準備好時,得到通知,接著就由這個線程??進? IO 操作,IO 操作本身是同步的。查閱?上相關資料,我發現就?前來說 AIO 的應?還不是很?泛。
以銀行取款為例:
- 同步 : 自己親自出馬持銀行卡到銀行取錢(使用同步IO時,Java自己處理IO讀寫);
- 異步 : 委托一小弟拿銀行卡到銀行取錢,然后給你(使用異步IO時,Java將IO讀寫委托給OS處理,需要將數據緩沖區地址和大小傳給OS(銀行卡和密碼),OS需要支持異步IO操作API);
- 阻塞 : ATM排隊取款,你只能等待(使用阻塞IO時,Java調用會一直阻塞到讀寫完成才返回);
- 非阻塞 : 柜臺取款,取個號,然后坐在椅子上做其它事,等號廣播會通知你辦理,沒到號你就不能去,你可以不斷問大堂經理排到了沒有,大堂經理如果說還沒到你就不能去(使用非阻塞IO時,如果不能讀寫Java調用會馬上返回,當IO事件分發器會通知可讀寫時再繼續進行讀寫,不斷循環直到讀寫完成)
Java對BIO、NIO、AIO的支持:
- Java BIO : 同步并阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。
- Java NIO : 同步非阻塞,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。
- Java AIO(NIO.2) : 異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理,
BIO、NIO、AIO適用場景分析:
- BIO方式適用于連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,并發局限于應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
- NIO方式適用于連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,并發局限于應用中,編程比較復雜,JDK1.4開始支持。
- AIO方式使用于連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與并發操作,編程比較復雜,JDK7開始支持。
深拷貝和淺拷貝
-
淺拷?:對基本數據類型進?值傳遞,對引?數據類型進?引?傳遞般的拷?,此為淺拷?。
-
深拷?:對基本數據類型進?值傳遞,對引?數據類型,創建?個新的對象,并復制其內容,此為深拷?。
深拷貝和淺拷貝最根本的區別在于是否真正獲取一個對象的復制實體,而不是引用。
- 假設B復制了A,修改A的時候,看B是否發生變化:
- 如果B跟著也變了,說明是淺拷貝,拿人手短!(修改堆內存中的同一個值)
- 如果B沒有改變,說明是深拷貝,自食其力!(修改堆內存中的不同的值)
淺復制:僅僅是指向被復制的內存地址,如果原地址發生改變,那么淺復制出來的對象也會相應的改變。
深復制:在計算機中開辟一塊新的內存地址用于存放復制的對象。
內存泄漏和內存溢出的區別
- 內存溢出(out of memory):指程序在申請內存時,沒有足夠的內存空間供其使用,出現 out of memory。
- 內存泄露(memory leak):指程序在申請內存后,無法釋放已申請的內存空間,內存泄露堆積會導致內存被占光。
- memory leak 最終會導致 out of memory。
java的垃圾回收機制
垃圾回收機制,簡稱 GC
- Java 語言不需要程序員直接控制內存回收,由 JVM 在后臺自動回收不再使用的內存
- 提高編程效率
- 保護程序的完整性
特點
- 回收 JVM 堆內存里的對象空間,不負責回收棧內存數據
- 垃圾回收發生具有不可預知性,程序無法精確控制垃圾回收機制執行
- 可以將對象的引用變量設置為 null,垃圾回收機制可以在下次執行時回收該對象。
- 垃圾回收機制回收任何對象之前,會先調用對象的 finalize() 方法。
- 可以通過 System.gc() 或 Runtime.getRuntime().gc() 通知系統進行垃圾回收,會有一些效果,但系統是否進行垃圾回收依然不確定
java.sql.Date和java.util.Date的區別
- java.sql.Date 是 java.util.Date 的子類
- java.util.Date 是 JDK 中的日期類,精確到時、分、秒、毫秒
- java.sql.Date 與數據庫 Date 相對應的一個類型,只有日期部分,時分秒都會設置為 0,如:2019-10-23 00:00:00
&和&&的作用和區別
&:
- 邏輯與,& 兩邊的表達式都會進行運算
- 整數的位運算符
&&:
- 短路與,&& 左邊的表達式結果為 false 時,&& 右邊的表達式不參與計算
Java中有幾種基本數據類型?它們分別占多大字節?
- byte:1個字節,8位
- short:2個字節,16位
- int:4個字節,32位
- long:8個字節,64位
- float:4個字節,32位
- double:8個字節,64位
- boolean:官方文檔未明確定義,依賴于 JVM 廠商的具體實現。邏輯上理解是占用 1位,但是實際中會考慮計算機高效存儲因素
- char:2個字節,16位
補充說明:字節的英文是 byte,位的英文是 bit
什么是java序列化?什么情況下需要序列化?
序列化:將 Java 對象轉換成字節流的過程。(寫文件)
反序列化:將字節流轉換成 Java 對象的過程。(讀文件)
當 Java 對象需要在網絡上傳輸 或者 持久化存儲到文件中時,就需要對 Java 對象進行序列化處理。
序列化的實現:類實現 Serializable 接口,這個接口沒有需要實現的方法。實現 Serializable 接口是為了告訴 jvm 這個類的對象可以被序列化。
注意事項:
- 某個類可以被序列化,則其子類也可以被序列化
- 對象中的某個屬性是對象類型,需要序列化也必須實現 Serializable 接口
- 聲明為 static 和 transient 的成員變量,不能被序列化。static 成員變量是描述類級別的屬性,transient 表示臨時數據
- 反序列化讀取序列化對象的順序要保持一致
throw和throws區別
throws是用來聲明一個方法可能拋出的所有異常信息,throws是將異常聲明但是不處理,而是將異常往上傳,誰調用我就交給誰處理。
而throw則是指拋出的一個具體的異常類型。
什么是hash和hash表?
Hash,是把任意長度的輸入通過散列算法變換成固定長度的輸出,該輸出就是散列值。使用Hash算法可以提高存儲空間的利用率,可以提高數據的查詢效率,也可以做數字簽名來保障數據傳遞的安全性。
對不同的關鍵字可能得到同一散列地址,現象稱碰撞。一組關鍵字和它們各自對應的散列地址映射到一個有限的連續的地址集(區間)上,這種表便稱為散列表
總結
以上是生活随笔為你收集整理的Java基础面试典籍60+ | 大别山码将的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javaone_替代JavaOne 20
- 下一篇: Java的最新发展– 2018年4月下旬