- 點擊主頁訪問更多精彩文章:https://blog.csdn.net/weixin_45692705?spm=1001.2101.3001.5343

Java基礎面試題目錄
- 共勉 !
- Java概述
- 1.什么是Java
- 2.何為編程
- 3.JDK和JRE和JVM的區別
- 5.Java語言有哪些特點
- 6.什么是位元組碼?采用位元組碼的最大好處是什么
- 7.什么是Java程式的主類?應用程式和小程式的主類有何不同?
- 8. Java和C++的區別
- 9. Java應用程式與小程式之間有那些差別?
- 10.Java是哪年誕生的
- 基礎語法
- 1. Java有哪些資料型別
- 2. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String上
- 3. 用最有效率的方法計算 2 乘以 8
- 4. Math.round(11.5) 等于多少Math.round(-11.5)等于多少
- 5. float f=3.4;是否正確
- 6. short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎
- 7. Java語言采用何種編碼方案?有何特點?
- 8. 什么是Java注釋
- 分類
- 作用
- 9. 訪問修飾符 public,private,protected,以及不寫(默認)時的區別
- 分類
- 10. &和&&的區別
- 11. Java 有沒有 goto
- 12. final 有什么用?
- 13. final finally finalize區別
- 14. this關鍵字的用法
- 15. super關鍵字的用法
- 16. this與super的區別
- 17. static存在的主要意義
- 18. static的獨特之處
- 19. static應用場景
- 20. static注意事項
- 21. break ,continue ,return 的區別及作用
- 22. 在 Java 中,如何跳出當前的多重嵌套回圈
- 面向物件
- 面向物件概述
- 1. 面向物件和面向程序的區別
- 面向物件三大特性
- 1. 面向物件的特征有哪些方面
- 2. 什么是多型機制?Java語言是如何實作多型的?
- 3. 面向物件五大基本原則是什么(可選)
- 類與介面
- 1.抽象類和介面的對比
- 2. 普通類和抽象類有哪些區別?
- 3. 抽象類能使用 final 修飾嗎?
- 4. 創建一個物件用什么關鍵字?物件實體與物件參考有何不同?
- 變數與方法
- 1. 成員變數與區域變數的區別有哪些
- 2. 在Java中定義一個不做事且沒有引數的構造方法的作用
- 3. 在呼叫子類構造方法之前會先呼叫父類沒有引數的構造方法,其目的是?
- 4. 一個類的構造方法的作用是什么?若一個類沒有宣告構造方法,改程式能正確執行嗎?為什么?
- 5. 構造方法有哪些特性?
- 6. 靜態變數和實體變數區別
- 7. 靜態變數與普通變數區別
- 8. 靜態方法和實體方法有何不同?
- 9. 在一個靜態方法內呼叫一個非靜態成員為什么是非法的?
- 10. 什么是方法的回傳值?回傳值的作用是什么?
- 內部類
- 1. 什么是內部類?
- 2. 內部類的分類有哪些
- 3. 內部類的優點
- 4. 內部類有哪些應用場景
- 5. 區域內部類和匿名內部類訪問區域變數的時候,為什么變數必須要加上final?
- 6. 內部類相關,看程式說出運行結果
- 重寫與多載
- 1. 構造器(constructor)是否可被重寫(override)
- 2. 多載(Overload)和重寫(Override)的區別,多載的方法能否根據回傳型別進行區分?
- 物件相等判斷
- 1. == 和 equals 的區別是什么
- 2. hashCode 與 equals (重要)
- 3. 物件的相等與指向他們的參考相等,兩者有什么不同?
- 4. 當一個物件被當作引數傳遞到一個方法后,此方法可改變這個物件的屬性,并可回傳變化后的結果,那么這里到底是值傳遞還是參考傳遞?
- 5. 為什么 Java 中只有值傳遞
- 6. 值傳遞和參考傳遞有什么區別
- Java包
- 1. JDK 中常用的包有哪些
- 2. import java和javax有什么區別
- IO流
- 反射
- 1. 什么是反射機制?
- 2. 反射機制優缺點
- 3. 反射機制的應用場景有哪些?
- 4. Java獲取反射的三種方法
- 常用API
- String的常用API
- 1. 字符型常量和字串常量的區別
- 2. 什么是字串常量池?
- 3. String 是最基本的資料型別嗎
- 4. String有哪些特性
- 5. String真的是不可變的嗎?
- 6. 是否可以繼承 String 類
- 7. String str="i"與 String str=new String(“i”)一樣嗎?
- 8. String s = new String(“xyz”);創建了幾個字串物件
- 9. 如何將字串反轉?
- 10. 陣列有沒有 length()方法?String 有沒有 length()方法
- 11. String 類的常用方法都有那些?
- 12. 在使用 HashMap 的時候,用 String 做 key 有什么好處?
- 13. String和StringBuffer、StringBuilder的區別是什么?String為什么是不可變的
- 包裝類相關
- 1. 自動裝箱與拆箱
- 2. int 和 Integer 有什么區別
- 3. Integer a= 127 與 Integer b = 127相等嗎
共勉 !
送給大家一句話:平凡的腳步也可以走完偉大的行程

Java概述

1.什么是Java
Java是一門面向物件編程語言,不僅吸收了C++語言的各種優點,還摒棄了C++里難以理解的多繼承、指標等概念,因此Java語言具有功能強大和簡單易用兩個特征,Java語言作為靜態面向物件編程語言的代表,極好地實作了面向物件理論,允許程式員以優雅的思維方式進行復雜的編程 ,
2.何為編程
編程就是讓計算機為解決某個問題而使用某種程式設計語言撰寫程式代碼,并最終得到結果的程序,為了使計算機能夠理解人的意圖,人類就必須要將需解決的問題的思路、方法、和手段通過計算機能夠理解的形式告訴計算機,使得計算機能夠根據人的指令一步一步去作業,完成某種特定的任務,這種人和計算機之間交流的程序就是編程,
3.JDK和JRE和JVM的區別
看Java官方的圖片,Jdk中包括了Jre,Jre中包括了JVM
JDK :Jdk還包括了一些Jre之外的東西 ,就是這些東西幫我們編譯Java代碼的, 還有就是監控Jvm的一些工具 Java Development Kit是提供給Java開發人員使用的,其中包含了Java的開發工具,也包括了JRE,所以安裝了JDK,就無需再單獨安裝JRE了,其中的開發工具:編譯工具(javac.exe),打包工具(jar.exe)等,
JRE :Jre大部分都是 C 和 C++ 語言撰寫的,他是我們在編譯java時所需要的基礎的類別庫 Java Runtime Environment包括Java虛擬機和Java程式所需的核心類別庫等,核心類別庫主要是java.lang包:包含了運行Java程式必不可少的系統類,如基本資料型別、基本數學函式、字串處理、執行緒、例外處理類等,系統預設加載這個包如果想要運行一個開發好的Java程式,計算機中只需要安裝JRE即可,
JVM:在倒數第二層 由他可以在(最后一層的)各種平臺上運行 Java Virtual Machine是Java虛擬機,Java程式需要運行在虛擬機上,不同的平臺有自己的虛擬機,因此Java語言可以實作跨平臺,

