一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - 面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

2021-08-31 01:09碼哥字節(jié) Java教程

從面試題作為切入點(diǎn)提升大家的 Java 內(nèi)功,所謂根基不牢,地動(dòng)山搖。只有扎實(shí)的基礎(chǔ),才是寫(xiě)出寫(xiě)好代碼。跟著「碼哥」一起來(lái)提綱挈領(lǐng),梳理一個(gè)相對(duì)完整的 Java 開(kāi)發(fā)技術(shù)能力圖譜,將基礎(chǔ)夯實(shí)。

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

從面試題作為切入點(diǎn)提升大家的 Java 內(nèi)功,所謂根基不牢,地動(dòng)山搖。只有扎實(shí)的基礎(chǔ),才是寫(xiě)出寫(xiě)好代碼。

拒絕知識(shí)碎片化

碼哥在 《Redis 系列》的開(kāi)篇 Redis 為什么這么快中說(shuō)過(guò):學(xué)習(xí)一個(gè)技術(shù),通常只接觸了零散的技術(shù)點(diǎn),沒(méi)有在腦海里建立一個(gè)完整的知識(shí)框架和架構(gòu)體系,沒(méi)有系統(tǒng)觀。這樣會(huì)很吃力,而且會(huì)出現(xiàn)一看好像自己會(huì),過(guò)后就忘記,一臉懵逼。

我們需要一個(gè)系統(tǒng)觀,清晰完整的去學(xué)習(xí)技術(shù),同時(shí)也不能埋頭苦干,過(guò)于死磕某個(gè)細(xì)節(jié)。

跟著「碼哥」一起來(lái)提綱挈領(lǐng),梳理一個(gè)相對(duì)完整的 Java 開(kāi)發(fā)技術(shù)能力圖譜,將基礎(chǔ)夯實(shí)。

萬(wàn)字總結(jié),建議收藏。面試不慌,加薪有望。

Java 平臺(tái)的理解

碼老濕,你是怎么理解 Java 平臺(tái)呢?

Java 是一種面向?qū)ο蟮恼Z(yǔ)言,有兩個(gè)明顯特性:

跨平臺(tái)能力:一次編寫(xiě),到處運(yùn)行(Write once,run anywhere);

垃圾收集:

Java 通過(guò)字節(jié)碼和 Java 虛擬機(jī)(JVM)這種跨平臺(tái)的抽象,屏蔽了操作系統(tǒng)和硬件的細(xì)節(jié),這也是實(shí)現(xiàn)「一次編譯,到處執(zhí)行」的基礎(chǔ)。

Java 通過(guò)垃圾收集器(Garbage Collector)回收分配內(nèi)存,大部分情況下,程序員不需要自己操心內(nèi)存的分配和回收。

最常見(jiàn)的垃圾收集器,如 SerialGC、Parallel GC、 CMS、 G1 等,對(duì)于適用于什么樣的工作負(fù)載最好也心里有數(shù)。

JVM、JRE、JDK 關(guān)系

碼老濕,能說(shuō)下 JVM、JRE 和 JDK 的關(guān)系么?

JVM Java Virtual Machine 是 Java 虛擬機(jī),Java 程序需要運(yùn)行在虛擬機(jī)上,不同的平臺(tái)有自己的虛擬機(jī),因此 Java 語(yǔ)言可以實(shí)現(xiàn)跨平臺(tái)。

JRE Java Runtime Environment包括 Java 虛擬機(jī)和 Java 程序所需的核心類庫(kù)等。

核心類庫(kù)主要是 java.lang 包:包含了運(yùn)行 Java 程序必不可少的系統(tǒng)類,如基本數(shù)據(jù)類型、基本數(shù)學(xué)函數(shù)、字符串處理、線程、異常處理類等,系統(tǒng)缺省加載這個(gè)包

如果想要運(yùn)行一個(gè)開(kāi)發(fā)好的 Java 程序,計(jì)算機(jī)中只需要安裝 JRE 即可。

JDK Java Development Kit是提供給 Java 開(kāi)發(fā)人員使用的,其中包含了 Java 的開(kāi)發(fā)工具,也包括了 JRE。

所以安裝了 JDK,就無(wú)需再單獨(dú)安裝 JRE 了。其中的開(kāi)發(fā)工具:編譯工具(javac.exe),打包工具(jar.exe) 等。

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

Java 是解釋執(zhí)行么?

碼老濕,Java 是解釋執(zhí)行的么?

這個(gè)說(shuō)法不太準(zhǔn)確。

我們開(kāi)發(fā)的 Java 的源代碼,首先通過(guò) Javac 編譯成為字節(jié)碼(bytecode),在運(yùn)行時(shí),通過(guò) Java 虛擬機(jī)(JVM)內(nèi)嵌的解釋器將字節(jié)碼轉(zhuǎn)換成為最終的機(jī)器碼。

但是常見(jiàn)的 JVM,比如我們大多數(shù)情況使用的 Oracle JDK 提供的 Hotspot JVM,都提供了 JIT(Just-In-Time)編譯器。

也就是通常說(shuō)的動(dòng)態(tài)編譯器,JIT 能夠在運(yùn)行時(shí)將熱點(diǎn)代碼編譯成機(jī)器碼,這種情況下部分熱點(diǎn)代碼就屬于編譯執(zhí)行,而不是解釋執(zhí)行了。

采用字節(jié)碼的好處

什么是字節(jié)碼?采用字節(jié)碼的好處是什么?

字節(jié)碼:Java 源代碼經(jīng)過(guò)虛擬機(jī)編譯器編譯后產(chǎn)生的文件(即擴(kuò)展為.class 的文件),它不面向任何特定的處理器,只面向虛擬機(jī)。

采用字節(jié)碼的好處:

眾所周知,我們通常把 Java 分為編譯期和運(yùn)行時(shí)。這里說(shuō)的 Java 的編譯和 C/C++ 是有著不同的意義的,Javac 的編譯,編譯 Java 源碼生成“.class”文件里面實(shí)際是字節(jié)碼,而不是可以直接執(zhí)行的機(jī)器碼。Java 通過(guò)字節(jié)碼和 Java 虛擬機(jī)(JVM)這種跨平臺(tái)的抽象,屏蔽了操作系統(tǒng)和硬件的細(xì)節(jié),這也是實(shí)現(xiàn)“一次編譯,到處執(zhí)行”的基礎(chǔ)。

基礎(chǔ)語(yǔ)法

JDK 1.8 之后有哪些新特性

接口默認(rèn)方法:Java8 允許我們給接口添加一個(gè)非抽象的方法實(shí)現(xiàn),只需要使用 default 關(guān)鍵字即可。

Lambda 表達(dá)式和函數(shù)式接口:Lambda 表達(dá)式本質(zhì)上是一段匿名內(nèi)部類,也可以是一段可以傳遞的代碼。

Lambda 允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞到方法中),使用 Lambda 表達(dá)式使代碼更加簡(jiǎn)潔,但是也不要濫用,否則會(huì)有可讀性等問(wèn)題,《EffectiveJava》作者 JoshBloch 建議使用 Lambda 表達(dá)式最好不要超過(guò) 3 行。