5.Java語言有哪些特點
-
簡單易學(Java語言的語法與C語言和C++語言很接近)
-
面向物件(封裝,繼承,多型)
-
平臺無關性(Java虛擬機實作平臺無關性)
-
支持網路編程并且很方便(Java語言誕生本身就是為簡化網路編程設計的)
-
支持多執行緒(多執行緒機制使應用程式在同一時間并行執行多項任)
-
健壯性(Java語言的強型別機制、例外處理、垃圾的自動收集等)
-
安全性好
6.什么是位元組碼?采用位元組碼的最大好處是什么
位元組碼:Java源代碼經過虛擬機編譯器編譯后產生的檔案(即擴展為.class的檔案),它不面向任何特定的處理器,只面向虛擬機,
采用位元組碼的好處:
- Java語言通過位元組碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點,所以Java程式運行時比較高效,而且,由于位元組碼并不專對一種特定的機器,因此,Java程式無須重新編譯便可在多種不同的計算機上運行,
先看下java中的編譯器和解釋器:
- Java中引入了虛擬機的概念,即在機器和編譯程式之間加入了一層抽象的虛擬機器,這臺虛擬的機器在任何平臺上都提供給編譯程式一個的共同的介面,編譯程式只需要面向虛擬機,生成虛擬機能夠理解的代碼,然后由解釋器來將虛擬機代碼轉換為特定系統的機器碼執行,在Java中,這種供虛擬機理解的代碼叫做位元組碼(即擴展為.class的檔案),它不面向任何特定的處理器,只面向虛擬機,每一種平臺的解釋器是不同的,但是實作的虛擬機是相同的,Java源程式經過編譯器編譯后變成位元組碼,位元組碼由虛擬機解釋執行,虛擬機將每一條要執行的位元組碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然后在特定的機器上運行,這就是上面提到的Java的特點的編譯與解釋并存的解釋,
Java源代碼---->編譯器---->jvm可執行的Java位元組碼(即虛擬指令)---->jvm---->jvm中解釋器----->機器可執行的二進制機器碼---->程式運行,
7.什么是Java程式的主類?應用程式和小程式的主類有何不同?
一個程式中可以有多個類,但只能有一個類是主類,在Java應用程式中,這個主類是指包含main()方法的類,而在Java小程式中,這個主類是一個繼承自系統類JApplet或Applet的子類,應用程式的主類不一定要求是public類,但小程式的主類要求必須是public類,主類是Java程式執行的入口點,
8. Java和C++的區別
我知道很多人沒學過C++,但是面試官就是沒事喜歡拿咱們Java和C++比呀!沒辦法!!!就算沒學過C++,也要 記下來!都是面向物件的語言,都支持封裝、繼承和多型Java不提供指標來直接訪問記憶體,程式記憶體更加安全Java的類是單繼承的,C++支持多重繼承;雖然Java的類不可以多繼承,但是介面可以多繼承,Java有自動記憶體管理機制,不需要程式員手動釋放無用記憶體
9. Java應用程式與小程式之間有那些差別?
- Oracle JDK版本將每三年發布一次,而OpenJDK版本每三個月發布一次;
- OpenJDK 是一個參考模型并且是完全開源的,而Oracle JDK是OpenJDK的一個實作,并不是完全開源的;
- Oracle JDK 比 OpenJDK 更穩定,OpenJDK和Oracle JDK的代碼幾乎相同,但Oracle JDK有更多的類和一些錯誤修復,因此,如果您想開發企業/商業軟體,我建議您選擇Oracle JDK,因為它經過了徹底的測驗和穩定,某些情況下,有些人提到在使用OpenJDK 可能會遇到了許多應用程式崩潰的問題,但是,只需切換到Oracle JDK就可以解決問題;
- 在回應性和JVM性能方面,Oracle JDK與OpenJDK相比提供了更好的性能;
- Oracle JDK不會為即將發布的版本提供長期支持,用戶每次都必須通過更新到最新版本獲得支持來
獲取最新版本; - Oracle JDK根據二進制代碼許可協議獲得許可,而OpenJDK根據GPL v2許可獲得許可,
10.Java是哪年誕生的
Java,誕生于1995年,原屬于SUM公司,2009年,美國甲骨文公司(Oracle)收購了SUM公司,
Java三大平臺:Java SE、Java EE、Java EE
-
Java SE:Java標準平臺,它是Java EE的基礎,它允許開發軟體運行在電腦桌面,(Eclipse就是JavaSE程式)
-
Java ME:Java微型平臺,用來開發移動設備上的軟體,比如早期諾基亞等按鍵機上的Java游戲,現在基本都使用Android和iOS開發手機軟體,
-
Java EE:Java企業平臺,針對web方向,主要應用于開發企業專案和互聯網專案,如淘寶,京東的后臺
基礎語法

1. Java有哪些資料型別
定義:Java語言是強型別語言,對于每一種資料都定義了明確的具體的資料型別,在記憶體中分配了不同大小的記憶體空間,
2. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String上
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int,從 Java5 開始,Java 中引入了列舉型別,expr 也可以是 enum 型別,從 Java 7 開始,expr 還可以是字串(String),但是長整型(long)在目前所有的版本中都是不可以的,
3. 用最有效率的方法計算 2 乘以 8
2 << 3(左移 3 位相當于乘以 2 的 3 次方,右移 3 位相當于除以 2 的 3 次方),
4. Math.round(11.5) 等于多少Math.round(-11.5)等于多少
Math.round(11.5)的回傳值是 12,Math.round(-11.5)的回傳值是-11,四舍五入的原理是在引數上加 0.5 然后進行下取整,
5. float f=3.4;是否正確
不正確,
- 3.4 是雙精度數,將雙精度型(double)賦值給浮點型(float)屬于下轉型(downcasting,也稱為窄化)會造成精度損失,因此需要強制型別轉換float f =(float)3.4; 或者寫成 floatf =3.4F;,
6. short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎
- 對于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 型別,因此 s1+1 運算結果也是 int型,需要強制轉換型別才能賦值給 short 型,
- 而 short s1 = 1; s1 += 1;可以正確編譯,因為 s1+= 1;相當于 s1 = (short(s1 + 1);其中有隱含的強制型別轉換,
7. Java語言采用何種編碼方案?有何特點?
Java語言采用Unicode編碼標準,Unicode(標準碼),它為每個字符制訂了一個唯一的數值,因此在任何的語言,平臺,程式都可以放心的使用,
8. 什么是Java注釋
定義:用于解釋說明程式的文字
分類
單行注釋
- 格式: // 注釋文字
多行注釋
- 格式: /* 注釋文字 */
檔案注釋
- 格式:/** 注釋文字 */
作用
在程式中,尤其是復雜的程式中,適當地加入注釋可以增加程式的可讀性,有利于程式的修改、除錯和交流,注釋的內容在程式編譯的時候會被忽視,不會產生目標代碼,注釋的部分不會對程式的執行結果產生任何影響,
注意事項:多行和檔案注釋都不能嵌套使用,
9. 訪問修飾符 public,private,protected,以及不寫(默認)時的區別
定義:Java中,可以使用訪問修飾符來保護對類、變數、方法和構造方法的訪問,Java 支持 4 種不同的訪問權限,
分類
- private : 在同一類內可見,使用物件:變數、方法, 注意:不能修飾類(外部類)
- default (即預設,什么也不寫,不使用任何關鍵字): 在同一包內可見,不使用任何修飾符,使用物件:類、介面、變數、方法,
- protected : 對同一包內的類和所有子類可見,使用物件:變數、方法, 注意:不能修飾類(外部類),
- public : 對所有類可見,使用物件:類、介面、變數、方法

10. &和&&的區別
&運算子有兩種用法:(1)按位與;(2)邏輯與,&&運算子是短路與運算,邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運算子左右兩端的布林值都是true 整個運算式的值才是 true,&&之所以稱為短路運算,是因為如果&&左邊的運算式的值是 false,右邊的運算式會被直接短路掉,不會進行運算,
注意:邏輯或運算子(|)和短路或運算子(||)的差別也是如此,
11. Java 有沒有 goto
goto 是 Java 中的保留字,在目前版本的 Java 中沒有使用,
12. final 有什么用?
用于修飾類、屬性和方法;
- 被final修飾的類不可以被繼承
- 被final修飾的方法不可以被重寫
- 被final修飾的變數不可以被改變,被final修飾不可變的是變數的參考,而不是參考指向的內容,
- 參考指向的內容是可以改變的
13. final finally finalize區別
-
final: final可以修飾類、變數、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變數表 示該變數是一個常量不能被重新賦值,
-
finally: finally一般作用在try-catch代碼塊中,在處理例外的時候,通常我們將一定要執行的代碼方法finally代碼塊 中,表示不管是否出現例外,該代碼塊都會執行,一般用來存放一些關閉資源的代碼,
-
finalize: finalize是一個方法,屬于Object類的一個方法,而Object類是所有類的父類,該方法一般由垃圾回收器來調 用,當我們呼叫System.gc() 方法的時候,由垃圾回收器呼叫finalize(),回收垃圾,一個物件是否可回收的 最后判斷,
14. this關鍵字的用法
this是自身的一個物件,代表物件本身,可以理解為:指向物件本身的一個指標,
this的用法在java中大體可以分為3種:
- 普通的直接參考,this相當于是指向當前物件本身,
- 形參與成員名字重名,用this來區分:
public Person(String name, int age) {
this.name = name;
this.age = age;
}
- 參考本類的建構式
class Person{
private String name;
private int age;
public Person() {}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this(name);
this.age = age;
}
}
15. super關鍵字的用法
super可以理解為是指向自己超(父)類物件的一個指標,而這個超類指的是離自己最近的一個父類,
super也有三種用法:
-
普通的直接參考與this類似,super相當于是指向當前物件的父類的參考,這樣就可以用super.xxx來參考父類的成員,
-
子類中的成員變數或方法與父類中的成員變數或方法同名時,用super進行區分
class Person{
protected String name;
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
private String name;
public Student(String name, String name1) {
super(name); this.name = name1;
}
public void getInfo(){
System.out.println(this.name); //Child
System.out.println(super.name); //Father
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Father","Child"); s1.getInfo();
}
}
- 參考父類建構式:
super(引數):呼叫父類中的某一個建構式(應該為建構式中的第一條陳述句),
this(引數):呼叫本類中另一種形式的建構式(應該為建構式中的第一條陳述句),
16. this與super的區別
super: 它參考當前物件的直接父類中的成員(用來訪問直接父類中被隱藏的父類中成員資料或函式,基類與派生類中有相同成員定義時如:super.變數名 super.成員函資料名(實參)
this: 它代表當前物件名(在程式中易產生二義性之處,應使用this來指明當前物件;如果函式的形參與類中的成員資料同名,這時需用this來指明成員變數名)
- super()和this()類似,區別是,super()在子類中呼叫父類的構造方法,this()在本類內呼叫本類的其它構造方法,super()和this()均需放在構造方法內第一行,盡管可以用this呼叫一個構造器,但卻不能呼叫兩個,this和super不能同時出現在一個建構式里面,因為this必然會呼叫其它的建構式,其它的建構式必然也會有super陳述句的存在,所以在同一個建構式里面有相同的陳述句,就失去了陳述句的意義,編譯器也不會通過,this()和super()都指的是物件,所以,均不可以在static環境中使用,包括:static變數,static方法,static陳述句塊,從本質上講,this是一個指向本物件的指標, 然而super是一個Java關鍵字,
17. static存在的主要意義
static的主要意義是在于創建獨立于具體物件的域變數或者方法,以致于即使沒有創建物件,也能使用屬性和呼叫方法!static關鍵字還有一個比較關鍵的作用就是 用來形成靜態代碼塊以優化程式性能,static塊可以置于類中的任何地方,類中可以有多個static塊,在類初次被加載的時候,會按照static塊的順序來執行每個static塊,并且只會執行一次,為什么說static塊可以用來優化程式性能,是因為它的特性:只會在類加載的時候執行一次,因此,很多時候會將一些只需要進行一次的初始化操作都放在static代碼塊中進行,
18. static的獨特之處
- 被static修飾的變數或者方法是獨立于該類的任何物件,也就是說,這些變數和方法不屬于任何一個實體物件,而是被類的實體物件所共享,
怎么理解 “被類的實體物件所共享” 這句話呢?就是說,一個類的靜態成員,它是屬于大伙的【大伙指的是這個類的多個物件實體,我們都知道一個類可以創建多個實體!】,所有的類物件共享的,不像成員變數是自個的【自個指的是這個類的單個實體物件】…我覺得我已經講的很通俗了,你明白了嗎?
- 在該類被第一次加載的時候,就會去加載被static修飾的部分,而且只在類第一次使用時加載并進行初始化,注意這是第一次用就要初始化,后面根據需要是可以再次賦值的,
- static變數值在類加載的時候分配空間,以后創建類物件的時候不會重新分配,賦值的話,是可以任意賦值的!
- 被static修飾的變數或者方法是優先于物件存在的,也就是說當一個類加載完畢之后,即便沒有創建物件,也可以去訪問,
19. static應用場景
因為static是被類的實體物件所共享,因此如果某個成員變數是被所有物件所共享的,那么這個成員變數就應該定義為靜態變數,
因此比較常見的static應用場景有:
- 修飾成員變數
- 修飾成員方法
- 靜態代碼塊
- 修飾類【只能修飾內部類也就是靜態內部類】
- 靜態導包
20. static注意事項
- 靜態只能訪問靜態,
- 非靜態既可以訪問非靜態的,也可以訪問靜態的,
21. break ,continue ,return 的區別及作用
- break 跳出總上一層回圈,不再執行回圈(結束當前的回圈體)
- continue 跳出本次回圈,繼續執行下次回圈(結束正在執行的回圈 進入下一個回圈條件)
- return 程式回傳,不再執行下面的代碼(結束當前的方法 直接回傳)
22. 在 Java 中,如何跳出當前的多重嵌套回圈
在Java中,要想跳出多重回圈,可以在外面的回圈陳述句前定義一個標號,然后在里層回圈體的代碼中使用帶有標號的break 陳述句,即可跳出外層回圈,
例如:
public static void main(String[] args) {
ok:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i=" + i + ",j=" + j);
if (j == 5) {
break ok;
}
}
}
}
面向物件