StreamAPI:用函數(shù)式編程方式在集合類上進(jìn)行復(fù)雜操作的工具,配合 Lambda 表達(dá)式可以方便的對(duì)集合進(jìn)行處理。

Java8 中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作。

使用 StreamAPI 對(duì)集合數(shù)據(jù)進(jìn)行操作,就類似于使用 SQL 執(zhí)行的數(shù)據(jù)庫(kù)查詢。也可以使用 StreamAPI 來(lái)并行執(zhí)行操作。

簡(jiǎn)而言之,StreamAPI 提供了一種高效且易于使用的處理數(shù)據(jù)的方式。

方法引用:方法引用提供了非常有用的語(yǔ)法,可以直接引用已有 Java 類或?qū)ο?實(shí)例)的方法或構(gòu)造器。

與 lambda 聯(lián)合使用,方法引用可以使語(yǔ)言的構(gòu)造更緊湊簡(jiǎn)潔,減少冗余代碼。

日期時(shí)間 API:Java8 引入了新的日期時(shí)間 API 改進(jìn)了日期時(shí)間的管理。

Optional 類:著名的 NullPointerException 是引起系統(tǒng)失敗最常見(jiàn)的原因。

很久以前 GoogleGuava 項(xiàng)目引入了 Optional 作為解決空指針異常的一種方式,不贊成代碼被 null 檢查的代碼污染,期望程序員寫(xiě)整潔的代碼。

受 GoogleGuava 的鼓勵(lì),Optional 現(xiàn)在是 Java8 庫(kù)的一部分。

新工具:新的編譯工具,如:Nashorn 引擎 jjs、類依賴分析器 jdeps。

構(gòu)造器是否可以重寫(xiě)

Constructor 不能被 override(重寫(xiě)),但是可以 overload(重載),所以你可以看到?個(gè)類中有多個(gè)構(gòu)造函數(shù)的情況。

wait() 和 sleep 區(qū)別

來(lái)源不同:sleep()來(lái)自 Thread 類,wait()來(lái)自 Object 類。

對(duì)于同步鎖的影響不同:sleep()不會(huì)該表同步鎖的行為,如果當(dāng)前線程持有同步鎖,那么 sleep 是不會(huì)讓線程釋放同步鎖的。

wait()會(huì)釋放同步鎖,讓其他線程進(jìn)入 synchronized 代碼塊執(zhí)行。

使用范圍不同:sleep()可以在任何地方使用。wait()只能在同步控制方法或者同步控制塊里面使用,否則會(huì)拋 IllegalMonitorStateException。

恢復(fù)方式不同:兩者會(huì)暫停當(dāng)前線程,但是在恢復(fù)上不太一樣。sleep()在時(shí)間到了之后會(huì)重新恢復(fù);

wait()則需要其他線程調(diào)用同一對(duì)象的 notify()/nofityAll()才能重新恢復(fù)。

&和&&的區(qū)別

&運(yùn)算符有兩種用法:

  1. 按位與;
  2. 邏輯與。

&&運(yùn)算符是短路與運(yùn)算。邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運(yùn)算符左右兩端的布爾值都是 true 整個(gè)表達(dá)式的值才是 true。

&&之所以稱為短路運(yùn)算,是因?yàn)槿绻?amp;&左邊的表達(dá)式的值是 false,右邊的表達(dá)式會(huì)被直接短路掉,不會(huì)進(jìn)行運(yùn)算。

注意:邏輯或運(yùn)算符(|)和短路或運(yùn)算符(||)的差別也是如此。

Java 有哪些數(shù)據(jù)類型?

Java 語(yǔ)言是強(qiáng)類型語(yǔ)言,對(duì)于每一種數(shù)據(jù)都定義了明確的具體的數(shù)據(jù)類型,在內(nèi)存中分配了不同大小的內(nèi)存空間。

分類

基本數(shù)據(jù)類型

  • 整數(shù)類型(byte,short,int,long)
  • 浮點(diǎn)類型(float,double)
  • 數(shù)值型
  • 字符型(char)
  • 布爾型(boolean)

引用數(shù)據(jù)類型

  • 類(class)
  • 接口(interface)
  • 數(shù)組([])

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

this 關(guān)鍵字的用法

this 是自身的一個(gè)對(duì)象,代表對(duì)象本身,可以理解為:指向?qū)ο蟊旧淼囊粋€(gè)指針。

this 的用法在 java 中大體可以分為 3 種:

  1. 普通的直接引用,this 相當(dāng)于是指向當(dāng)前對(duì)象本身。
  2. 形參與成員名字重名,用 this 來(lái)區(qū)分:
  1. public Person(String nameint age) { 
  2.     this.name = name
  3.     this.age = age; 

引用本類的構(gòu)造函數(shù)

  1. class Person{ 
  2.     private String name
  3.     private int age; 
  4.  
  5.     public Person() { 
  6.     } 
  7.  
  8.     public Person(String name) { 
  9.         this.name = name
  10.     } 
  11.     public Person(String nameint age) { 
  12.         this(name); 
  13.         this.age = age; 
  14.     } 

super 關(guān)鍵字的用法

super 可以理解為是指向自己超(父)類對(duì)象的一個(gè)指針,而這個(gè)超類指的是離自己最近的一個(gè)父類。

super 也有三種用法:

1.普通的直接引用:與 this 類似,super 相當(dāng)于是指向當(dāng)前對(duì)象的父類的引用,這樣就可以用 super.xxx 來(lái)引用父類的成員。

2.子類中的成員變量或方法與父類中的成員變量或方法同名時(shí),用 super 進(jìn)行區(qū)分

  1. class Person{ 
  2.     protected String name
  3.  
  4.     public Person(String name) { 
  5.         this.name = name
  6.     } 
  7.  
  8.  
  9. class Student extends Person{ 
  10.     private String name
  11.  
  12.     public Student(String name, String name1) { 
  13.         super(name); 
  14.         this.name = name1; 
  15.     } 
  16.  
  17.     public void getInfo(){ 
  18.         System.out.println(this.name);      //Child 
  19.         System.out.println(super.name);     //Father 
  20.     } 
  21.  
  22.  
  23. public class Test { 
  24.     public static void main(String[] args) { 
  25.        Student s1 = new Student("Father","Child"); 
  26.        s1.getInfo(); 
  27.  
  28.     } 

3.引用父類構(gòu)造函數(shù);

成員變量與局部變量的區(qū)別有哪些變量:在程序執(zhí)行的過(guò)程中,在某個(gè)范圍內(nèi)其值可以發(fā)生改變的量。從本質(zhì)上講,變量其實(shí)是內(nèi)存中的一小塊區(qū)域。

成員變量:方法外部,類內(nèi)部定義的變量。

局部變量:類的方法中的變量。

區(qū)別如下:

作用域

成員變量:針對(duì)整個(gè)類有效。局部變量:只在某個(gè)范圍內(nèi)有效。(一般指的就是方法,語(yǔ)句體內(nèi))

存儲(chǔ)位置

成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失,存儲(chǔ)在堆內(nèi)存中。

局部變量:在方法被調(diào)用,或者語(yǔ)句被執(zhí)行的時(shí)候存在,存儲(chǔ)在棧內(nèi)存中。當(dāng)方法調(diào)用完,或者語(yǔ)句結(jié)束后,就自動(dòng)釋放。

生命周期

成員變量:隨著對(duì)象的創(chuàng)建而存在,隨著對(duì)象的消失而消失 局部變量:當(dāng)方法調(diào)用完,或者語(yǔ)句結(jié)束后,就自動(dòng)釋放。

初始值

成員變量:有默認(rèn)初始值。

局部變量:沒(méi)有默認(rèn)初始值,使用前必須賦值。

動(dòng)態(tài)代理是基于什么原理

基于反射實(shí)現(xiàn)

反射機(jī)制是 Java 語(yǔ)言提供的一種基礎(chǔ)功能,賦予程序在運(yùn)行時(shí)自省(introspect,官方用語(yǔ))的能力。通過(guò)反射我們可以直接操作類或者對(duì)象,比如獲取某個(gè)對(duì)象的類定義,獲取類聲明的屬性和方法,調(diào)用方法或者構(gòu)造對(duì)象,甚至可以運(yùn)行時(shí)修改類定義。

碼老濕,他的使用場(chǎng)景是什么?

AOP 通過(guò)(動(dòng)態(tài))代理機(jī)制可以讓開(kāi)發(fā)者從這些繁瑣事項(xiàng)中抽身出來(lái),大幅度提高了代碼的抽象程度和復(fù)用度。

包裝 RPC 調(diào)用:通過(guò)代理可以讓調(diào)用者與實(shí)現(xiàn)者之間解耦。比如進(jìn)行 RPC 調(diào)用,框架內(nèi)部的尋址、序列化、反序列化等,對(duì)于調(diào)用者往往是沒(méi)有太大意義的,通過(guò)代理,可以提供更加友善的界面。

int 與 Integer 區(qū)別

Java 是一個(gè)近乎純潔的面向?qū)ο缶幊陶Z(yǔ)言,但是為了編程的方便還是引入了基本數(shù)據(jù)類型,但是為了能夠?qū)⑦@些基本數(shù)據(jù)類型當(dāng)成對(duì)象操作,Java 為每一個(gè)基本數(shù)據(jù)類型都引入了對(duì)應(yīng)的包裝類型(wrapper class),int 的包裝類就是 Integer,從 Java 5 開(kāi)始引入了自動(dòng)裝箱/拆箱機(jī)制,使得二者可以相互轉(zhuǎn)換。

Java 為每個(gè)原始類型提供了包裝類型:

  • 原始類型: boolean,char,byte,short,int,long,float,double。
  • 包裝類型:Boolean,Character,Byte,Short,Integer,Long,F(xiàn)loat,Double。

int 是我們常說(shuō)的整形數(shù)字,是 Java 的 8 個(gè)原始數(shù)據(jù)類型(Primitive Types,boolean、byte 、short、char、int、float、double、long)之一。Java 語(yǔ)言雖然號(hào)稱一切都是對(duì)象,但原始數(shù)據(jù)類型是例外。

Integer 是 int 對(duì)應(yīng)的包裝類,它有一個(gè) int 類型的字段存儲(chǔ)數(shù)據(jù),并且提供了基本操作,比如數(shù)學(xué)運(yùn)算、int 和字符串之間轉(zhuǎn)換等。在 Java 5 中,引入了自動(dòng)裝箱和自動(dòng)拆箱功能(boxing/unboxing),Java 可以根據(jù)上下文,自動(dòng)進(jìn)行轉(zhuǎn)換,極大地簡(jiǎn)化了相關(guān)編程。

Integer a= 127 與 Integer b = 127 相等嗎

對(duì)于對(duì)象引用類型:==比較的是對(duì)象的內(nèi)存地址。對(duì)于基本數(shù)據(jù)類型:==比較的是值。

大部分?jǐn)?shù)據(jù)操作都是集中在有限的、較小的數(shù)值范圍,因而,在 Java 5 中新增了靜態(tài)工廠方法 valueOf,在調(diào)用它的時(shí)候會(huì)利用一個(gè)緩存機(jī)制,帶來(lái)了明顯的性能改進(jìn)。按照 Javadoc,這個(gè)值默認(rèn)緩存是 -128 到 127 之間。

如果整型字面量的值在-128 到 127 之間,那么自動(dòng)裝箱時(shí)不會(huì) new 新的 Integer 對(duì)象,而是直接引用常量池中的 Integer 對(duì)象,超過(guò)范圍 a1==b1 的結(jié)果是 false。

  1. public static void main(String[] args) { 
  2.     Integer a = new Integer(3); 
  3.     Integer b = 3;  // 將3自動(dòng)裝箱成Integer類型 
  4.     int c = 3; 
  5.     System.out.println(a == b); // false 兩個(gè)引用沒(méi)有引用同一對(duì)象 
  6.     System.out.println(a == c); // true a自動(dòng)拆箱成int類型再和c比較 
  7.     System.out.println(b == c); // true 
  8.  
  9.     Integer a1 = 128; 
  10.     Integer b1 = 128; 
  11.     System.out.println(a1 == b1); // false 
  12.  
  13.     Integer a2 = 127; 
  14.     Integer b2 = 127; 
  15.     System.out.println(a2 == b2); // true 

面向?qū)ο?/h3>

面向?qū)ο笈c面向過(guò)程的區(qū)別是什么?

面向過(guò)程

優(yōu)點(diǎn):性能比面向?qū)ο蟾撸驗(yàn)轭愓{(diào)用時(shí)需要實(shí)例化,開(kāi)銷比較大,比較消耗資源;比如單片機(jī)、嵌入式開(kāi)發(fā)、Linux/Unix 等一般采用面向過(guò)程開(kāi)發(fā),性能是最重要的因素。

缺點(diǎn):沒(méi)有面向?qū)ο笠拙S護(hù)、易復(fù)用、易擴(kuò)展

面向?qū)ο?/h3>

優(yōu)點(diǎn):易維護(hù)、易復(fù)用、易擴(kuò)展,由于面向?qū)ο笥蟹庋b、繼承、多態(tài)性的特性,可以設(shè)計(jì)出低耦合的系統(tǒng),使系統(tǒng)更加靈活、更加易于維護(hù)

缺點(diǎn):性能比面向過(guò)程低

面向過(guò)程是具體化的,流程化的,解決一個(gè)問(wèn)題,你需要一步一步的分析,一步一步的實(shí)現(xiàn)。

面向?qū)ο笫悄P突模阒恍璩橄蟪鲆粋€(gè)類,這是一個(gè)封閉的盒子,在這里你擁有數(shù)據(jù)也擁有解決問(wèn)題的方法。需要什么功能直接使用就可以了,不必去一步一步的實(shí)現(xiàn),至于這個(gè)功能是如何實(shí)現(xiàn)的,管我們什么事?我們會(huì)用就可以了。

面向?qū)ο蟮牡讓悠鋵?shí)還是面向過(guò)程,把面向過(guò)程抽象成類,然后封裝,方便我們使用的就是面向?qū)ο罅恕?/p>

面向?qū)ο缶幊桃驗(yàn)槠渚哂胸S富的特性(封裝、抽象、繼承、多態(tài)),可以實(shí)現(xiàn)很多復(fù)雜的設(shè)計(jì)思路,是很多設(shè)計(jì)原則、設(shè)計(jì)模式等編碼實(shí)現(xiàn)的基礎(chǔ)。