面向物件概述
1. 面向物件和面向程序的區別
面向程序:
- 優點:性能比面向物件高,因為類呼叫時需要實體化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般采用面向程序開發,性能是最重要的因素,
- 缺點:沒有面向物件易維護、易復用、易擴展
面向物件:
- 優點:易維護、易復用、易擴展,由于面向物件有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易于維護
- 缺點:性能比面向程序低
面向程序是具體化的,流程化的,解決一個問題,你需要一步一步的分析,一步一步的實作,
面向物件是模型化的,你只需抽象出一個類,這是一個封閉的盒子,在這里你擁有資料也擁有解決問題的方法,需要什么功能直接使用就可以了,不必去一步一步的實作,至于這個功能是如何實作的,管我們什么事?我們會用就可以了,
面向物件的底層其實還是面向程序,把面向程序抽象成類,然后封裝,方便我們使用的就是面向物件了,
面向物件三大特性

1. 面向物件的特征有哪些方面
- 抽象是將一類物件的共同特征總結出來構造類的程序,包括資料抽象和行為抽象兩方面,抽象只關注物件有哪些屬性和行為,并不關注這些行為的細節是什么,
- 封裝把一個物件的屬性私有化,同時提供一些可以被外界訪問的屬性的方法,如果屬性不想被外界訪問,我們大可不必提供方法給外界訪問,但是如果一個類沒有提供給外界訪問的方法,那么這個類也沒有什么意義了,
- 繼承是使用已存在的類的定義作為基礎建立新類的技術,新類的定義可以增加新的資料或新的功
能,也可以用父類的功能,但不能選擇性地繼承父類,通過使用繼承我們能夠非常方便地復用以前
的代碼,
關于繼承如下 3 點請記住:
- 子類擁有父類非 private 的屬性和方法,
- 子類可以擁有自己屬性和方法,即子類可以對父類進行擴展,
- 子類可以用自己的方式實作父類的方法,(以后介紹),
- 多型:父類或介面定義的參考變數可以指向子類或具體實作類的實體物件,提高了程式的拓展性,在Java中有兩種形式可以實作多型:繼承(多個子類對同一方法的重寫)和介面(實作介面并覆寫介面中同一方法),
2. 什么是多型機制?Java語言是如何實作多型的?
- 所謂多型就是指程式中定義的參考變數所指向的具體型別和通過該參考變數發出的方法呼叫在編程時并不確定,而是在程式運行期間才確定,即一個參考變數倒底會指向哪個類的實體物件,該參考變數發出的方法呼叫到底是哪個類中實作的方法,必須在由程式運行期間才能決定,因為在程式運行時才確定具體的類,這樣,不用修改源程式代碼,就可以讓參考變數系結到各種不同的類實作上,從而導致該參考呼叫的具體方法隨之改變,即不修改程式代碼就可以改變程式運行時所系結的具體代碼,讓程式可以選擇多個運行狀態,這就是多型性,
- 多型分為編譯時多型和運行時多型,其中編輯時多型是靜態的,主要是指方法的多載,它是根據參
數串列的不同來區分不同的函式,通過編輯之后會變成兩個不同的函式,在運行時談不上多型,而
運行時多型是動態的,它是通過動態系結來實作的,也就是我們所說的多型性,
多型的實作
Java實作多型有三個必要條件:繼承、重寫、向上轉型,
- 繼承:在多型中必須存在有繼承關系的子類和父類,
- 重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法,
- 向上轉型:在多型中需要將子類的參考賦給父類物件,只有這樣該參考才能夠具備技能呼叫父類的方法和子類的方法,
只有滿足了上述三個條件,我們才能夠在同一個繼承結構中使用統一的邏輯實作代碼處理不同的物件,從而達到執行不同的行為,
對于Java而言,它多型的實作機制遵循一個原則:當超類物件參考變數參考子類物件時,被參考物件的型別而不是參考變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆寫的方法,
3. 面向物件五大基本原則是什么(可選)
單一職責原則SRP(Single Responsibility Principle)
- 類的功能要單一,不能包羅萬象,跟雜貨鋪似的,
開放封閉原則OCP(Open-Close Principle)
- 一個模塊對于拓展是開放的,對于修改是封閉的,想要增加功能熱烈歡迎,想要修改,哼,一萬個不樂意,
里式替換原則LSP(the Liskov Substitution Principle LSP)
- 子類可以替換父類出現在父類能夠出現的任何地方,比如你能代表你爸去你姥姥家干活,哈哈~~
依賴倒置原則DIP(the Dependency Inversion Principle DIP)
- 高層次的模塊不應該依賴于低層次的模塊,他們都應該依賴于抽象,抽象不應該依賴于具體實作,具體實作應該依賴于抽象,就是你出國要說你是中國人,而不能說你是哪個村子的,比如說中國人是抽象的,下面有具體的xx省,xx市,xx縣,你要依賴的抽象是中國人,而不是你是xx村的,
介面分離原則ISP(the Interface Segregation Principle ISP)
- 設計時采用多個與特定客戶類有關的介面比采用一個通用的介面要好,就比如一個手機擁有打電話,看視頻,玩游戲等功能,把這幾個功能拆分成不同的介面,比在一個介面里要好的多,
類與介面

1.抽象類和介面的對比
抽象類是用來捕捉子類的通用特性的,介面是抽象方法的集合,
從設計層面來說,抽象類是對類的抽象,是一種模板設計,介面是行為的抽象,是一種行為的規范,
相同點
- 介面和抽象類都不能實體化
- 都位于繼承的頂端,用于被其他實作或繼承
- 都包含抽象方法,其子類都必須覆寫這些抽象方法
不同點

備注: Java8中介面中引入默認方法和靜態方法,以此來減少抽象類和介面之間的差異,
現在,我們可以為介面提供默認實作的方法了,并且不用強制子類來實作它,
介面和抽象類各有優缺點,在介面和抽象類的選擇上,必須遵守這樣一個原則:
- 行為模型應該總是通過介面而不是抽象類定義,所以通常是優先選用介面,盡量少用抽象類,
- 選擇抽象類的時候通常是如下情況:需要定義子類的行為,又要為子類提供通用的功能,
2. 普通類和抽象類有哪些區別?
普通類不能包含抽象方法,抽象類可以包含抽象方法,
抽象類不能直接實體化,普通類可以直接實體化,
3. 抽象類能使用 final 修飾嗎?
不能,定義抽象類就是讓其他類繼承的,如果定義為 final 該類就不能被繼承,這樣彼此就會產生矛盾,所以 final 不能修飾抽象類,
4. 創建一個物件用什么關鍵字?物件實體與物件參考有何不同?
new關鍵字,new創建物件實體(物件實體在堆記憶體中),物件參考指向物件實體(物件參考存放在堆疊記憶體中),一個物件參考可以指向0個或1個物件(一根繩子可以不系氣球,也可以系一個氣球);一個物件可以有n個參考指向它(可以用n條繩子系住一個氣球)
變數與方法