面向?qū)ο笏拇筇匦?/h3>

碼老濕,如何理解面向?qū)ο蟮乃拇筇匦?

抽象

抽象是將一類對(duì)象的共同特征總結(jié)出來(lái)構(gòu)造類的過(guò)程,包括數(shù)據(jù)抽象和行為抽象兩方面。抽象只關(guān)注對(duì)象有哪些屬性和行為,并不關(guān)注這些行為的細(xì)節(jié)是什么。

另外,抽象是一個(gè)寬泛的設(shè)計(jì)思想,開(kāi)發(fā)者能不能設(shè)計(jì)好代碼,抽象能力也至關(guān)重要。

很多設(shè)計(jì)原則都體現(xiàn)了抽象這種設(shè)計(jì)思想,比如基于接口而非實(shí)現(xiàn)編程、開(kāi)閉原則(對(duì)擴(kuò)展開(kāi)放、對(duì)修改關(guān)閉)、代碼解耦(降低代碼的耦合性)等。

在面對(duì)復(fù)雜系統(tǒng)的時(shí)候,人腦能承受的信息復(fù)雜程度是有限的,所以我們必須忽略掉一些非關(guān)鍵性的實(shí)現(xiàn)細(xì)節(jié)。

封裝

把一個(gè)對(duì)象的屬性私有化,同時(shí)提供一些可以被外界訪問(wèn)的屬性的方法,如果屬性不想被外界訪問(wèn),我們大可不必提供方法給外界訪問(wèn)。

通過(guò)封裝,只需要暴露必要的方法給調(diào)用者,調(diào)用者不必了解背后的業(yè)務(wù)細(xì)節(jié),用錯(cuò)的概率就減少。

繼承

使用已存在的類的定義作為基礎(chǔ)建立新類的技術(shù),新類的定義可以增加新的數(shù)據(jù)或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。

通過(guò)使用繼承我們能夠非常方便地復(fù)用以前的代碼,需要注意的是,過(guò)度使用繼承,層級(jí)深就會(huì)導(dǎo)致代碼可讀性和可維護(hù)性變差。

關(guān)于繼承如下 3 點(diǎn)請(qǐng)記住:

  1. 子類擁有父類非 private 的屬性和方法。
  2. 子類可以擁有自己屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展。
  3. 子類可以用自己的方式實(shí)現(xiàn)父類的方法。(以后介紹)。

多態(tài)

所謂多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定。

即一個(gè)引用變量到底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。

在 Java 中有兩種形式可以實(shí)現(xiàn)多態(tài):繼承(多個(gè)子類對(duì)同一方法的重寫(xiě))和接口(實(shí)現(xiàn)接口并覆蓋接口中同一方法)。

多態(tài)也是很多設(shè)計(jì)模式、設(shè)計(jì)原則、編程技巧的代碼實(shí)現(xiàn)基礎(chǔ),比如策略模式、基于接口而非實(shí)現(xiàn)編程、依賴倒置原則、里式替換原則、利用多態(tài)去掉冗長(zhǎng)的 if-else 語(yǔ)句等等。

什么是多態(tài)機(jī)制?

所謂多態(tài)就是指程序中定義的引用變量所指向的具體類型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。

因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類,這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類實(shí)現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變,即不修改程序代碼就可以改變程序運(yùn)行時(shí)所綁定的具體代碼,讓程序可以選擇多個(gè)運(yùn)行狀態(tài),這就是多態(tài)性。

多態(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)。

其中編輯時(shí)多態(tài)是靜態(tài)的,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來(lái)區(qū)分不同的函數(shù),通過(guò)編輯之后會(huì)變成兩個(gè)不同的函數(shù),在運(yùn)行時(shí)談不上多態(tài)。

而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的,它是通過(guò)動(dòng)態(tài)綁定來(lái)實(shí)現(xiàn)的,也就是我們所說(shuō)的多態(tài)性。

Java 語(yǔ)言是如何實(shí)現(xiàn)多態(tài)的?

Java 實(shí)現(xiàn)多態(tài)有三個(gè)必要條件:繼承、重寫(xiě)、向上轉(zhuǎn)型。

繼承:在多態(tài)中必須存在有繼承關(guān)系的子類和父類。

重寫(xiě):子類對(duì)父類中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類的方法。

向上轉(zhuǎn)型:在多態(tài)中需要將子類的引用賦給父類對(duì)象,只有這樣該引用才能夠具備技能調(diào)用父類的方法和子類的方法。

只有滿足了上述三個(gè)條件,我們才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn)代碼處理不同的對(duì)象,從而達(dá)到執(zhí)行不同的行為。

重載與重寫(xiě)

方法的重載和重寫(xiě)都是實(shí)現(xiàn)多態(tài)的方式,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性。

重載:發(fā)生在同一個(gè)類中,方法名相同參數(shù)列表不同(參數(shù)類型不同、個(gè)數(shù)不同、順序不同),與方法返回值和訪問(wèn)修飾符無(wú)關(guān),即重載的方法不能根據(jù)返回類型進(jìn)行區(qū)分。

重寫(xiě):發(fā)生在父子類中,方法名、參數(shù)列表必須相同,返回值小于等于父類,拋出的異常小于等于父類,訪問(wèn)修飾符大于等于父類(里氏代換原則);如果父類方法訪問(wèn)修飾符為 private 則子類中就不是重寫(xiě)。

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

== : 它的作用是判斷兩個(gè)對(duì)象的地址是不是相等。即,判斷兩個(gè)對(duì)象是不是同一個(gè)對(duì)象。(基本數(shù)據(jù)類型 == 比較的是值,引用數(shù)據(jù)類型 == 比較的是內(nèi)存地址)。

equals() : 它的作用也是判斷兩個(gè)對(duì)象是否相等。但它一般有兩種使用情況:

類沒(méi)有覆蓋 equals() 方法。則通過(guò) equals() 比較該類的兩個(gè)對(duì)象時(shí),等價(jià)于通過(guò)“==”比較這兩個(gè)對(duì)象。

類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來(lái)兩個(gè)對(duì)象的內(nèi)容相等;若它們的內(nèi)容相等,則返回 true (即,認(rèn)為這兩個(gè)對(duì)象相等)。

為什么重寫(xiě) equals 時(shí)必須重寫(xiě) hashCode 方法?

如果兩個(gè)對(duì)象相等,則 hashcode 一定也是相同的

兩個(gè)對(duì)象相等,對(duì)兩個(gè)對(duì)象分別調(diào)用 equals 方法都返回 true

兩個(gè)對(duì)象有相同的 hashcode 值,它們也不一定是相等的.

因此,equals 方法被覆蓋過(guò),則 hashCode 方法也必須被覆蓋

為什么要有 hashcode

我們以“HashSet 如何檢查重復(fù)”為例子來(lái)說(shuō)明為什么要有 hashCode:

當(dāng)你把對(duì)象加入 HashSet 時(shí),HashSet 會(huì)先計(jì)算對(duì)象的 hashcode 值來(lái)判斷對(duì)象加入的位置,同時(shí)也會(huì)與其他已經(jīng)加入的對(duì)象的 hashcode 值作比較,如果沒(méi)有相符的 hashcode,HashSet 會(huì)假設(shè)對(duì)象沒(méi)有重復(fù)出現(xiàn)。