1. 成員變數與區域變數的區別有哪些
- 變數:在程式執行的程序中,在某個范圍內其值可以發生改變的量,從本質上講,變數其實是記憶體中的一小塊區域
- 成員變數:方法外部,類內部定義的變數
- 區域變數:類的方法中的變數,
成員變數和區域變數的區別
作用域
- 成員變數:針對整個類有效,
- 區域變數:只在某個范圍內有效,(一般指的就是方法,陳述句體內)
存盤位置
- 成員變數:隨著物件的創建而存在,隨著物件的消失而消失,存盤在堆記憶體中,
- 區域變數:在方法被呼叫,或者陳述句被執行的時候存在,存盤在堆疊記憶體中,當方法呼叫完,或者陳述句結束后,就自動釋放,
生命周期
- 成員變數:隨著物件的創建而存在,隨著物件的消失而消失
- 區域變數:當方法呼叫完,或者陳述句結束后,就自動釋放,
初始值
- 成員變數:有默認初始值,
- 區域變數:沒有默認初始值,使用前必須賦值,
2. 在Java中定義一個不做事且沒有引數的構造方法的作用
Java程式在執行子類的構造方法之前,如果沒有用super()來呼叫父類特定的構造方法,則會呼叫父類中“沒有引數的構造方法”,因此,如果父類中只定義了有引數的構造方法,而在子類的構造方法中又沒有用super()來呼叫父類中特定的構造方法,則編譯時將發生錯誤,因為Java程式在父類中找不到沒有引數的構造方法可供執行,解決辦法是在父類里加上一個不做事且沒有引數的構造方法,
3. 在呼叫子類構造方法之前會先呼叫父類沒有引數的構造方法,其目的是?
幫助子類做初始化作業,
4. 一個類的構造方法的作用是什么?若一個類沒有宣告構造方法,改程式能正確執行嗎?為什么?
主要作用是完成對類物件的初始化作業,可以執行,因為一個類即使沒有宣告構造方法也會有默認的不帶引數的構造方法,
5. 構造方法有哪些特性?
- 名字與類名相同;
- 沒有回傳值,但不能用void宣告建構式;
- 生成類的物件時自動執行,無需呼叫,
6. 靜態變數和實體變數區別
- 靜態變數: 靜態變數由于不屬于任何實體物件,屬于類的,所以在記憶體中只會有一份,在類的加載程序中,JVM只為靜態變數分配一次記憶體空間,
- 實體變數: 每次創建物件,都會為每個物件分配成員變數記憶體空間,實體變數是屬于實體物件的,在記憶體中,創建幾次物件,就有幾份成員變數,
7. 靜態變數與普通變數區別
- static變數也稱作靜態變數,靜態變數和非靜態變數的區別是:靜態變數被所有的物件所共享,在記憶體中只有一個副本,它當且僅當在類初次加載時會被初始化,而非靜態變數是物件所擁有的,在創建物件的時候被初始化,存在多個副本,各個物件擁有的副本互不影響,
還有一點就是static成員變數的初始化順序按照定義的順序進行初始化,
8. 靜態方法和實體方法有何不同?
靜態方法和實體方法的區別主要體現在兩個方面:
-
在外部呼叫靜態方法時,可以使用"類名.方法名"的方式,也可以使用"物件名.方法名"的方式,而實體方法只有后面這種方式,也就是說,呼叫靜態方法可以無需創建物件,
-
靜態方法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變數和靜態方法),而不允許訪問實體成員變數和實體方法;實體方法則無此限制,
9. 在一個靜態方法內呼叫一個非靜態成員為什么是非法的?
由于靜態方法可以不通過物件進行呼叫,因此在靜態方法里,不能呼叫其他非靜態變數,也不可以訪問非靜態變數成員,
10. 什么是方法的回傳值?回傳值的作用是什么?
方法的回傳值是指我們獲取到的某個方法體中的代碼執行后產生的結果!(前提是該方法可能產生結果),回傳值的作用:接收出結果,使得它可以用于其他的操作!
內部類

1. 什么是內部類?
在Java中,可以將一個類的定義放在另外一個類的定義內部,這就是內部類,內部類本身就是類的一個屬性,與其他屬性定義方式一致,
2. 內部類的分類有哪些
內部類可以分為四種:成員內部類、區域內部類、匿名內部類和靜態內部類
靜態內部類
- 定義在類內部的靜態類,就是靜態內部類,
public class Outer {
private static int radius = 1;
static class StaticInner {
public void visit() {
System.out.println("visit outer static variable:" + radius);
}
}
}
- 靜態內部類可以訪問外部類所有的靜態變數,而不可訪問外部類的非靜態變數;靜態內部類的創建方式,
new 外部類.靜態內部類(),如下:
Outer.StaticInner inner = new Outer.StaticInner();
inner.visit();
成員內部類
- 定義在類內部,成員位置上的非靜態類,就是成員內部類,
public class Outer {
private static int radius = 1;
private int count =2;
class Inner {
public void visit() {
System.out.println("visit outer static variable:" + radius);
System.out.println("visit outer variable:" + count);
}
}
}
- 成員內部類可以訪問外部類所有的變數和方法,包括靜態和非靜態,私有和公有,成員內部類依賴于外部類的實體,它的創建方式
外部類實體.new 內部類(),如下:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.visit();
區域內部類
- 定義在方法中的內部類,就是區域內部類,
public class Outer {
private int out_a = 1;
private static int STATIC_b = 2;
public void testFunctionClass(){
int inner_c =3;
class Inner {
private void fun(){
System.out.println(out_a);
System.out.println(STATIC_b);
System.out.println(inner_c);
}
}
Inner inner = new Inner();
inner.fun();
}
public static void testStaticFunctionClass(){
int d =3;
class Inner {
private void fun(){
// System.out.println(out_a); 編譯錯誤,定義在靜態方法中的區域類不可以訪問外部類的實體變數
System.out.println(STATIC_b);
System.out.println(d);
}
}
Inner inner = new Inner();
inner.fun();
}
}
- 定義在實體方法中的區域類可以訪問外部類的所有變數和方法,定義在靜態方法中的區域類只能訪問外部類的靜態變數和方法,區域內部類的創建方式,在對應方法內,
new 內部類(),如下:
public static void testStaticFunctionClass(){
class Inner {
}
Inner inner = new Inner();
}
匿名內部類
- 匿名內部類就是沒有名字的內部類,日常開發中使用的比較多,
public class Outer {
private void test(final int i) {
new Service() {
public void method() {
for (int j = 0; j < i; j++) {
System.out.println("匿名內部類" );
}
}
}.method();
}
}
//匿名內部類必須繼承或實作一個已有的介面
interface Service{
void method();
}
- 除了沒有名字,匿名內部類還有以下特點:
- 匿名內部類必須繼承一個抽象類或者實作一個介面,
- 匿名內部類不能定義任何靜態成員和靜態方法,
- 當所在的方法的形參需要被匿名內部類使用時,必須宣告為 final,
- 匿名內部類不能是抽象的,它必須要實作繼承的類或者實作的介面的所有抽象方法,
- 匿名內部類創建方式:
new 類/介面{
//匿名內部類實作部分
}
3. 內部類的優點
我們為什么要使用內部類呢?因為它有以下優點:
- 一個內部類物件可以訪問創建它的外部類物件的內容,包括私有資料!
- 內部類不為同一包的其他類所見,具有很好的封裝性;
- 內部類有效實作了“多重繼承”,優化 java 單繼承的缺陷,
- 匿名內部類可以很方便的定義回呼,
4. 內部類有哪些應用場景
- 一些多演算法場合
- 解決一些非面向物件的陳述句塊,
- 適當使用內部類,使得代碼更加靈活和富有擴展性,
- 當某個類除了它的外部類,不再被其他的類使用時,
5. 區域內部類和匿名內部類訪問區域變數的時候,為什么變數必須要加上final?
區域內部類和匿名內部類訪問區域變數的時候,為什么變數必須要加上final呢?它內部原理是什么呢?
先看這段代碼:
public class Outer {
void outMethod(){
final int a =10;
class Inner {
void innerMethod(){
System.out.println(a);
}
}
}
}
- 以上例子,為什么要加final呢?是因為生命周期不一致, 區域變數直接存盤在堆疊中,當方法執行結束后,非final的區域變數就被銷毀,而區域內部類對區域變數的參考依然存在,如果區域內部類要呼叫區域變數時,就會出錯,加了final,可以確保區域內部類使用的變數與外層的區域變數區分開,解決了這個問題,
6. 內部類相關,看程式說出運行結果
public class Outer {
private int age = 12;
class Inner {
private int age = 13;
public void print() {
int age = 14;
System.out.println("區域變數:" + age);
System.out.println("內部類變數:" + this.age);
System.out.println("外部類變數:" + Outer.this.age);
}
}
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.print();
}
}
- 運行結果:
區域變數:14
內部類變數:13
外部類變數:12
重寫與多載

1. 構造器(constructor)是否可被重寫(override)
構造器不能被繼承,因此不能被重寫,但可以被多載,
2. 多載(Overload)和重寫(Override)的區別,多載的方法能否根據回傳型別進行區分?
方法的多載和重寫都是實作多型的方式,區別在于前者實作的是編譯時的多型性,而后者實作的是運行時的多型性,
- 多載:發生在同一個類中,方法名相同引數串列不同(引數型別不同、個數不同、順序不同),與方法回傳值和訪問修飾符無關,即多載的方法不能根據回傳型別進行區分
- 重寫:發生在父子類中,方法名、引數串列必須相同,回傳值小于等于父類,拋出的例外小于等于父類,訪問修飾符大于等于父類(里氏代換原則);如果父類方法訪問修飾符為private則子類中就不是重寫,
物件相等判斷

1. == 和 equals 的區別是什么
==: 它的作用是判斷兩個物件的地址是不是相等,即,判斷兩個物件是不是同一個物件,(基本資料型別==比較的是值,參考資料型別==比較的是記憶體地址)equals(): 它的作用也是判斷兩個物件是否相等,但它一般有兩種使用情況:
- 情況1:類沒有覆寫 equals() 方法,則通過 equals() 比較該類的兩個物件時,等價于通過“==”比較這兩個物件,
- 情況2:類覆寫了 equals() 方法,一般,我們都覆寫 equals() 方法來兩個物件的內容相等;若它們的內容相等,則回傳 true (即,認為這兩個物件相等),
舉個例子:
public class test1 {
public static void main(String[] args) {
String a = new String("ab"); // a 為一個參考
String b = new String("ab"); // b為另一個參考,物件的內容一樣
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 從常量池中查找
if (aa == bb){ // true
System.out.println("aa==bb");
}
if (a == b){ // false,非同一物件
System.out.println("a==b");
}
if (a.equals(b)){ // true
System.out.println("aEQb");
}
if (42 == 42.0) { // true
System.out.println("true");
}
}
說明:
- String中的equals方法是被重寫過的,因為object的equals方法是比較的物件的記憶體地址,而String的equals方法比較的是物件的值,
- 當創建String型別的物件時,虛擬機會在常量池中查找有沒有已經存在的值和要創建的值相同的物件,如果有就把它賦給當前參考,如果沒有就在常量池中重新創建一個String物件,
2. hashCode 與 equals (重要)
- HashSet如何檢查重復
- 兩個物件的 hashCode() 相同,則 equals() 也一定為 true,對嗎?
- hashCode和equals方法的關系
- 面試官可能會問你:“你重寫過 hashcode 和 equals 么,為什么重寫equals時必須重寫hashCode方法?”
hashCode()介紹
-
hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是回傳一個int整數,這個哈希碼的作用是確定該物件在哈希表中的索引位置,hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode()函式,
-
散串列存盤的是鍵值對(key-value),它的特點是:能根據“鍵”快速的檢索出對應的“值”,這其中就利用到了散列碼!(可以快速找到所需要的物件)
為什么要有 hashCode
我們以“HashSet 如何檢查重復”為例子來說明為什么要有 hashCode:
- 當你把物件加入 HashSet 時,HashSet 會先計算物件的 hashcode 值來判斷物件加入的位置,同時也會與其他已經加入的物件的 hashcode 值作比較,如果沒有相符的hashcode,HashSet會假設物件沒有重復出現,但是如果發現有相同 hashcode 值的物件,這時會呼叫 equals()方法來檢查hashcode 相等的物件是否真的相同,如果兩者相同,HashSet 就不會讓其加入操作成功,如果不同的話,就會重新散列到其他位置,這樣我們就大大減少了 equals 的次數,相應就大大提高了執行速度,
hashCode()與equals()的相關規定
- 如果兩個物件相等,則hashcode一定也是相同的
- 兩個物件相等,對兩個物件分別呼叫equals方法都回傳true
- 兩個物件有相同的hashcode值,它們也不一定是相等的
因此,equals 方法被覆寫過,則 hashCode 方法也必須被覆寫
hashCode() 的默認行為是對堆上的物件產生獨特值,如果沒有重寫 hashCode(),則該 class 的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料)
3. 物件的相等與指向他們的參考相等,兩者有什么不同?
物件的相等 比的是記憶體中存放的內容是否相等而 參考相等 比較的是他們指向的記憶體地址是否相等,
4. 當一個物件被當作引數傳遞到一個方法后,此方法可改變這個物件的屬性,并可回傳變化后的結果,那么這里到底是值傳遞還是參考傳遞?
是值傳遞,Java 語言的方法呼叫只支持引數的值傳遞,當一個物件實體作為一個引數被傳遞到方法中時,引數的值就是對該物件的參考,物件的屬性可以在被呼叫程序中被改變,但對物件參考的改變是不會影響到呼叫者的
5. 為什么 Java 中只有值傳遞
-
首先回顧一下在程式設計語言中有關將引數傳遞給方法(或函式)的一些專業術語,按值呼叫(call by value)表示方法接收的是呼叫者提供的值,而按參考呼叫(call by reference)表示方法接收的是呼叫者提供的變數地址,一個方法可以修改傳遞參考所對應的變數值,而不能修改傳遞值呼叫所對應的變數值, 它用來描述各種程式設計語言(不只是Java)中方法引數傳遞方式,
-
Java程式設計語言總是采用按值呼叫,也就是說,方法得到的是所有引數值的一個拷貝,也就是說,方法不能修改傳遞給它的任何引數變數的內容,
下面通過 3 個例子來給大家說明
example 1
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
結果:
- a = 20 b = 10 num1 = 10 num2 = 20
決議:

- 在swap方法中,a、b的值進行交換,并不會影響到 num1、num2,因為,a、b中的值,只是從num1、num2 的復制過來的,也就是說,a、b相當于num1、num2 的副本,副本的內容無論怎么修改,都不會影響到原件本身,
通過上面例子,我們已經知道了一個方法不能修改一個基本資料型別的引數,而物件參考作為引數就不一樣,請看example 2
example 2
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 5 };
System.out.println(arr[0]);
change(arr);
System.out.println(arr[0]);
}
public static void change(int[] array) {
// 將陣列的第一個元素變為0
array[0] = 0;
}
結果:
- 1 0
決議:

- array 被初始化 arr 的拷貝也就是一個物件的參考,也就是說 array 和 arr 指向的時同一個陣列物件, 因此,外部對參考物件的改變會反映到所對應的物件上,
通過 example2 我們已經看到,實作一個改變物件引數狀態的方法并不是一件難事,理由很簡單,方法得到的是物件參考的拷貝,物件參考及其他的拷貝同時參考同一個物件,
- 很多程式設計語言(特別是,C++和Pascal)提供了兩種引數傳遞的方式:值呼叫和參考呼叫,有些程式員(甚至本書的作者)認為Java程式設計語言對物件采用的是參考呼叫,實際上,這種理解是不對的,由于這種誤解具有一定的普遍性,所以下面給出一個反例來詳細地闡述一下這個問題,
example 3
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student s1 = new Student("小張");
Student s2 = new Student("小李");
Test.swap(s1, s2);
System.out.println("s1:" + s1.getName());
System.out.println("s2:" + s2.getName());
}
public static void swap(Student x, Student y) {
Student temp = x;
x = y;
y = temp;
System.out.println("x:" + x.getName());
System.out.println("y:" + y.getName());
}
}
結果:
- x:小李 y:小張 s1:小張 s2:小李
決議:
- 交換之前:

- 交換之后

- 通過上面兩張圖可以很清晰的看出:
方法并沒有改變存盤在變數 s1 和 s2 中的物件參考,swap方法的引數x和y被初始化為兩個物件參考的拷貝,這個方法交換的是這兩個拷貝
總結:
Java程式設計語言對物件采用的不是參考呼叫,實際上,物件參考是按值傳遞的,
下面再總結一下Java中方法引數的使用情況:
- 一個方法不能修改一個基本資料型別的引數(即數值型或布爾型》
- 一個方法可以改變一個物件引數的狀態,
- 一個方法不能讓物件引數參考一個新的物件,
6. 值傳遞和參考傳遞有什么區別
- 值傳遞:指的是在方法呼叫時,傳遞的引數是按值的拷貝傳遞,傳遞的是值的拷貝,也就是說傳遞后就互不相關了,
- 參考傳遞:指的是在方法呼叫時,傳遞的引數是按參考進行傳遞,其實傳遞的參考的地址,也就是變數所對應的記憶體空間的地址,傳遞的是值的參考,也就是說傳遞前和傳遞后都指向同一個參考(也就是同一個記憶體空間),
Java包

1. JDK 中常用的包有哪些
- java.lang:這個是系統的基礎類;
- java.io:這里面是所有輸入輸出有關的類,比如檔案操作等;
- java.nio:為了完善 io 包中的功能,提高 io 包中性能而寫的一個新包;
- java.net:這里面是與網路有關的類;
- java.util:這個是系統輔助類,特別是集合類;
- java.sql:這個是資料庫操作的類,
2. import java和javax有什么區別
- 剛開始的時候 JavaAPI 所必需的包是 java 開頭的包,javax 當時只是擴展 API 包來說使用,然而隨著時間的推移,javax 逐漸的擴展成為 Java API 的組成部分,但是,將擴展從 javax 包移動到 java包將是太麻煩了,最侄訓破壞一堆現有的代碼,因此,最終決定 javax 包將成為標準API的一部分,
所以,實際上java和javax沒有區別,這都是一個名字,
IO流
IO流詳細面試題:整理了將近三萬字,超硬核BIO,NIO,AIO,Netty 超越 99% IO文章(面試題+綜合案例+練習題)
反射

1. 什么是反射機制?
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制,
靜態編譯和動態編譯
- 靜態編譯:在編譯時確定型別,系結物件
- 動態編譯:運行時確定型別,系結物件
2. 反射機制優缺點
- 優點: 運行期型別的判斷,動態加載類,提高代碼靈活度,
- 缺點: 性能瓶頸:反射相當于一系列解釋操作,通知 JVM 要做的事情,性能比直接的java代碼要慢很多,
3. 反射機制的應用場景有哪些?
反射是框架設計的靈魂,
- 在我們平時的專案開發程序中,基本上很少會直接使用到反射機制,但這不能說明反射機制沒有用,實際上有很多設計、開發都與反射機制有關,例如模塊化的開發,通過反射去呼叫對應的位元組碼;動態代理設計模式也采用了反射機制,還有我們日常使用的 Spring/Hibernate 等框架也大量使用到了反射機制,
舉例:
- 我們在使用JDBC連接資料庫時使用Class.forName()通過反射加載資料庫的驅動程式;
- Spring框架也用到很多反射機制,最經典的就是xml的配置模式,Spring 通過 XML 配置模式裝載 Bean 的程序:1) 將程式內所有 XML 或 Properties 組態檔加載入記憶體中; 2)Java類里面決議xml或properties里面的內容,得到對應物體類的位元組碼字串以及相關的屬性資訊; 3)使用反射機制,根據這個字串獲得某個類的Class實體; 4)動態配置實體的屬性
4. Java獲取反射的三種方法
1.通過new物件實作反射機制 2.通過路徑實作反射機制 3.通過類名實作反射機制
public class Student {
private int id;
String name;
protected boolean sex;
public float score;
}
public class Get {
//獲取反射機制三種方式
public static void main(String[] args) throws ClassNotFoundException {
//方式一(通過建立物件)
Student stu = new Student();
Class classobj1 = stu.getClass();
System.out.println(classobj1.getName());
//方式二(所在通過路徑-相對路徑)
Class classobj2 = Class.forName("fanshe.Student");
System.out.println(classobj2.getName());
//方式三(通過類名)
Class classobj3 = Student.class;
System.out.println(classobj3.getName());
}
}
常用API