但是如果發(fā)現(xiàn)有相同 hashcode 值的對(duì)象,這時(shí)會(huì)調(diào)用 equals()方法來(lái)檢查 hashcode 相等的對(duì)象是否真的相同。

如果兩者相同,HashSet 就不會(huì)讓其加入操作成功。

如果不同的話,就會(huì)重新散列到其他位置。這樣我們就大大減少了 equals 的次數(shù),相應(yīng)就大大提高了執(zhí)行速度。

面向?qū)ο蟮幕驹瓌t

碼老濕,什么是 SOLID?

這是面向?qū)ο缶幊痰囊环N設(shè)計(jì)原則,對(duì)于每一種設(shè)計(jì)原則,我們需要掌握它的設(shè)計(jì)初衷,能解決哪些編程問(wèn)題,有哪些應(yīng)用場(chǎng)景。

  • 單一職責(zé)原則 SRP(Single Responsibility Principle) 類的功能要單一,不能包羅萬(wàn)象,跟雜貨鋪似的。
  • 開(kāi)放封閉原則 OCP(Open-Close Principle) 一個(gè)模塊對(duì)于拓展是開(kāi)放的,對(duì)于修改是封閉的,想要增加功能熱烈歡迎,想要修改,哼,一萬(wàn)個(gè)不樂(lè)意。
  • 里式替換原則 LSP(the Liskov Substitution Principle LSP) 子類可以替換父類出現(xiàn)在父類能夠出現(xiàn)的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~(其實(shí)多態(tài)就是一種這個(gè)原則的一種實(shí)現(xiàn))。
  • 接口分離原則 ISP(the Interface Segregation Principle ISP) 設(shè)計(jì)時(shí)采用多個(gè)與特定客戶類有關(guān)的接口比采用一個(gè)通用的接口要好。就比如一個(gè)手機(jī)擁有打電話,看視頻,玩游戲等功能,把這幾個(gè)功能拆分成不同的接口,比在一個(gè)接口里要好的多。
  • 依賴倒置原則 DIP(the Dependency Inversion Principle DIP) :高層模塊(high-level modules)不要依賴低層模塊(low-level)。高層模塊和低層模塊應(yīng)該通過(guò)抽象(abstractions)來(lái)互相依賴。除此之外,抽象(abstractions)不要依賴具體實(shí)現(xiàn)細(xì)節(jié)(details),具體實(shí)現(xiàn)細(xì)節(jié)(details)依賴抽象(abstractions)。
  • 抽象不應(yīng)該依賴于具體實(shí)現(xiàn),具體實(shí)現(xiàn)應(yīng)該依賴于抽象。就是你出國(guó)要說(shuō)你是中國(guó)人,而不能說(shuō)你是哪個(gè)村子的。
  • 比如說(shuō)中國(guó)人是抽象的,下面有具體的 xx 省,xx 市,xx 縣。你要依賴的抽象是中國(guó)人,而不是你是 xx 村的。
  • 所謂高層模塊和低層模塊的劃分,簡(jiǎn)單來(lái)說(shuō)就是,在調(diào)用鏈上,調(diào)用者屬于高層,被調(diào)用者屬于低層。
  • Tomcat 就是高層模塊,我們編寫(xiě)的 Web 應(yīng)用程序代碼就是低層模塊。Tomcat 和應(yīng)用程序代碼之間并沒(méi)有直接的依賴關(guān)系,兩者都依賴同一個(gè)「抽象」,也就是 Servlet 規(guī)范。
  • Servlet 規(guī)范不依賴具體的 Tomcat 容器和應(yīng)用程序的實(shí)現(xiàn)細(xì)節(jié),而 Tomcat 容器和應(yīng)用程序依賴 Servlet 規(guī)范。

碼老濕,接口隔離與單一職責(zé)有什么區(qū)別?

單一職責(zé)側(cè)重點(diǎn)是模塊、類、接口的設(shè)計(jì)思想。

接口隔離原則側(cè)重于接口設(shè)計(jì),提供了一種判斷接口職責(zé)是否單一的標(biāo)準(zhǔn)。

Exception 與 Error 區(qū)別?

碼老濕,他們的相同點(diǎn)是什么呀?

Exception 和 Error 都是繼承了 Throwable 類,在 Java 中只有 Throwable 類型的實(shí)例才可以被拋出(throw)或者捕獲(catch),它是異常處理機(jī)制的基本組成類型。

Exception 和 Error 體現(xiàn)了 Java 平臺(tái)設(shè)計(jì)者對(duì)不同異常情況的分類。

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

異常使用規(guī)范:

  • 盡量不要捕獲類似 Exception 這樣的通用異常,而是應(yīng)該捕獲特定異常
  • 不要生吞(swallow)異常。這是異常處理中要特別注意的事情,因?yàn)楹芸赡軙?huì)導(dǎo)致非常難以診斷的詭異情況。

Exception

Exception是程序正常運(yùn)行中,可以預(yù)料的意外情況,可能并且應(yīng)該被捕獲,進(jìn)行相應(yīng)處理。

就好比開(kāi)車去洗桑拿,前方道路施工,禁止通行。但是我們換條路就可以解決。

Exception 又分為可檢查(checked)異常和不檢查(unchecked)異常,可檢查異常在源代碼里必須顯式地進(jìn)行捕獲處理,這是編譯期檢查的一部分。

不檢查異常就是所謂的運(yùn)行時(shí)異常,類似 NullPointerException、ArrayIndexOutOfBoundsException 之類,通常是可以編碼避免的邏輯錯(cuò)誤,具體根據(jù)需要來(lái)判斷是否需要捕獲,并不會(huì)在編譯期強(qiáng)制要求。

Checked Exception 的假設(shè)是我們捕獲了異常,然后恢復(fù)程序。但是,其實(shí)我們大多數(shù)情況下,根本就不可能恢復(fù)。

Checked Exception 的使用,已經(jīng)大大偏離了最初的設(shè)計(jì)目的。Checked Exception 不兼容 functional 編程,如果你寫(xiě)過(guò) Lambda/Stream 代碼,相信深有體會(huì)。

Error

此類錯(cuò)誤一般表示代碼運(yùn)行時(shí) JVM 出現(xiàn)問(wèn)題。通常有 Virtual MachineError(虛擬機(jī)運(yùn)行錯(cuò)誤)、NoClassDefFoundError(類定義錯(cuò)誤)等。

比如 OutOfMemoryError:內(nèi)存不足錯(cuò)誤;StackOverflowError:棧溢出錯(cuò)誤。此類錯(cuò)誤發(fā)生時(shí),JVM 將終止線程。

絕大多數(shù)導(dǎo)致程序不可恢復(fù),這些錯(cuò)誤是不受檢異常,非代碼性錯(cuò)誤。因此,當(dāng)此類錯(cuò)誤發(fā)生時(shí),應(yīng)用程序不應(yīng)該去處理此類錯(cuò)誤。按照 Java 慣例,我們是不應(yīng)該實(shí)現(xiàn)任何新的 Error 子類的!