String的常用API
1. 字符型常量和字串常量的區別
- 形式上: 字符常量是單引號引起的一個字符 字串常量是雙引號引起的若干個字符
- 含義上: 字符常量相當于一個整形值(ASCII值),可以參加運算式運算 字串常量代表一個地址值(該字串在記憶體中存放位置)
- 占記憶體大小 字符常量只占一個位元組 字串常量占若干個位元組(至少一個字符結束標志)
2. 什么是字串常量池?
字串常量池位于堆記憶體中,專門用來存盤字串常量,可以提高記憶體的使用率,避免開辟多塊空間存盤相同的字串,在創建字串時 JVM 會首先檢查字串常量池,如果該字串已經存在池中,則回傳它的參考,如果不存在,則實體化一個字串放到池中,并回傳其參考,
3. String 是最基本的資料型別嗎
不是,
- Java 中的基本資料型別只有 8 個 :byte、short、int、long、float、double、char、boolean;除了基本型別(primitive type),剩下的都是參考型別(referencetype),Java 5 以后引入的列舉型別也算是一種比較特殊的參考型別,
這是很基礎的東西,但是很多初學者卻容易忽視,Java 的 8 種基本資料型別中不包括 String,基本資料型別中用來描述文本>資料的是 char,但是它只能表示單個字符,比如 ‘a’,‘好’ 之類的,如果要描述一段文本,就需要用多個 char 型別的變數,也>就是一個 char 型別陣列,比如“你好” 就是長度為2的陣列 chars = {‘你’,‘好’};
但是使用陣列過于麻煩,所以就有了 String,String 底層就是一個 char 型別的陣列,只是使用的時候開發者不需要直接操作底層陣列,用更加簡便的方式即可完成對字串的使用,
4. String有哪些特性
- 不變性:String 是只讀字串,是一個典型的 immutable 物件,對它進行任何操作,其實都是創建一個新的物件,再把參考指向該物件,不變模式的主要作用在于當一個物件需要被多執行緒共享并頻繁訪問時,可以保證資料的一致性,
- 常量池優化:String 物件創建之后,會在字串常量池中進行快取,如果下次創建同樣的物件時,會直接回傳快取的參考,
- final:使用 final 來定義 String 類,表示 String 類不能被繼承,提高了系統的安全性,
5. String真的是不可變的嗎?
我覺得如果別人問這個問題的話,回答不可變就可以了,
下面只是給大家看兩個有代表性的例子:
1.String不可變但不代表參考不可以變
String str = "Hello";
str = str + " World";
System.out.println("str=" + str);
結果:
- str=Hello World
決議:
- 實際上,原來String的內容是不變的,只是str由原來指向"Hello"的記憶體地址轉為指向"HelloWorld"的記憶體地址而已,也就是說多開辟了一塊記憶體區域給"Hello World"字串,
2.通過反射是可以修改所謂的“不可變”物件
// 創建字串"Hello World", 并賦給參考s
String s = "Hello World";
System.out.println("s = " + s); // Hello World
// 獲取String類中的value欄位
Field valueFieldOfString = String.class.getDeclaredField("value");
// 改變value屬性的訪問權限
valueFieldOfString.setAccessible(true);
// 獲取s物件上的value屬性的值
char[] value = (char[]) valueFieldOfString.get(s);
// 改變value所參考的陣列中的第5個字符
value[5] = '_';
System.out.println("s = " + s); // Hello_World
結果:
- s = Hello World s = Hello_World
決議:
- 用反射可以訪問私有成員, 然后反射出String物件中的value屬性, 進而改變通過獲得的value參考改變陣列的結構,但是一般我們不會這么做,這里只是簡單提一下有這個東西,
6. 是否可以繼承 String 類
String 類是 final 類,不可以被繼承,
7. String str="i"與 String str=new String(“i”)一樣嗎?
不一樣,因為記憶體的分配方式不一樣,String str="i"的方式,java 虛擬機會將其分配到常量池中;而 String str=new String(“i”) 則會被分到堆記憶體中,
8. String s = new String(“xyz”);創建了幾個字串物件
兩個物件,一個是靜態區的"xyz",一個是用new創建在堆上的物件,
String str1 = "hello"; //str1指向靜態區
String str2 = new String("hello"); //str2指向堆上的物件
String str3 = "hello";
String str4 = new String("hello");
System.out.println(str1.equals(str2));//true
System.out.println(str2.equals(str4)); //true
System.out.println(str1 == str3); //true
System.out.println(str1 == str2); //false
System.out.println(str2 == str4); //false
System.out.println(str2 == "hello"); //false
str2 = str1;
System.out.println(str2 == "hello");//true
9. 如何將字串反轉?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法,
示例代碼:
StringBuffer reverse StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); // gfedcba
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder. reverse()); // gfedcba
10. 陣列有沒有 length()方法?String 有沒有 length()方法
- 陣列沒有 length()方法 ,有 length 的屬性,String 有 length()方法,JavaScript中,獲得字串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆,
11. String 類的常用方法都有那些?
- indexOf():回傳指定字符的索引,
- charAt():回傳指定索引處的字符,
- replace():字串替換,
- trim():去除字串兩端空白,
- split():分割字串,回傳一個分割后的字串陣列,
- getBytes():回傳字串的 byte 型別陣列,
- length():回傳字串長度,
- toLowerCase():將字串轉成小寫字母,
- toUpperCase():將字串轉成大寫字符,
- substring():截取字串,
- equals():字串比較,
12. 在使用 HashMap 的時候,用 String 做 key 有什么好處?
HashMap 內部實作是通過 key 的 hashcode 來確定 value 的存盤位置,因為字串是不可變的,所以當創建字串時,它的 hashcode 被快取下來,不需要再次計算,所以相比于其他物件更快,
13. String和StringBuffer、StringBuilder的區別是什么?String為什么是不可變的
可變性
- String類中使用字符陣列保存字串,private?final?char?value[],所以string物件是不可變的,StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符陣列保存字串,char[] value,這兩種物件都是可變的,
執行緒安全性
- String中的物件是不可變的,也就可以理解為常量,執行緒安全,AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字串的基本操作,如expandCapacity、append、insert、indexOf等公共方法,StringBuffer對方法加了同步鎖或者對呼叫的方法加了同步鎖,所以是執行緒安全的,StringBuilder并沒有對方法進行加同步鎖,所以是非執行緒安全的,
性能
- 每次對String 型別進行改變的時候,都會生成一個新的String物件,然后將指標指向新的String 物件,StringBuffer每次都會對StringBuffer物件本身進行操作,而不是生成新的物件并改變物件參考,相同情況下使用StirngBuilder 相比使用StringBuffer 僅能獲得10%~15% 左右的性能提升,但卻要冒多執行緒不安全的風險,
對于三者使用的總結
- 如果要操作少量的資料用 = String
- 單執行緒操作字串緩沖區 下操作大量資料 = StringBuilder
- 多執行緒操作字串緩沖區 下操作大量資料 = StringBuffer
了解Steing 類的常用方法:String類的常用方法總結,Cs挽周帶你玩轉String類(圖文總結超詳細) !
包裝類相關

1. 自動裝箱與拆箱
- 裝箱:將基本型別用它們對應的參考型別包裝起來;
- 拆箱:將包裝型別轉換為基本資料型別;
2. int 和 Integer 有什么區別
Java 是一個近乎純潔的面向物件編程語言,但是為了編程的方便還是引入了基本資料型別,但是為了能夠將這些基本資料型別當成物件操作,Java 為每一個基本資料型別都引入了對應的包裝型別(wrapper class),int 的包裝類就是 Integer,從 Java 5 開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換,
Java 為每個原始型別提供了包裝型別:
- 原始型別: boolean,char,byte,short,int,long,float,double
- 包裝型別:Boolean,Character,Byte,Short,Integer,Long,Float,Double
3. Integer a= 127 與 Integer b = 127相等嗎
- 對于物件參考型別:==比較的是物件的記憶體地址,
- 對于基本資料型別:==比較的是值,
- 如果整型字面量的值在-128到127之間,那么自動裝箱時不會new新的Integer物件,而是直接參考常量池中的Integer物件,超過范圍 a1==b1的結果是false
整合不易! 一鍵三連就是對博主最大的支持!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/290867.html
標籤:java