比如開(kāi)車去洗桑拿,老王出車禍了。無(wú)法洗了,只能去醫(yī)院。

JVM 如何處理異常?

在一個(gè)方法中如果發(fā)生異常,這個(gè)方法會(huì)創(chuàng)建一個(gè)異常對(duì)象,并轉(zhuǎn)交給 JVM,該異常對(duì)象包含異常名稱,異常描述以及異常發(fā)生時(shí)應(yīng)用程序的狀態(tài)。

創(chuàng)建異常對(duì)象并轉(zhuǎn)交給 JVM 的過(guò)程稱為拋出異常。可能有一系列的方法調(diào)用,最終才進(jìn)入拋出異常的方法,這一系列方法調(diào)用的有序列表叫做調(diào)用棧。

JVM 會(huì)順著調(diào)用棧去查找看是否有可以處理異常的代碼,如果有,則調(diào)用異常處理代碼。

當(dāng) JVM 發(fā)現(xiàn)可以處理異常的代碼時(shí),會(huì)把發(fā)生的異常傳遞給它。如果 JVM 沒(méi)有找到可以處理該異常的代碼塊,JVM 就會(huì)將該異常轉(zhuǎn)交給默認(rèn)的異常處理器(默認(rèn)處理器為 JVM 的一部分),默認(rèn)異常處理器打印出異常信息并終止應(yīng)用程序。

NoClassDefFoundError 和 ClassNotFoundException

NoClassDefFoundError 是一個(gè) Error 類型的異常,是由 JVM 引起的,不應(yīng)該嘗試捕獲這個(gè)異常。

引起該異常的原因是 JVM 或 ClassLoader 嘗試加載某類時(shí)在內(nèi)存中找不到該類的定義,該動(dòng)作發(fā)生在運(yùn)行期間,即編譯時(shí)該類存在,但是在運(yùn)行時(shí)卻找不到了,可能是變異后被刪除了等原因?qū)е?

ClassNotFoundException 是一個(gè)受查異常,需要顯式地使用 try-catch 對(duì)其進(jìn)行捕獲和處理,或在方法簽名中用 throws 關(guān)鍵字進(jìn)行聲明。

當(dāng)使用 Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 動(dòng)態(tài)加載類到內(nèi)存的時(shí)候,通過(guò)傳入的類路徑參數(shù)沒(méi)有找到該類,就會(huì)拋出該異常;

另一種拋出該異常的可能原因是某個(gè)類已經(jīng)由一個(gè)類加載器加載至內(nèi)存中,另一個(gè)加載器又嘗試去加載它。

Java 常見(jiàn)異常有哪些?

java.lang.IllegalAccessError:違法訪問(wèn)錯(cuò)誤。當(dāng)一個(gè)應(yīng)用試圖訪問(wèn)、修改某個(gè)類的域(Field)或者調(diào)用其方法,但是又違反域或方法的可見(jiàn)性聲明,則拋出該異常。

java.lang.InstantiationError:實(shí)例化錯(cuò)誤。當(dāng)一個(gè)應(yīng)用試圖通過(guò) Java 的 new 操作符構(gòu)造一個(gè)抽象類或者接口時(shí)拋出該異常.

java.lang.OutOfMemoryError:內(nèi)存不足錯(cuò)誤。當(dāng)可用內(nèi)存不足以讓 Java 虛擬機(jī)分配給一個(gè)對(duì)象時(shí)拋出該錯(cuò)誤。

java.lang.StackOverflowError:堆棧溢出錯(cuò)誤。當(dāng)一個(gè)應(yīng)用遞歸調(diào)用的層次太深而導(dǎo)致堆棧溢出或者陷入死循環(huán)時(shí)拋出該錯(cuò)誤。

java.lang.ClassCastException:類造型異常。假設(shè)有類 A 和 B(A 不是 B 的父類或子類),O 是 A 的實(shí)例,那么當(dāng)強(qiáng)制將 O 構(gòu)造為類 B 的實(shí)例時(shí)拋出該異常。該異常經(jīng)常被稱為強(qiáng)制類型轉(zhuǎn)換異常。

java.lang.ClassNotFoundException:找不到類異常。當(dāng)應(yīng)用試圖根據(jù)字符串形式的類名構(gòu)造類,而在遍歷 CLASSPAH 之后找不到對(duì)應(yīng)名稱的 class 文件時(shí),拋出該異常。

java.lang.ArithmeticException:算術(shù)條件異常。譬如:整數(shù)除零等。

java.lang.ArrayIndexOutOfBoundsException:數(shù)組索引越界異常。當(dāng)對(duì)數(shù)組的索引值為負(fù)數(shù)或大于等于數(shù)組大小時(shí)拋出。

final、finally、finalize 區(qū)別?

除了名字相似,他們毫無(wú)關(guān)系!!!

  • final 可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫(xiě)、修飾變量表示該變量是一個(gè)常量不能被重新賦值。
  • finally 一般作用在 try-catch 代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法 finally 代碼塊中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來(lái)存放一些關(guān)閉資源的代碼。
  • finalize 是一個(gè)方法,屬于 Object 類的一個(gè)方法,而 Object 類是所有類的父類,Java 中允許使用 finalize()方法在垃圾收集器將對(duì)象從內(nèi)存中清除出去之前做必要的清理工作。

final 有什么用?

用于修飾類、屬性和方法;

  • 被 final 修飾的類不可以被繼承
  • 被 final 修飾的方法不可以被重寫(xiě)
  • 被 final 修飾的變量不可以被改變,被 final 修飾不可變的是變量的引用,而不是引用指向的內(nèi)容,引用指向的內(nèi)容是可以改變的。

try-catch-finally 中,如果 catch 中 return 了,finally 還會(huì)執(zhí)行嗎?

答:會(huì)執(zhí)行,在 return 前執(zhí)行。

注意:在 finally 中改變返回值的做法是不好的,因?yàn)槿绻嬖?finally 代碼塊,try 中的 return 語(yǔ)句不會(huì)立馬返回調(diào)用者,而是記錄下返回值待 finally 代碼塊執(zhí)行完畢之后再向調(diào)用者返回其值,然后如果在 finally 中修改了返回值,就會(huì)返回修改后的值。

顯然,在 finally 中返回或者修改返回值會(huì)對(duì)程序造成很大的困擾,C#中直接用編譯錯(cuò)誤的方式來(lái)阻止程序員干這種齷齪的事情,Java 中也可以通過(guò)提升編譯器的語(yǔ)法檢查級(jí)別來(lái)產(chǎn)生警告或錯(cuò)誤。

  1. public static int getInt() { 
  2.     int a = 10; 
  3.     try { 
  4.         System.out.println(a / 0); 
  5.         a = 20; 
  6.     } catch (ArithmeticException e) { 
  7.         a = 30; 
  8.         return a; 
  9.         /* 
  10.          * return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30;這個(gè)返回路徑就形成了 
  11.          * 但是呢,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容,a=40 
  12.          * 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了,而是常量30 
  13.          */ 
  14.     } finally { 
  15.         a = 40; 
  16.     } 
  17.  return a; 

執(zhí)行結(jié)果:30。

  1. public static int getInt() { 
  2.     int a = 10; 
  3.     try { 
  4.         System.out.println(a / 0); 
  5.         a = 20; 
  6.     } catch (ArithmeticException e) { 
  7.         a = 30; 
  8.         return a; 
  9.     } finally { 
  10.         a = 40; 
  11.         //如果這樣,就又重新形成了一條返回路徑,由于只能通過(guò)1個(gè)return返回,所以這里直接返回40 
  12.         return a; 
  13.     } 
  14.  

執(zhí)行結(jié)果:40。

強(qiáng)引用、軟引用、弱引用、虛引用

強(qiáng)引用、軟引用、弱引用、幻象引用有什么區(qū)別?具體使用場(chǎng)景是什么?

不同的引用類型,主要體現(xiàn)的是對(duì)象不同的可達(dá)性(reachable)狀態(tài)和對(duì)垃圾收集的影響。

強(qiáng)引用

通過(guò) new 創(chuàng)建的對(duì)象就是強(qiáng)引用,強(qiáng)引用指向一個(gè)對(duì)象,就表示這個(gè)對(duì)象還活著,垃圾回收不會(huì)去收集。

軟引用

是一種相對(duì)強(qiáng)引用弱化一些的引用,只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象。

JVM 會(huì)確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對(duì)象。

軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存,如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。

弱引用

ThreadlocalMap 中的 key 就是用了弱引用,因?yàn)?ThreadlocalMap 被 thread 對(duì)象持有,所以如果是強(qiáng)引用的話,只有當(dāng) thread 結(jié)束時(shí)才能被回收,而弱引用則可以在使用完后立即回收,不必等待 thread 結(jié)束。

虛引用

“虛引用”顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。

虛引用主要用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。虛引用與軟引用和弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。

當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。

String 篇章

可變性

String 類中使用字符數(shù)組保存字符串,private final char value[],所以 string 對(duì)象是不可變的。StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串,char[] value,這兩種象都是可變的。·線程安全性

String 中的對(duì)象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder 是 StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。

StringBuffer 對(duì)方法加了同步鎖或者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder 并沒(méi)有對(duì)方法進(jìn)行加同步鎖,所以是非線程安全的。

性能

每次對(duì) String 類型進(jìn)行改變的時(shí)候,都會(huì)生成一個(gè)新的 String 對(duì)象,然后將指針指向新的 String 對(duì)象。

StringBuffer 每次都會(huì)對(duì) StringBuffer 對(duì)象本身進(jìn)行操作,而不是生成新的對(duì)象并改變對(duì)象引用。相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)。

對(duì)于三者使用的總結(jié)

如果要操作少量的數(shù)據(jù)用 = String

單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuilder

多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù) = StringBuffer

String

String 是 Java 語(yǔ)言非常基礎(chǔ)和重要的類,提供了構(gòu)造和管理字符串的各種基本邏輯。它是典型的 Immutable 類,被聲明成為 final class,所有屬性也都是 final 的。

也由于它的不可變性,類似拼接、裁剪字符串等動(dòng)作,都會(huì)產(chǎn)生新的 String 對(duì)象。

StringBuilder

StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 沒(méi)有本質(zhì)區(qū)別,但是它去掉了線程安全的部分,有效減小了開(kāi)銷,是絕大部分情況下進(jìn)行字符串拼接的首選。

StringBuffer

StringBuffer 是為解決上面提到拼接產(chǎn)生太多中間對(duì)象的問(wèn)題而提供的一個(gè)類,我們可以用 append 或者 add 方法,把字符串添加到已有序列的末尾或者指定位置。

StringBuffer 本質(zhì)是一個(gè)線程安全的可修改字符序列,它保證了線程安全,也隨之帶來(lái)了額外的性能開(kāi)銷,所以除非有線程安全的需要,不然還是推薦使用它的后繼者,也就是 StringBuilder。

HashMap 使用 String 作為 key 有什么好處

HashMap 內(nèi)部實(shí)現(xiàn)是通過(guò) key 的 hashcode 來(lái)確定 value 的存儲(chǔ)位置,因?yàn)樽址遣豢勺兊模援?dāng)創(chuàng)建字符串時(shí),它的 hashcode 被緩存下來(lái),不需要再次計(jì)算,所以相比于其他對(duì)象更快。

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

抽象類是用來(lái)捕捉子類的通用特性的。接口是抽象方法的集合。

接口和抽象類各有優(yōu)缺點(diǎn),在接口和抽象類的選擇上,必須遵守這樣一個(gè)原則:

  • 行為模型應(yīng)該總是通過(guò)接口而不是抽象類定義,所以通常是優(yōu)先選用接口,盡量少用抽象類。
  • 選擇抽象類的時(shí)候通常是如下情況:需要定義子類的行為,又要為子類提供通用的功能。

相同點(diǎn)

  • 接口和抽象類都不能實(shí)例化
  • 都位于繼承的頂端,用于被其他實(shí)現(xiàn)或繼承
  • 都包含抽象方法,其子類都必須覆寫(xiě)這些抽象方法

接口接口定義了協(xié)議,是面向?qū)ο缶幊?封裝、繼承多態(tài))基礎(chǔ),通過(guò)接口我們能很好的實(shí)現(xiàn)單一職責(zé)、接口隔離、內(nèi)聚。

  • 不能實(shí)例化;
  • 不能包含任何非常量成員,任何 field 都是隱含著 public static final 的意義;
  • 同時(shí),沒(méi)有非靜態(tài)方法實(shí)現(xiàn),也就是說(shuō)要么是抽象方法,要么是靜態(tài)方法。

Java8 中接口中引入默認(rèn)方法和靜態(tài)方法,并且不用強(qiáng)制子類來(lái)實(shí)現(xiàn)它。以此來(lái)減少抽象類和接口之間的差異。

抽象類

抽象類是不能實(shí)例化的類,用 abstract 關(guān)鍵字修飾 class,其目的主要是代碼重用。

從設(shè)計(jì)層面來(lái)說(shuō),抽象類是對(duì)類的抽象,是一種模板設(shè)計(jì),接口是行為的抽象,是一種行為的規(guī)范。

除了不能實(shí)例化,形式上和一般的 Java 類并沒(méi)有太大區(qū)別。

可以有一個(gè)或者多個(gè)抽象方法,也可以沒(méi)有抽象方法。抽象類大多用于抽取相關(guān) Java 類的共用方法實(shí)現(xiàn)或者是共同成員變量,然后通過(guò)繼承的方式達(dá)到代碼復(fù)用的目的。

碼老濕,抽象類能用 final 修飾么?

不能,定義抽象類就是讓其他類繼承的,如果定義為 final 該類就不能被繼承,這樣彼此就會(huì)產(chǎn)生矛盾,所以 final 不能修飾抽象類

值傳遞

當(dāng)一個(gè)對(duì)象被當(dāng)作參數(shù)傳遞到一個(gè)方法后,此方法可改變這個(gè)對(duì)象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?

是值傳遞。

Java 語(yǔ)言的方法調(diào)用只支持參數(shù)的值傳遞。當(dāng)一個(gè)對(duì)象實(shí)例作為一個(gè)參數(shù)被傳遞到方法中時(shí),參數(shù)的值就是對(duì)該對(duì)象的引用。

對(duì)象的屬性可以在被調(diào)用過(guò)程中被改變,但對(duì)對(duì)象引用的改變是不會(huì)影響到調(diào)用者的。

為什么 Java 只有值傳遞?

首先回顧一下在程序設(shè)計(jì)語(yǔ)言中有關(guān)將參數(shù)傳遞給方法(或函數(shù))的一些專業(yè)術(shù)語(yǔ)。按值調(diào)用(call by value)表示方法接收的是調(diào)用者提供的值,而按引用調(diào)用(call by reference)表示方法接收的是調(diào)用者提供的變量地址。

一個(gè)方法可以修改傳遞引用所對(duì)應(yīng)的變量值,而不能修改傳遞值調(diào)用所對(duì)應(yīng)的變量值。

它用來(lái)描述各種程序設(shè)計(jì)語(yǔ)言(不只是 Java)中方法參數(shù)傳遞方式。

Java 程序設(shè)計(jì)語(yǔ)言總是采用按值調(diào)用。也就是說(shuō),方法得到的是所有參數(shù)值的一個(gè)拷貝,也就是說(shuō),方法不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。

基本數(shù)據(jù)類型

例子如下:

  1. public static void main(String[] args) { 
  2.     int num1 = 10; 
  3.     int num2 = 20; 
  4.  
  5.     swap(num1, num2); 
  6.  
  7.     System.out.println("num1 = " + num1); 
  8.     System.out.println("num2 = " + num2); 
  9.  
  10. public static void swap(int a, int b) { 
  11.     int temp = a; 
  12.     a = b; 
  13.     b = temp
  14.  
  15.     System.out.println("a = " + a); 
  16.     System.out.println("b = " + b); 

執(zhí)行結(jié)果:

  1. a = 20 
  2. b = 10 
  3. num1 = 10 
  4. num2 = 20 

解析:

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

在 swap 方法中,a、b 的值進(jìn)行交換,并不會(huì)影響到 num1、num2。

因?yàn)椋琣、b 中的值,只是從 num1、num2 的復(fù)制過(guò)來(lái)的。

也就是說(shuō),a、b 相當(dāng)于 num1、num2 的副本,副本的內(nèi)容無(wú)論怎么修改,都不會(huì)影響到原件本身。

對(duì)象引用類型

  1. public static void main(String[] args) { 
  2.     int[] arr = { 1, 2, 3, 4, 5 }; 
  3.     System.out.println(arr[0]); 
  4.     change(arr); 
  5.     System.out.println(arr[0]); 
  6.  
  7. public static void change(int[] array) { 
  8.     // 將數(shù)組的第一個(gè)元素變?yōu)? 
  9.     array[0] = 0; 

結(jié)果:

解析:

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)

array 被初始化 arr 的拷貝也就是一個(gè)對(duì)象的引用,也就是說(shuō) array 和 arr 指向的時(shí)同一個(gè)數(shù)組對(duì)象。因此,外部對(duì)引用對(duì)象的改變會(huì)反映到所對(duì)應(yīng)的對(duì)象上。

通過(guò) example2 我們已經(jīng)看到,實(shí)現(xiàn)一個(gè)改變對(duì)象參數(shù)狀態(tài)的方法并不是一件難事。理由很簡(jiǎn)單,方法得到的是對(duì)象引用的拷貝,對(duì)象引用及其他的拷貝同時(shí)引用同一個(gè)對(duì)象。

很多程序設(shè)計(jì)語(yǔ)言(特別是,C++和 Pascal)提供了兩種參數(shù)傳遞的方式:值調(diào)用和引用調(diào)用。

有些程序員認(rèn)為 Java 程序設(shè)計(jì)語(yǔ)言對(duì)對(duì)象采用的是引用調(diào)用,實(shí)際上,這種理解是不對(duì)的。

值傳遞和引用傳遞有什么區(qū)別?

值傳遞:指的是在方法調(diào)用時(shí),傳遞的參數(shù)是按值的拷貝傳遞,傳遞的是值的拷貝,也就是說(shuō)傳遞后就互不相關(guān)了。

引用傳遞:指的是在方法調(diào)用時(shí),傳遞的參數(shù)是按引用進(jìn)行傳遞,其實(shí)傳遞的引用的地址,也就是變量所對(duì)應(yīng)的內(nèi)存空間的地址。傳遞的是值的引用,也就是說(shuō)傳遞前和傳遞后都指向同一個(gè)引用(也就是同一個(gè)內(nèi)存空間)。

本文轉(zhuǎn)載自微信公眾號(hào)「碼哥字節(jié)」

面霸篇:高頻 Java 基礎(chǔ)問(wèn)題(核心卷一)原文鏈接:https://mp.weixin.qq.com/s/lztiWtwm9ryle6bc199MdQ

延伸 · 閱讀

精彩推薦
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一個(gè)注意事項(xiàng)

    Java8中Stream使用的一個(gè)注意事項(xiàng)

    最近在工作中發(fā)現(xiàn)了對(duì)于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7472021-02-04
  • Java教程xml與Java對(duì)象的轉(zhuǎn)換詳解

    xml與Java對(duì)象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對(duì)象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程Java實(shí)現(xiàn)搶紅包功能

    Java實(shí)現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)搶紅包功能,采用多線程模擬多人同時(shí)搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程升級(jí)IDEA后Lombok不能使用的解決方法

    升級(jí)IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級(jí),尋思已經(jīng)有好久沒(méi)有升過(guò)級(jí)了。升級(jí)完畢重啟之后,突然發(fā)現(xiàn)好多錯(cuò)誤,本文就來(lái)介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程20個(gè)非常實(shí)用的Java程序代碼片段

    20個(gè)非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個(gè)非常實(shí)用的Java程序片段,對(duì)java開(kāi)發(fā)項(xiàng)目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
主站蜘蛛池模板: 美女张开下身让男人桶 | 2021国产精品视频一区 | 成人影音先锋 | 日本人妖网站 | 国内视频一区二区 | 奇米影视7777久久精品 | chinese军人@gay | 轻轻色在线视频中文字幕 | 亚洲精品国产在线 | 四虎影院在线免费观看 | 天天色一色 | 日本午夜大片免费观看视频 | 午夜私人影院在线观看 | 给我免费观看的视频在线播放 | 亚洲高清中文字幕一区二区三区 | 日本高h | 国产成人精品实拍在线 | 高清在线一区二区 | 清纯漂亮女友初尝性过程 | 青青草精品在线 | 四虎影音 | 午夜人妻理论片天堂影院 | 亚洲品质自拍视频网站 | 亚洲欧美日韩另类在线一 | 国产欧美日韩视频在线观看一区二区 | 青青草精品在线观看 | 黄色大片网 | 国产精品日韩欧美在线 | 17个农民工婉莹第一部 | 欧美性理论片在线观看片免费 | 果冻传媒九一制片厂网站 | 色女的乖男人 | 公交车强校花系列小说 | 69欧美性猛交 | 日本网络视频www色高清免费 | 欧美一级片在线免费观看 | sss在线观看免费视频 | 免费人成在线观看视频播放 | 婷婷色天使在线视频观看 | 日韩精品亚洲一级在线观看 | 国产精品怡红院永久免费 |