一.Java概述
何為編程
編程就是讓計(jì)算機(jī)為解決某個(gè)問(wèn)題而使用某種程序設(shè)計(jì)語(yǔ)言編寫(xiě)程序代碼,并 終得到結(jié)果的過(guò)程。
為了使計(jì)算機(jī)能夠理解人的意圖,人類(lèi)就必須要將需解決的問(wèn)題的思路、方法、 和手段通過(guò)計(jì)算機(jī)能夠理解的形式告訴計(jì)算機(jī),使得計(jì)算機(jī)能夠根據(jù)人的指令一 步一步去工作,完成某種特定的任務(wù)。這種人和計(jì)算機(jī)之間交流的過(guò)程就是編 程。
什么是Java
Java是一門(mén)面向?qū)ο缶幊陶Z(yǔ)言,不僅吸收了C++語(yǔ)言的各種優(yōu)點(diǎn),還摒棄了 C++里難以理解的多繼承、指針等概念,因此Java語(yǔ)言具有功能強(qiáng)大和簡(jiǎn)單易 用兩個(gè)特征。Java語(yǔ)言作為靜態(tài)面向?qū)ο缶幊陶Z(yǔ)言的代表,極好地實(shí)現(xiàn)了面向?qū)?象理論,允許程序員以優(yōu)雅的思維方式進(jìn)行復(fù)雜的編程 。
jdk1.5之后的三大版本
- Java SE(J2SE,Java 2 Platform Standard Edition,標(biāo)準(zhǔn)版) Java SE 以前稱(chēng)為 J2SE。它允許開(kāi)發(fā)和部署在桌面、服務(wù)器、嵌入式環(huán)境和實(shí)時(shí)環(huán)境中使 用的 Java 應(yīng)用程序。Java SE 包含了支持 Java Web 服務(wù)開(kāi)發(fā)的類(lèi),并為Java EE和Java ME提供基礎(chǔ)。
- Java EE(J2EE,Java 2 Platform Enterprise Edition,企業(yè)版) Java EE 以前稱(chēng)為 J2EE。企業(yè)版本幫助開(kāi)發(fā)和部署可移植、健壯、可伸縮且安全的服務(wù)器 端Java 應(yīng)用程序。Java EE 是在 Java SE 的基礎(chǔ)上構(gòu)建的,它提供 Web 服務(wù)、組件模型、 管理和通信 API,可以用來(lái)實(shí)現(xiàn)企業(yè)級(jí)的面向服務(wù)體系結(jié)構(gòu)(service-oriented architecture,SOA)和 Web2.0應(yīng)用程序。2018年2月,Eclipse 宣布正式將 JavaEE 更名 為 JakartaEE
- Java ME(J2ME,Java 2 Platform Micro Edition,微型版) Java ME 以前稱(chēng)為 J2ME。Java ME 為在移動(dòng)設(shè)備和嵌入式設(shè)備(比如手機(jī)、PDA、電視 機(jī)頂盒和打印機(jī))上運(yùn)行的應(yīng)用程序提供一個(gè)健壯且靈活的環(huán)境。Java ME 包括靈活的用 戶界面、健壯的安全模型、許多內(nèi)置的網(wǎng)絡(luò)協(xié)議以及對(duì)可以動(dòng)態(tài)下載的連網(wǎng)和離線應(yīng)用程序 的豐富支持?;?Java ME 規(guī)范的應(yīng)用程序只需編寫(xiě)一次,就可以用于許多設(shè)備,而且可 以利用每個(gè)設(shè)備的本機(jī)功能。
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程序所需的核心類(lèi)庫(kù)等。核 心類(lèi)庫(kù)主要是java.lang包:包含了運(yùn)行Java程序必不可少的系統(tǒng)類(lèi),如基本數(shù) 據(jù)類(lèi)型、基本數(shù)學(xué)函數(shù)、字符串處理、線程、異常處理類(lèi)等,系統(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)等
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-mFIOelzo-1692506313322)(01-Java基礎(chǔ)知識(shí)面試題(2020最新版).assets/image-20201106172325865.png)]
什么是跨平臺(tái)性?原理是什么
所謂跨平臺(tái)性,是指java語(yǔ)言編寫(xiě)的程序,一次編譯后,可以在多個(gè)系統(tǒng)平臺(tái)上 運(yùn)行。
實(shí)現(xiàn)原理:Java程序是通過(guò)java虛擬機(jī)在系統(tǒng)平臺(tái)上運(yùn)行的,只要該系統(tǒng)可以安 裝相應(yīng)的java虛擬機(jī),該系統(tǒng)就可以運(yùn)行java程序。
Java語(yǔ)言有哪些特點(diǎn)
簡(jiǎn)單易學(xué)(Java語(yǔ)言的語(yǔ)法與C語(yǔ)言和C++語(yǔ)言很接近)
面向?qū)ο螅ǚ庋b,繼承,多態(tài))
平臺(tái)無(wú)關(guān)性(Java虛擬機(jī)實(shí)現(xiàn)平臺(tái)無(wú)關(guān)性)
支持網(wǎng)絡(luò)編程并且很方便(Java語(yǔ)言誕生本身就是為簡(jiǎn)化網(wǎng)絡(luò)編程設(shè)計(jì)的)
支持多線程(多線程機(jī)制使應(yīng)用程序在同一時(shí)間并行執(zhí)行多項(xiàng)任)
健壯性(Java語(yǔ)言的強(qiáng)類(lèi)型機(jī)制、異常處理、垃圾的自動(dòng)收集等)
安全性
什么是字節(jié)碼?采用字節(jié)碼的大好處是什么
字節(jié)碼:Java源代碼經(jīng)過(guò)虛擬機(jī)編譯器編譯后產(chǎn)生的文件(即擴(kuò)展為.class的文 件),它不面向任何特定的處理器,只面向虛擬機(jī)。
采用字節(jié)碼的好處:
Java語(yǔ)言通過(guò)字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語(yǔ)言執(zhí)行效率低的 問(wèn)題,同時(shí)又保留了解釋型語(yǔ)言可移植的特點(diǎn)。所以Java程序運(yùn)行時(shí)比較高效, 而且,由于字節(jié)碼并不專(zhuān)對(duì)一種特定的機(jī)器,因此,Java程序無(wú)須重新編譯便可 在多種不同的計(jì)算機(jī)上運(yùn)行。
先看下java中的編譯器和解釋器:
Java中引入了虛擬機(jī)的概念,即在機(jī)器和編譯程序之間加入了一層抽象的虛擬機(jī) 器。這臺(tái)虛擬的機(jī)器在任何平臺(tái)上都提供給編譯程序一個(gè)的共同的接口。編譯程 序只需要面向虛擬機(jī),生成虛擬機(jī)能夠理解的代碼,然后由解釋器來(lái)將虛擬機(jī)代 碼轉(zhuǎn)換為特定系統(tǒng)的機(jī)器碼執(zhí)行。在Java中,這種供虛擬機(jī)理解的代碼叫做字節(jié) 碼(即擴(kuò)展為.class的文件),它不面向任何特定的處理器,只面向虛擬機(jī)。每 一種平臺(tái)的解釋器是不同的,但是實(shí)現(xiàn)的虛擬機(jī)是相同的。Java源程序經(jīng)過(guò)編譯 器編譯后變成字節(jié)碼,字節(jié)碼由虛擬機(jī)解釋執(zhí)行,虛擬機(jī)將每一條要執(zhí)行的字節(jié) 碼送給解釋器,解釋器將其翻譯成特定機(jī)器上的機(jī)器碼,然后在特定的機(jī)器上運(yùn) 行,這就是上面提到的Java的特點(diǎn)的編譯與解釋并存的解釋。
Java源代碼‐‐‐‐>編譯器‐‐‐‐>jvm可執(zhí)行的Java字節(jié)碼(即虛擬指令)‐‐‐‐>jvm‐‐‐‐>jvm中 解釋器‐‐‐‐‐>機(jī)器可執(zhí)行的二進(jìn)制機(jī)器碼‐‐‐‐>程序運(yùn)行。
什么是Java程序的主類(lèi)?應(yīng)用程序和小程序的主類(lèi)有何不同?
一個(gè)程序中可以有多個(gè)類(lèi),但只能有一個(gè)類(lèi)是主類(lèi)。在Java應(yīng)用程序中,這個(gè)主 類(lèi)是指包含main()方法的類(lèi)。而在Java小程序中,這個(gè)主類(lèi)是一個(gè)繼承自系統(tǒng) 類(lèi)JApplet或Applet的子類(lèi)。應(yīng)用程序的主類(lèi)不一定要求是public類(lèi),但小程序 的主類(lèi)要求必須是public類(lèi)。主類(lèi)是Java程序執(zhí)行的入口點(diǎn)。
Java應(yīng)用程序與小程序之間有那些差別?
簡(jiǎn)單說(shuō)應(yīng)用程序是從主線程啟動(dòng)(也就是main()方法)。applet小程序沒(méi)有main 方法,主要是嵌在瀏覽器頁(yè)面上運(yùn)行(調(diào)用init()線程或者run()來(lái)啟動(dòng)),嵌入瀏 覽器這點(diǎn)跟flash的小游戲類(lèi)似。
Java和C++的區(qū)別
我知道很多人沒(méi)學(xué)過(guò)C++,但是面試官就是沒(méi)事喜歡拿咱們Java和C++比呀! 沒(méi)辦法!??!就算沒(méi)學(xué)過(guò)C++,也要記下來(lái)!
- 都是面向?qū)ο蟮恼Z(yǔ)言,都支持封裝、繼承和多態(tài)
- Java不提供指針來(lái)直接訪問(wèn)內(nèi)存,程序內(nèi)存更加安全
- Java的類(lèi)是單繼承的,C++支持多重繼承;雖然Java的類(lèi)不可以多繼承,但是 接口可以多繼承。
- Java有自動(dòng)內(nèi)存管理機(jī)制,不需要程序員手動(dòng)釋放無(wú)用內(nèi)存
Oracle JDK 和 OpenJDK 的對(duì)比
- Oracle JDK版本將每三年發(fā)布一次,而OpenJDK版本每三個(gè)月發(fā)布一 次;
- OpenJDK 是一個(gè)參考模型并且是完全開(kāi)源的,而Oracle JDK是 OpenJDK的一個(gè)實(shí)現(xiàn),并不是完全開(kāi)源的;
- Oracle JDK 比 OpenJDK 更穩(wěn)定。OpenJDK和Oracle JDK的代碼幾乎 相同,但Oracle JDK有更多的類(lèi)和一些錯(cuò)誤修復(fù)。因此,如果您想開(kāi)發(fā)企 業(yè)/商業(yè)軟件,我建議您選擇Oracle JDK,因?yàn)樗?jīng)過(guò)了徹底的測(cè)試和穩(wěn) 定。某些情況下,有些人提到在使用OpenJDK 可能會(huì)遇到了許多應(yīng)用程 序崩潰的問(wèn)題,但是,只需切換到Oracle JDK就可以解決問(wèn)題;
- 在響應(yīng)性和JVM性能方面,Oracle JDK與OpenJDK相比提供了更好的 性能;
- Oracle JDK不會(huì)為即將發(fā)布的版本提供長(zhǎng)期支持,用戶每次都必須通過(guò) 更新到最新版本獲得支持來(lái)獲取最新版本;
- Oracle JDK根據(jù)二進(jìn)制代碼許可協(xié)議獲得許可,而OpenJDK根據(jù)GPL v2許可獲得許可。
二.基礎(chǔ)語(yǔ)法
1.數(shù)據(jù)類(lèi)型
Java有哪些數(shù)據(jù)類(lèi)型
定義:Java語(yǔ)言是強(qiáng)類(lèi)型語(yǔ)言,對(duì)于每一種數(shù)據(jù)都定義了明確的具體的數(shù)據(jù)類(lèi) 型,在內(nèi)存中分配了不同大小的內(nèi)存空間。
分類(lèi):
基本數(shù)據(jù)類(lèi)型
- ? 數(shù)值型
? 整數(shù)類(lèi)型(byte,short,int,long)
? 浮點(diǎn)類(lèi)型(float,double) - ? 字符型(char)
- ? 布爾型(boolean)
引用數(shù)據(jù)類(lèi)型
- ? 類(lèi)(class)
- ? 接口(interface)
- ? 數(shù)組([])
Java基本數(shù)據(jù)類(lèi)型圖
switch 是否能作用在 byte 上,是否能作用在 long 上,是否 能作用在 String 上
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java5 開(kāi)始,Java 中引入了枚舉類(lèi)型,expr 也可以是 enum 類(lèi)型,從 Java 7 開(kāi)始,expr 還可以是字符串(String),但是長(zhǎng)整型(long)在目前所有的版 本中都是不可以的
用最有效率的方法計(jì)算 2 乘以 8
2 << 3(左移 3 位相當(dāng)于乘以 2 的 3 次方,右移 3 位相當(dāng)于除以 2 的 3 次 方)。
Math.round(11.5) 等于多少?Math.round(-11.5) 等于多少
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍 五入的原理是在參數(shù)上加 0.5 然后進(jìn)行下取整。
loat f=3.4;是否正確
不正確。3.4 是雙精度數(shù),將雙精度型(double)賦值給浮點(diǎn)型(float)屬于 下轉(zhuǎn)型(down-casting,也稱(chēng)為窄化)會(huì)造成精度損失,因此需要強(qiáng)制類(lèi)型轉(zhuǎn) 換float f =(float)3.4; 或者寫(xiě)成 float f =3.4F;。
short s1 = 1; s1 = s1 + 1;有錯(cuò)嗎?short s1 = 1; s1 += 1;有錯(cuò)嗎
對(duì)于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 類(lèi)型,因此 s1+1 運(yùn)算結(jié)果也是 int型,需要強(qiáng)制轉(zhuǎn)換類(lèi)型才能賦值給 short 型。 而 short s1 = 1; s1 += 1;可以正確編譯,因?yàn)?s1+= 1;相當(dāng)于 s1 = (short(s1 + 1);其中有隱含的強(qiáng)制類(lèi)型轉(zhuǎn)換。
2.編碼
Java語(yǔ)言采用何種編碼方案?有何特點(diǎn)?
Java語(yǔ)言采用Unicode編碼標(biāo)準(zhǔn),Unicode(標(biāo)準(zhǔn)碼),它為每個(gè)字符制訂了一 個(gè)唯一的數(shù)值,因此在任何的語(yǔ)言,平臺(tái),程序都可以放心的使用。
3. 注釋
什么Java注釋
定義:用于解釋說(shuō)明程序的文字
分類(lèi)
- 單行注釋 格式: // 注釋文字
- 多行注釋 格式: /* 注釋文字 */
- 文檔注釋 格式:/** 注釋文字 */
作用
在程序中,尤其是復(fù)雜的程序中,適當(dāng)?shù)丶尤胱⑨尶梢栽黾映绦虻目勺x性,有利 于程序的修改、調(diào)試和交流。注釋的內(nèi)容在程序編譯的時(shí)候會(huì)被忽視,不會(huì)產(chǎn)生 目標(biāo)代碼,注釋的部分不會(huì)對(duì)程序的執(zhí)行結(jié)果產(chǎn)生任何影響。 注意事項(xiàng):多行和文檔注釋都不能嵌套使用。 訪問(wèn)修飾符
訪問(wèn)修飾符 public,private,protected,以及不寫(xiě)(默認(rèn))時(shí)的 區(qū)別
定義:Java中,可以使用訪問(wèn)修飾符來(lái)保護(hù)對(duì)類(lèi)、變量、方法和構(gòu)造方法的訪 問(wèn)。Java 支持 4 種不同的訪問(wèn)權(quán)限。
分類(lèi):
- private : 在同一類(lèi)內(nèi)可見(jiàn)。使用對(duì)象:變量、方法。 注意:不能修飾類(lèi)(外部 類(lèi))
- default (即缺省,什么也不寫(xiě),不使用任何關(guān)鍵字): 在同一包內(nèi)可見(jiàn),不使用 任何修飾符。使用對(duì)象:類(lèi)、接口、變量、方法。
- protected : 對(duì)同一包內(nèi)的類(lèi)和所有子類(lèi)可見(jiàn)。使用對(duì)象:變量、方法。 注意: 不能修飾類(lèi)(外部類(lèi))。
- public : 對(duì)所有類(lèi)可見(jiàn)。使用對(duì)象:類(lèi)、接口、變量、方法
訪問(wèn)修飾符圖
4.運(yùn)算符
&和&&的區(qū)別
&運(yùn)算符有兩種用法:(1)按位與;(2)邏輯與。
&&運(yùn)算符是短路與運(yùn)算。邏輯與跟短路與的差別是非常巨大的,雖然二者都要 求運(yùn)算符左右兩端的布爾值都是true 整個(gè)表達(dá)式的值才是 true。&&之所以稱(chēng)
為短路運(yùn)算,是因?yàn)槿绻?amp;&左邊的表達(dá)式的值是 false,右邊的表達(dá)式會(huì)被直 接短路掉,不會(huì)進(jìn)行運(yùn)算。
注意:邏輯或運(yùn)算符(|)和短路或運(yùn)算符(||)的差別也是如此。
5.關(guān)鍵字
Java 有沒(méi)有 goto
goto 是 Java 中的保留字,在目前版本的 Java 中沒(méi)有使用。
final 有什么用?
用于修飾類(lèi)、屬性和方法;
- 被final修飾的類(lèi)不可以被繼承
- 被final修飾的方法不可以被重寫(xiě)
- 被final修飾的變量不可以被改變,被final修飾不可變的是變量的引用,而不是引用指向的內(nèi)容,引用指向的內(nèi)容是可以改變的
final finally finalize區(qū)別
- final可以修飾類(lèi)、變量、方法,修飾類(lèi)表示該類(lèi)不能被繼承、修飾方法表示該方法不能被重寫(xiě)、修飾變量表示該變量是一個(gè)常量不能被重新賦值。
- finally一般作用在try-catch代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來(lái)存放一些關(guān)閉資源的代碼。
- finalize是一個(gè)方法,屬于Object類(lèi)的一個(gè)方法,而Object類(lèi)是所有類(lèi)的父類(lèi),該方法一般由垃圾回收器來(lái)調(diào)用,當(dāng)我們調(diào)用System.gc() 方法的時(shí)候,由垃圾回收器調(diào)用finalize(),回收垃圾,一個(gè)對(duì)象是否可回收的最后判斷。
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 name, int age) {
2 this.name = name;
3 this.age = age;
4 }
3.引用本類(lèi)的構(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 name, int age) {
12 this(name);
13 this.age = age;
14 }
15 }
super關(guān)鍵字的用法
super可以理解為是指向自己超(父)類(lèi)對(duì)象的一個(gè)指針,而這個(gè)超類(lèi)指的是離
自己最近的一個(gè)父類(lèi)。
super也有三種用法:
1.普通的直接引用
與this類(lèi)似,super相當(dāng)于是指向當(dāng)前對(duì)象的父類(lèi)的引用,這樣就可以用
super.xxx來(lái)引用父類(lèi)的成員。
2.子類(lèi)中的成員變量或方法與父類(lèi)中的成員變量或方法同名時(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
10 class Student extends Person{
11 private String name;
12
13 public Student(String name, String name1) {
14 super(name);
15 this.name = name1;
16 }
17
18 public void getInfo(){
19 System.out.println(this.name); //Child
20 System.out.println(super.name); //Father
21 }
22
23 }
24
25 public class Test {
26 public static void main(String[] args) {
27 Student s1 = new Student("Father","Child");
28 s1.getInfo();
29
30 }
31 }
3.引用父類(lèi)構(gòu)造函數(shù)
super(參數(shù)):調(diào)用父類(lèi)中的某一個(gè)構(gòu)造函數(shù)(應(yīng)該為構(gòu)造函數(shù)中的第一條語(yǔ)句)。
this(參數(shù)):調(diào)用本類(lèi)中另一種形式的構(gòu)造函數(shù)(應(yīng)該為構(gòu)造函數(shù)中的第一條語(yǔ)句)。
this與super的區(qū)別
- super: 它引用當(dāng)前對(duì)象的直接父類(lèi)中的成員(用來(lái)訪問(wèn)直接父類(lèi)中被隱藏的父類(lèi)中成員數(shù)據(jù)或函數(shù),基類(lèi)與派生類(lèi)中有相同成員定義時(shí)如:super.變量名 super.成員函數(shù)據(jù)名(實(shí)參)
- this:它代表當(dāng)前對(duì)象名(在程序中易產(chǎn)生二義性之處,應(yīng)使用this來(lái)指明當(dāng)前對(duì)象;如果函數(shù)的形參與類(lèi)中的成員數(shù)據(jù)同名,這時(shí)需用this來(lái)指明成員變量名)
- super()和this()類(lèi)似,區(qū)別是,super()在子類(lèi)中調(diào)用父類(lèi)的構(gòu)造方法,this()在本類(lèi)內(nèi)調(diào)用本類(lèi)的其它構(gòu)造方法。
- super()和this()均需放在構(gòu)造方法內(nèi)第一行。
- 盡管可以用this調(diào)用一個(gè)構(gòu)造器,但卻不能調(diào)用兩個(gè)。
- this和super不能同時(shí)出現(xiàn)在一個(gè)構(gòu)造函數(shù)里面,因?yàn)閠his必然會(huì)調(diào)用其它的構(gòu)造函數(shù),其它的構(gòu)造函數(shù)必然也會(huì)有super語(yǔ)句的存在,所以在同一個(gè)構(gòu)造函數(shù)里面有相同的語(yǔ)句,就失去了語(yǔ)句的意義,編譯器也不會(huì)通過(guò)。
- this()和super()都指的是對(duì)象,所以,均不可以在static環(huán)境中使用。包括:
static變量,static方法,static語(yǔ)句塊。 - 從本質(zhì)上講,this是一個(gè)指向本對(duì)象的指針, 然而super是一個(gè)Java關(guān)鍵字。
static存在的主要意義
static的主要意義是在于創(chuàng)建獨(dú)立于具體對(duì)象的域變量或者方法。以致于即使沒(méi)有創(chuàng)建對(duì)象,也能使用屬性和調(diào)用方法!
static關(guān)鍵字還有一個(gè)比較關(guān)鍵的作用就是 用來(lái)形成靜態(tài)代碼塊以優(yōu)化程序性能。static塊可以置于類(lèi)中的任何地方,類(lèi)中可以有多個(gè)static塊。在類(lèi)初次被加載的時(shí)候,會(huì)按照static塊的順序來(lái)執(zhí)行每個(gè)static塊,并且只會(huì)執(zhí)行一次。為什么說(shuō)static塊可以用來(lái)優(yōu)化程序性能,是因?yàn)樗奶匦?只會(huì)在類(lèi)加載的時(shí)候
執(zhí)行一次。因此,很多時(shí)候會(huì)將一些只需要進(jìn)行一次的初始化操作都放在static代碼塊中進(jìn)行。
static的獨(dú)特之處
1、被static修飾的變量或者方法是獨(dú)立于該類(lèi)的任何對(duì)象,也就是說(shuō),這些變量和方法不屬于任何一個(gè)實(shí)例對(duì)象,而是被類(lèi)的實(shí)例對(duì)象所共享。
怎么理解 “被類(lèi)的實(shí)例對(duì)象所共享” 這句話呢?就是說(shuō),一個(gè)類(lèi)的靜態(tài)成員,它是屬于大伙的【大伙指的是這個(gè)類(lèi)的多個(gè)對(duì)象實(shí)例,我們都知道一個(gè)類(lèi)可以創(chuàng)建多個(gè)實(shí)例!】,所有的類(lèi)對(duì)象共享的,不像成員變量是自個(gè)的【自個(gè)指的是這個(gè)類(lèi)的單個(gè)實(shí)例對(duì)象】…我覺(jué)得我已經(jīng)講的很通俗了,你明白了咩?
2、在該類(lèi)被第一次加載的時(shí)候,就會(huì)去加載被static修飾的部分,而且只在類(lèi)第一次使用時(shí)加載并進(jìn)行初始化,注意這是第一次用就要初始化,后面根據(jù)需要是可以再次賦值的。
3、static變量值在類(lèi)加載的時(shí)候分配空間,以后創(chuàng)建類(lèi)對(duì)象的時(shí)候不會(huì)重新分配。賦值的話,是可以任意賦值的!
4、被static修飾的變量或者方法是優(yōu)先于對(duì)象存在的,也就是說(shuō)當(dāng)一個(gè)類(lèi)加載完畢之后,即便沒(méi)有創(chuàng)建對(duì)象,也可以去訪問(wèn)。
static應(yīng)用場(chǎng)景
因?yàn)閟tatic是被類(lèi)的實(shí)例對(duì)象所共享,因此如果某個(gè)成員變量是被所有對(duì)象所共享的,那么這個(gè)成員變量就應(yīng)該定義為靜態(tài)變量。
因此比較常見(jiàn)的static應(yīng)用場(chǎng)景有:
1、修飾成員變量
2、修飾成員方法
3、靜態(tài)代碼塊
4、修飾類(lèi)【只能修飾內(nèi)部類(lèi)也就是靜態(tài)內(nèi)部類(lèi)】
5、靜態(tài)導(dǎo)包
static注意事項(xiàng)
1、靜態(tài)只能訪問(wèn)靜態(tài)。 2、非靜態(tài)既可以訪問(wèn)非靜態(tài)的,也可以訪問(wèn)靜態(tài)的。
6.流程控制語(yǔ)句
break ,continue ,return 的區(qū)別及作用
break 跳出總上一層循環(huán),不再執(zhí)行循環(huán)(結(jié)束當(dāng)前的循環(huán)體)continue 跳出本次循環(huán),繼續(xù)執(zhí)行下次循環(huán)(結(jié)束正在執(zhí)行的循環(huán) 進(jìn)入下一個(gè)循環(huán)條件)
return 程序返回,不再執(zhí)行下面的代碼(結(jié)束當(dāng)前的方法 直接返回)
在 Java 中,如何跳出當(dāng)前的多重嵌套循環(huán)
在Java中,要想跳出多重循環(huán),可以在外面的循環(huán)語(yǔ)句前定義一個(gè)標(biāo)號(hào),然后在里層循環(huán)體的代碼中使用帶有標(biāo)號(hào)的break 語(yǔ)句,即可跳出外層循環(huán)。例如:
1 public static void main(String[] args) {
2 ok:
3 for (int i = 0; i < 10; i++) {
4 for (int j = 0; j < 10; j++) {
5 System.out.println("i=" + i + ",j=" + j);
6 if (j == 5) {
7 break ok;
8 }
9
10 }
11 }
12 }
三.面向?qū)ο?/h2>
1.面向?qū)ο蟾攀?/h3>
面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別
面向過(guò)程:
面向?qū)ο蠛兔嫦蜻^(guò)程的區(qū)別
面向過(guò)程:
優(yōu)點(diǎn):性能比面向?qū)ο蟾?,因?yàn)轭?lèi)調(diào)用時(shí)需要實(shí)例化,開(kāi)銷(xiāo)比較大,比較消耗資源;比如單片機(jī)、嵌入式開(kāi)發(fā)、Linux/Unix等一般采用面向過(guò)程開(kāi)發(fā),能是最重要的因素。
缺點(diǎn):沒(méi)有面向?qū)ο笠拙S護(hù)、易復(fù)用、易擴(kuò)展
面向?qū)ο螅?/h5>
優(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è)類(lèi),這是一個(gè)封閉的盒子,在這里你擁有數(shù)據(jù)也擁有解決問(wèn)題的方法。需要什么功能直接使用就可以了,不必去一步一步的實(shí)現(xiàn),至于這個(gè)功能是如何實(shí)現(xiàn)的,管我們什么事?我們會(huì)用就可以了。
面向?qū)ο蟮牡讓悠鋵?shí)還是面向過(guò)程,把面向過(guò)程抽象成類(lèi),然后封裝,方便我們使用的就是面向?qū)ο罅恕?/p>
2.面向?qū)ο笕筇匦?/h3>
面向?qū)ο蟮奶卣饔心男┓矫?/h4>
**面向?qū)ο蟮奶卣髦饕幸韵聨讉€(gè)方面: **
**抽象:**抽象是將一類(lèi)對(duì)象的共同特征總結(jié)出來(lái)構(gòu)造類(lèi)的過(guò)程,包括數(shù)據(jù)抽象和行 為抽象兩方面。抽象只關(guān)注對(duì)象有哪些屬性和行為,并不關(guān)注這些行為的細(xì)節(jié)是 什么。
-
封裝 : 封裝把一個(gè)對(duì)象的屬性私有化,同時(shí)提供一些可以被外界訪問(wèn)的屬性的方法,如 果屬性不想被外界訪問(wèn),我們大可不必提供方法給外界訪問(wèn)。但是如果一個(gè)類(lèi)沒(méi) 有提供給外界訪問(wèn)的方法,那么這個(gè)類(lèi)也沒(méi)有什么意義了。
-
繼承 : 繼承是使用已存在的類(lèi)的定義作為基礎(chǔ)建立新類(lèi)的技術(shù),新類(lèi)的定義可以增加新 的數(shù)據(jù)或新的功能,也可以用父類(lèi)的功能,但不能選擇性地繼承父類(lèi)。通過(guò)使用 繼承我們能夠非常方便地復(fù)用以前的代碼。
? 關(guān)于繼承如下 3 點(diǎn)請(qǐng)記?。?/p>
? 1.子類(lèi)擁有父類(lèi)非 private 的屬性和方法。
? 2.子類(lèi)可以擁有自己屬性和方法,即子類(lèi)可以對(duì)父類(lèi)進(jìn)行擴(kuò)展。
? 3.子類(lèi)可以用自己的方式實(shí)現(xiàn)父類(lèi)的方法。
-
多態(tài) : 所謂多態(tài)就是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出 的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量到 底會(huì)指向哪個(gè)類(lèi)的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類(lèi)中實(shí)現(xiàn)的 方法,必須在由程序運(yùn)行期間才能決定。
在Java中有兩種形式可以實(shí)現(xiàn)多態(tài):繼承(多個(gè)子類(lèi)對(duì)同一方法的重寫(xiě))和接口 (實(shí)現(xiàn)接口并覆蓋接口中同一方法)。
其中Java 面向?qū)ο缶幊倘筇匦裕悍庋b 繼承 多態(tài)
封裝:隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外提供公共訪問(wèn)方式,將變化隔離,便 于使用,提高復(fù)用性和安全性。
繼承:繼承是使用已存在的類(lèi)的定義作為基礎(chǔ)建立新類(lèi)的技術(shù),新類(lèi)的定義可以 增加新的數(shù)據(jù)或新的功能,也可以用父類(lèi)的功能,但不能選擇性地繼承父類(lèi)。通 過(guò)使用繼承可以提高代碼復(fù)用性。繼承是多態(tài)的前提。
**關(guān)于繼承如下 3 點(diǎn)請(qǐng)記住: **
- 子類(lèi)擁有父類(lèi)非 private 的屬性和方法。
- 子類(lèi)可以擁有自己屬性和方法,即子類(lèi)可以對(duì)父類(lèi)進(jìn)行擴(kuò)展。
- 子類(lèi)可以用自己的方式實(shí)現(xiàn)父類(lèi)的方法。
多態(tài)性:父類(lèi)或接口定義的引用變量可以指向子類(lèi)或具體實(shí)現(xiàn)類(lèi)的實(shí)例對(duì)象。提 高了程序的拓展性。
在Java中有兩種形式可以實(shí)現(xiàn)多態(tài):繼承(多個(gè)子類(lèi)對(duì)同一方法的重寫(xiě))和接口 (實(shí)現(xiàn)接口并覆蓋接口中同一方法)。
方法重載(overload)實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性(也稱(chēng)為前綁定),而方法重 寫(xiě)(override)實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性(也稱(chēng)為后綁定)。
一個(gè)引用變量到底會(huì)指向哪個(gè)類(lèi)的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是 哪個(gè)類(lèi)中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。運(yùn)行時(shí)的多態(tài)是面向?qū)?象精髓的東西,要實(shí)現(xiàn)多態(tài)需要做兩件事:
- 方法重寫(xiě)(子類(lèi)繼承父類(lèi)并重寫(xiě)父類(lèi)中已有的或抽象的方法);
- 對(duì)象造型(用父類(lèi)型引用子類(lèi)型對(duì)象,這樣同樣的引用調(diào)用同樣的方法就會(huì)根據(jù) 子類(lèi)對(duì)象的不同而表現(xiàn)出不同的行為)。
什么是多態(tài)機(jī)制?Java語(yǔ)言是如何實(shí)現(xiàn)多態(tài)的?
所謂多態(tài)就是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出 的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒 底會(huì)指向哪個(gè)類(lèi)的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類(lèi)中實(shí)現(xiàn)的 方法,必須在由程序運(yùn)行期間才能決定。因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類(lèi),這 樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類(lèi)實(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)性
多態(tài)的實(shí)現(xiàn)
Java實(shí)現(xiàn)多態(tài)有三個(gè)必要條件:繼承、重寫(xiě)、向上轉(zhuǎn)型。
繼承:在多態(tài)中必須存在有繼承關(guān)系的子類(lèi)和父類(lèi)。
重寫(xiě):子類(lèi)對(duì)父類(lèi)中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類(lèi)的 方法。
向上轉(zhuǎn)型:在多態(tài)中需要將子類(lèi)的引用賦給父類(lèi)對(duì)象,只有這樣該引用才能夠具 備技能調(diào)用父類(lèi)的方法和子類(lèi)的方法。
只有滿足了上述三個(gè)條件,我們才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn) 代碼處理不同的對(duì)象,從而達(dá)到執(zhí)行不同的行為。
對(duì)于Java而言,它多態(tài)的實(shí)現(xiàn)機(jī)制遵循一個(gè)原則:當(dāng)超類(lèi)對(duì)象引用變量引用子類(lèi) 對(duì)象時(shí),被引用對(duì)象的類(lèi)型而不是引用變量的類(lèi)型決定了調(diào)用誰(shuí)的成員方法,但 是這個(gè)被調(diào)用的方法必須是在超類(lèi)中定義過(guò)的,也就是說(shuō)被子類(lèi)覆蓋的方法。
面向?qū)ο笪宕蠡驹瓌t是什么(可選)
- 單一職責(zé)原則SRP(Single Responsibility Principle)類(lèi)的功能要單一,不能包羅萬(wàn)象,跟雜貨鋪似的。
開(kāi)放封閉原則OCP(Open-Close Principle) - 一個(gè)模塊對(duì)于拓展是開(kāi)放的,對(duì)于修改是封閉的,想要增加功能熱烈歡迎,想要修改,哼,
一萬(wàn)個(gè)不樂(lè)意。 - 里式替換原則LSP(the Liskov Substitution Principle LSP)子類(lèi)可以替換父類(lèi)出現(xiàn)在父類(lèi)能夠出現(xiàn)的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
- 依賴(lài)倒置原則DIP(the Dependency Inversion Principle DIP)高層次的模塊不應(yīng)該依賴(lài)于低層次的模塊,他們都應(yīng)該依賴(lài)于抽象。抽象不應(yīng)該依賴(lài)于具體實(shí)現(xiàn),具體實(shí)現(xiàn)應(yīng)該依賴(lài)于抽象。就是你出國(guó)要說(shuō)你是中國(guó)人,而不能說(shuō)你是哪個(gè)村子的。比如說(shuō)中國(guó)人是抽象的,下面有具體的xx省,xx市,xx縣。你要依賴(lài)的抽象是中國(guó)人,而不是你是xx村的。
- 接口分離原則ISP(the Interface Segregation Principle ISP)
設(shè)計(jì)時(shí)采用多個(gè)與特定客戶類(lèi)有關(guān)的接口比采用一個(gè)通用的接口要好。就比如一個(gè)手機(jī)擁有
打電話,看視頻,玩游戲等功能,把這幾個(gè)功能拆分成不同的接口,比在一個(gè)接口里要好的
多。
四.類(lèi)與接口
抽象類(lèi)和接口的對(duì)比
抽象類(lèi)是用來(lái)捕捉子類(lèi)的通用特性的。接口是抽象方法的集合。
從設(shè)計(jì)層面來(lái)說(shuō),抽象類(lèi)是對(duì)類(lèi)的抽象,是一種模板設(shè)計(jì),接口是行為的抽象,是一種行為的規(guī)范。
相同點(diǎn)
- 接口和抽象類(lèi)都不能實(shí)例化
- 都位于繼承的頂端,用于被其他實(shí)現(xiàn)或繼承
- 都包含抽象方法,其子類(lèi)都必須覆寫(xiě)這些抽象方法
不同點(diǎn)
參數(shù) | 抽象類(lèi) | 接口 |
---|---|---|
聲明 | 抽象類(lèi)使用abstract關(guān)鍵字聲明 | 接口使用interface關(guān)鍵字聲明 |
實(shí)現(xiàn) | 子類(lèi)使用extends關(guān)鍵字來(lái)繼承抽象類(lèi)。如果子類(lèi)不是抽象類(lèi)的話,它需要提供抽象類(lèi)中所有聲明的方法的實(shí)現(xiàn) | 子類(lèi)使用implements關(guān)鍵字來(lái)實(shí)現(xiàn)接口。它需要提供接口中所有聲明的方法的實(shí)現(xiàn) |
構(gòu)造器 | 抽象類(lèi)可以有構(gòu)造器 | 接口不能有構(gòu)造器 |
訪問(wèn)修飾符 | 抽象類(lèi)中的方法可以是任意訪問(wèn)修飾符 | 接口方法默認(rèn)修飾符是public。并且不允許定義為 private 或者 protected |
多繼承 | 一個(gè)類(lèi)最多只能繼承一個(gè)抽象類(lèi) | 一個(gè)類(lèi)可以實(shí)現(xiàn)多個(gè)接口 |
字段聲明 | 抽象類(lèi)的字段聲明可以是任意的 | 接口的字段默認(rèn)都是 static 和 final 的 |
備注:Java8中接口中引入默認(rèn)方法和靜態(tài)方法,以此來(lái)減少抽象類(lèi)和接口之間 的差異。
現(xiàn)在,我們可以為接口提供默認(rèn)實(shí)現(xiàn)的方法了,并且不用強(qiáng)制子類(lèi)來(lái)實(shí)現(xiàn)它。 接口和抽象類(lèi)各有優(yōu)缺點(diǎn),在接口和抽象類(lèi)的選擇上,必須遵守這樣一個(gè)原則:
- 行為模型應(yīng)該總是通過(guò)接口而不是抽象類(lèi)定義,所以通常是優(yōu)先選用接口,盡量 少用抽象類(lèi)。
- 選擇抽象類(lèi)的時(shí)候通常是如下情況:需要定義子類(lèi)的行為,又要為子類(lèi)提供通用 的功能。
普通類(lèi)和抽象類(lèi)有哪些區(qū)別?
- 普通類(lèi)不能包含抽象方法,抽象類(lèi)可以包含抽象方法。
- 抽象類(lèi)不能直接實(shí)例化,普通類(lèi)可以直接實(shí)例化。
抽象類(lèi)能使用 final 修飾嗎?
不能,定義抽象類(lèi)就是讓其他類(lèi)繼承的,如果定義為 final 該類(lèi)就不能被繼承, 這樣彼此就會(huì)產(chǎn)生矛盾,所以 final 不能修飾抽象類(lèi)
創(chuàng)建一個(gè)對(duì)象用什么關(guān)鍵字?對(duì)象實(shí)例與對(duì)象引用有何不同?
new關(guān)鍵字,new創(chuàng)建對(duì)象實(shí)例(對(duì)象實(shí)例在堆內(nèi)存中),對(duì)象引用指向?qū)ο髮?shí) 例(對(duì)象引用存放在棧內(nèi)存中)。一個(gè)對(duì)象引用可以指向0個(gè)或1個(gè)對(duì)象(一根 繩子可以不系氣球,也可以系一個(gè)氣球);一個(gè)對(duì)象可以有n個(gè)引用指向它(可以 用n條繩子系住一個(gè)氣球)
五.變量與方法
成員變量與局部變量的區(qū)別有哪些
變量:在程序執(zhí)行的過(guò)程中,在某個(gè)范圍內(nèi)其值可以發(fā)生改變的量。從本質(zhì)上 講,變量其實(shí)是內(nèi)存中的一小塊區(qū)域 成員變量:方法外部,類(lèi)內(nèi)部定義的變量 局部變量:類(lèi)的方法中的變量。 成員變量和局部變量的區(qū)別
作用域
成員變量:針對(duì)整個(gè)類(lèi)有效。
局部變量:只在某個(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)初始值,使用前必須賦值。
使用原則
在使用變量時(shí)需要遵循的原則為:就近原則 首先在局部范圍找,有就使用;接著在成員位置找。
在Java中定義一個(gè)不做事且沒(méi)有參數(shù)的構(gòu)造方法的作用
Java程序在執(zhí)行子類(lèi)的構(gòu)造方法之前,如果沒(méi)有用super()來(lái)調(diào)用父類(lèi)特定的構(gòu) 造方法,則會(huì)調(diào)用父類(lèi)中“沒(méi)有參數(shù)的構(gòu)造方法”。因此,如果父類(lèi)中只定義了 有參數(shù)的構(gòu)造方法,而在子類(lèi)的構(gòu)造方法中又沒(méi)有用super()來(lái)調(diào)用父類(lèi)中特定 的構(gòu)造方法,則編譯時(shí)將發(fā)生錯(cuò)誤,因?yàn)镴ava程序在父類(lèi)中找不到?jīng)]有參數(shù)的構(gòu) 造方法可供執(zhí)行。解決辦法是在父類(lèi)里加上一個(gè)不做事且沒(méi)有參數(shù)的構(gòu)造方法。
在調(diào)用子類(lèi)構(gòu)造方法之前會(huì)先調(diào)用父類(lèi)沒(méi)有參數(shù)的構(gòu)造方法,其 目的是?
幫助子類(lèi)做初始化工作。
一個(gè)類(lèi)的構(gòu)造方法的作用是什么?若一個(gè)類(lèi)沒(méi)有聲明構(gòu)造方法, 改程序能正確執(zhí)行嗎?為什么?
主要作用是完成對(duì)類(lèi)對(duì)象的初始化工作。可以執(zhí)行。因?yàn)橐粋€(gè)類(lèi)即使沒(méi)有聲明構(gòu) 造方法也會(huì)有默認(rèn)的不帶參數(shù)的構(gòu)造方法。
構(gòu)造方法有哪些特性?
名字與類(lèi)名相同;
沒(méi)有返回值,但不能用void聲明構(gòu)造函數(shù);
生成類(lèi)的對(duì)象時(shí)自動(dòng)執(zhí)行,無(wú)需調(diào)用。
靜態(tài)變量和實(shí)例變量區(qū)別
靜態(tài)變量: 靜態(tài)變量由于不屬于任何實(shí)例對(duì)象,屬于類(lèi)的,所以在內(nèi)存中只會(huì) 有一份,在類(lèi)的加載過(guò)程中,JVM只為靜態(tài)變量分配一次內(nèi)存空間。
實(shí)例變量: 每次創(chuàng)建對(duì)象,都會(huì)為每個(gè)對(duì)象分配成員變量?jī)?nèi)存空間,實(shí)例變量 是屬于實(shí)例對(duì)象的,在內(nèi)存中,創(chuàng)建幾次對(duì)象,就有幾份成員變量。
靜態(tài)變量與普通變量區(qū)別
static變量也稱(chēng)作靜態(tài)變量,靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有 的對(duì)象所共享,在內(nèi)存中只有一個(gè)副本,它當(dāng)且僅當(dāng)在類(lèi)初次加載時(shí)會(huì)被初始 化。而非靜態(tài)變量是對(duì)象所擁有的,在創(chuàng)建對(duì)象的時(shí)候被初始化,存在多個(gè)副 本,各個(gè)對(duì)象擁有的副本互不影響。
還有一點(diǎn)就是static成員變量的初始化順序按照定義的順序進(jìn)行初始化。
靜態(tài)方法和實(shí)例方法有何不同?
靜態(tài)方法和實(shí)例方法的區(qū)別主要體現(xiàn)在兩個(gè)方面:
-
在外部調(diào)用靜態(tài)方法時(shí),可以使用"類(lèi)名.方法名"的方式,也可以使 用"對(duì)象名.方法名"的方式。而實(shí)例方法只有后面這種方式。也就是說(shuō),調(diào) 用靜態(tài)方法可以無(wú)需創(chuàng)建對(duì)象。
-
靜態(tài)方法在訪問(wèn)本類(lèi)的成員時(shí),只允許訪問(wèn)靜態(tài)成員(即靜態(tài)成員變量 和靜態(tài)方法),而不允許訪問(wèn)實(shí)例成員變量和實(shí)例方法;實(shí)例方法則無(wú)此 限制
在一個(gè)靜態(tài)方法內(nèi)調(diào)用一個(gè)非靜態(tài)成員為什么是非法的?
由于靜態(tài)方法可以不通過(guò)對(duì)象進(jìn)行調(diào)用,因此在靜態(tài)方法里,不能調(diào)用其他非靜 態(tài)變量,也不可以訪問(wèn)非靜態(tài)變量成員。
什么是方法的返回值?返回值的作用是什么?
方法的返回值是指我們獲取到的某個(gè)方法體中的代碼執(zhí)行后產(chǎn)生的結(jié)果?。ㄇ疤?是該方法可能產(chǎn)生結(jié)果)。返回值的作用:接收出結(jié)果,使得它可以用于其他的 操作!
六.內(nèi)部類(lèi)
什么是內(nèi)部類(lèi)?
在Java中,可以將一個(gè)類(lèi)的定義放在另外一個(gè)類(lèi)的定義內(nèi)部,這就是內(nèi)部類(lèi)。內(nèi) 部類(lèi)本身就是類(lèi)的一個(gè)屬性,與其他屬性定義方式一致。
內(nèi)部類(lèi)的分類(lèi)有哪些
內(nèi)部類(lèi)可以分為四種:成員內(nèi)部類(lèi)、局部?jī)?nèi)部類(lèi)、匿名內(nèi)部類(lèi)和靜態(tài)內(nèi)部類(lèi)。
靜態(tài)內(nèi)部類(lèi)
定義在類(lèi)內(nèi)部的靜態(tài)類(lèi),就是靜態(tài)內(nèi)部類(lèi)。
1 public class Outer {
2
3 private static int radius = 1;
4
5 static class StaticInner {
6 public void visit() {
7 System.out.println("visit outer static variable:" + radius);
8 }
9 }
10 }
靜態(tài)內(nèi)部類(lèi)可以訪問(wèn)外部類(lèi)所有的靜態(tài)變量,而不可訪問(wèn)外部類(lèi)的非靜態(tài)變量; 靜態(tài)內(nèi)部類(lèi)的創(chuàng)建方式,new 外部類(lèi).靜態(tài)內(nèi)部類(lèi)(),如下:
1 Outer.StaticInner inner = new Outer.StaticInner();
2 inner.visit
成員內(nèi)部類(lèi)
定義在類(lèi)內(nèi)部,成員位置上的非靜態(tài)類(lèi),就是成員內(nèi)部類(lèi)。
1 public class Outer {
2
3 private static int radius = 1;
4 private int count =2;
5
6 class Inner {
7 public void visit() {
8 System.out.println("visit outer static variable:" + radius);
9 System.out.println("visit outer variable:" + count);
10 }
11 }
12 }
成員內(nèi)部類(lèi)可以訪問(wèn)外部類(lèi)所有的變量和方法,包括靜態(tài)和非靜態(tài),私有和公 有。成員內(nèi)部類(lèi)依賴(lài)于外部類(lèi)的實(shí)例,它的創(chuàng)建方式外部類(lèi)實(shí)例.new 內(nèi)部類(lèi)(),如 下:
1 Outer outer = new Outer();
2 Outer.Inner inner = outer.new Inner();
3 inner.visit();
局部?jī)?nèi)部類(lèi)
定義在方法中的內(nèi)部類(lèi),就是局部?jī)?nèi)部類(lèi)
1 public class Outer {
2
3 private int out_a = 1;
4 private static int STATIC_b = 2;
5
6 public void testFunctionClass(){
7 int inner_c =3;
8 class Inner {
9 private void fun(){
10 System.out.println(out_a);
11 System.out.println(STATIC_b);
12 System.out.println(inner_c);
13 }
14 }
15 Inner inner = new Inner();
16 inner.fun();
17 }
18 public static void testStaticFunctionClass(){
19 int d =3;
20 class Inner {
21 private void fun(){
22 // System.out.println(out_a); 編譯錯(cuò)誤,定義在靜態(tài)方法中的局部類(lèi)不可以訪問(wèn)外
部類(lèi)的實(shí)例變量
23 System.out.println(STATIC_b);
24 System.out.println(d);
25 }
26 }
27 Inner inner = new Inner();
28 inner.fun();
29 }
30 }
定義在實(shí)例方法中的局部類(lèi)可以訪問(wèn)外部類(lèi)的所有變量和方法,定義在靜態(tài)方法 中的局部類(lèi)只能訪問(wèn)外部類(lèi)的靜態(tài)變量和方法。局部?jī)?nèi)部類(lèi)的創(chuàng)建方式,在對(duì)應(yīng) 方法內(nèi),new 內(nèi)部類(lèi)(),如下:
1 public static void testStaticFunctionClass(){
2 class Inner {
3 }
4 Inner inner = new Inner();
5 }
匿名內(nèi)部類(lèi)
匿名內(nèi)部類(lèi)就是沒(méi)有名字的內(nèi)部類(lèi),日常開(kāi)發(fā)中使用的比較多。
1 public class Outer {
2
3 private void test(final int i) {
4 new Service() {
5 public void method() {
6 for (int j = 0; j < i; j++) {
7 System.out.println("匿名內(nèi)部類(lèi)" );
8 }
9 }
10 }.method();
11 }
12 }
13 //匿名內(nèi)部類(lèi)必須繼承或?qū)崿F(xiàn)一個(gè)已有的接口
14 interface Service{
15 void method();
16 }
除了沒(méi)有名字,匿名內(nèi)部類(lèi)還有以下特點(diǎn):
- 匿名內(nèi)部類(lèi)必須繼承一個(gè)抽象類(lèi)或者實(shí)現(xiàn)一個(gè)接口。
- 匿名內(nèi)部類(lèi)不能定義任何靜態(tài)成員和靜態(tài)方法。
- 當(dāng)所在的方法的形參需要被匿名內(nèi)部類(lèi)使用時(shí),必須聲明為 final。
- 匿名內(nèi)部類(lèi)不能是抽象的,它必須要實(shí)現(xiàn)繼承的類(lèi)或者實(shí)現(xiàn)的接口的所有抽象方 法。
匿名內(nèi)部類(lèi)創(chuàng)建方式:
1 new 類(lèi)/接口{
2 //匿名內(nèi)部類(lèi)實(shí)現(xiàn)部分
3 }
內(nèi)部類(lèi)的優(yōu)點(diǎn)
我們?yōu)槭裁匆褂脙?nèi)部類(lèi)呢?因?yàn)樗幸韵聝?yōu)點(diǎn):
- 一個(gè)內(nèi)部類(lèi)對(duì)象可以訪問(wèn)創(chuàng)建它的外部類(lèi)對(duì)象的內(nèi)容,包括私有數(shù)據(jù)!
- 內(nèi)部類(lèi)不為同一包的其他類(lèi)所見(jiàn),具有很好的封裝性;
- 內(nèi)部類(lèi)有效實(shí)現(xiàn)了“多重繼承”,優(yōu)化 java 單繼承的缺陷。
- 匿名內(nèi)部類(lèi)可以很方便的定義回調(diào)。
內(nèi)部類(lèi)有哪些應(yīng)用場(chǎng)景
-
一些多算法場(chǎng)合
-
解決一些非面向?qū)ο蟮恼Z(yǔ)句塊。
-
適當(dāng)使用內(nèi)部類(lèi),使得代碼更加靈活和富有擴(kuò)展性。
-
當(dāng)某個(gè)類(lèi)除了它的外部類(lèi),不再被其他的類(lèi)使用時(shí)。
局部?jī)?nèi)部類(lèi)和匿名內(nèi)部類(lèi)訪問(wèn)局部變量的時(shí)候,為什么變量必須 要加上final?
局部?jī)?nèi)部類(lèi)和匿名內(nèi)部類(lèi)訪問(wèn)局部變量的時(shí)候,為什么變量必須要加上final呢? 它內(nèi)部原理是什么呢?
先看這段代碼:
1 public class Outer {
2
3 void outMethod(){
4 final int a =10;
5 class Inner {
6 void innerMethod(){
7 System.out.println(a);
8 }
9
10 }
11 }
12 }
以上例子,為什么要加final呢?是因?yàn)樯芷诓灰恢拢?局部變量直接存儲(chǔ)在 棧中,當(dāng)方法執(zhí)行結(jié)束后,非final的局部變量就被銷(xiāo)毀。而局部?jī)?nèi)部類(lèi)對(duì)局部變 量的引用依然存在,如果局部?jī)?nèi)部類(lèi)要調(diào)用局部變量時(shí),就會(huì)出錯(cuò)。加了final, 可以確保局部?jī)?nèi)部類(lèi)使用的變量與外層的局部變量區(qū)分開(kāi),解決了這個(gè)問(wèn)題。
內(nèi)部類(lèi)相關(guān),看程序說(shuō)出運(yùn)行結(jié)果
1 public class Outer {
2 private int age = 12;
3
4 class Inner {
5 private int age = 13;
6 public void print() {
7 int age = 14;
8 System.out.println("局部變量:" + age);
9 System.out.println("內(nèi)部類(lèi)變量:" + this.age);
10 System.out.println("外部類(lèi)變量:" + Outer.this.age);
11 }
12 }
13
14 public static void main(String[] args) {
15 Outer.Inner in = new Outer().new Inner();
16 in.print();
17 }
18
19 }
運(yùn)行結(jié)果:
1 局部變量:14
2 內(nèi)部類(lèi)變量:13
3 外部類(lèi)變量:12
七.重寫(xiě)與重載
構(gòu)造器(constructor)是否可被重寫(xiě)(override)
構(gòu)造器不能被繼承,因此不能被重寫(xiě),但可以被重載。
重載(Overload)和重寫(xiě)(Override)的區(qū)別。重載的方法能 否根據(jù)返回類(lèi)型進(jìn)行區(qū)分?
方法的重載和重寫(xiě)都是實(shí)現(xiàn)多態(tài)的方式,區(qū)別在于前者實(shí)現(xiàn)的是編譯時(shí)的多態(tài) 性,而后者實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性。
重載:發(fā)生在同一個(gè)類(lèi)中,方法名相同參數(shù)列表不同(參數(shù)類(lèi)型不同、個(gè)數(shù)不 同、順序不同),與方法返回值和訪問(wèn)修飾符無(wú)關(guān),即重載的方法不能根據(jù)返回 類(lèi)型進(jìn)行區(qū)分
重寫(xiě):發(fā)生在父子類(lèi)中,方法名、參數(shù)列表必須相同,返回值小于等于父類(lèi),拋 出的異常小于等于父類(lèi),訪問(wèn)修飾符大于等于父類(lèi)(里氏代換原則);如果父類(lèi) 方法訪問(wèn)修飾符為private則子類(lèi)中就不是重寫(xiě)。
八.對(duì)象相等判斷
== 和 equals 的區(qū)別是什么
== : 它的作用是判斷兩個(gè)對(duì)象的地址是不是相等。即,判斷兩個(gè)對(duì)象是不是同 一個(gè)對(duì)象。(基本數(shù)據(jù)類(lèi)型 == 比較的是值,引用數(shù)據(jù)類(lèi)型 == 比較的是內(nèi)存地址)
equals() : 它的作用也是判斷兩個(gè)對(duì)象是否相等。但它一般有兩種使用情況: 情況1:類(lèi)沒(méi)有覆蓋 equals() 方法。則通過(guò) equals() 比較該類(lèi)的兩個(gè)對(duì)象時(shí), 等價(jià)于通過(guò)“==”比較這兩個(gè)對(duì)象。
情況2:類(lèi)覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來(lái)兩個(gè)對(duì)象 的內(nèi)容相等;若它們的內(nèi)容相等,則返回 true (即,認(rèn)為這兩個(gè)對(duì)象相等)。
舉個(gè)例子:
1 public class test1 {
2 public static void main(String[] args) {
3 String a = new String("ab"); // a 為一個(gè)引用
4 String b = new String("ab"); // b為另一個(gè)引用,對(duì)象的內(nèi)容一樣
5 String aa = "ab"; // 放在常量池中
6 String bb = "ab"; // 從常量池中查找
7 if (aa == bb) // true
8 System.out.println("aa==bb");
9 if (a == b) // false,非同一對(duì)象
10 System.out.println("a==b");
11 if (a.equals(b)) // true
12 System.out.println("aEQb");
13 if (42 == 42.0) { // true
14 System.out.println("true");
15 }
16 }
17 }
說(shuō)明:
- String中的equals方法是被重寫(xiě)過(guò)的,因?yàn)閛bject的equals方法是比較的對(duì)象的 內(nèi)存地址,而String的equals方法比較的是對(duì)象的值。
- 當(dāng)創(chuàng)建String類(lèi)型的對(duì)象時(shí),虛擬機(jī)會(huì)在常量池中查找有沒(méi)有已經(jīng)存在的值和要 創(chuàng)建的值相同的對(duì)象,如果有就把它賦給當(dāng)前引用。如果沒(méi)有就在常量池中重新創(chuàng)建 一個(gè)String對(duì)象。
hashCode 與 equals (重要)
HashSet如何檢查重復(fù)
兩個(gè)對(duì)象的 hashCode() 相同,則 equals() 也一定為 true,對(duì)嗎?
hashCode和equals方法的關(guān)系
面試官可能會(huì)問(wèn)你:“你重寫(xiě)過(guò) hashcode 和 equals 么,為什么重寫(xiě)equals時(shí) 必須重寫(xiě)hashCode方法?”
hashCode()介紹
hashCode() 的作用是獲取哈希碼,也稱(chēng)為散列碼;它實(shí)際上是返回一個(gè)int整 數(shù)。這個(gè)哈希碼的作用是確定該對(duì)象在哈希表中的索引位置。hashCode() 定義 在JDK的Object.java中,這就意味著Java中的任何類(lèi)都包含有hashCode()函數(shù)。
散列表存儲(chǔ)的是鍵值對(duì)(key-value),它的特點(diǎn)是:能根據(jù)“鍵”快速的檢索出 對(duì)應(yīng)的“值”。這其中就利用到了散列碼!(可以快速找到所需要的對(duì)象)
為什么要有 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ì)重新散列到其他位置。(摘自我的Java啟蒙書(shū)《Head first java》 第二版)。這樣我們就大大減少了 equals 的次數(shù),相應(yīng)就大大提高了執(zhí)行速 度。
hashCode()與equals()的相關(guān)規(guī)定
如果兩個(gè)對(duì)象相等,則hashcode一定也是相同的 兩個(gè)對(duì)象相等,對(duì)兩個(gè)對(duì)象分別調(diào)用equals方法都返回true 兩個(gè)對(duì)象有相同的hashcode值,它們也不一定是相等的
因此,equals 方法被覆蓋過(guò),則 hashCode 方法也必須被覆蓋
hashCode() 的默認(rèn)行為是對(duì)堆上的對(duì)象產(chǎn)生獨(dú)特值。如果沒(méi)有重寫(xiě)
hashCode(),則該 class 的兩個(gè)對(duì)象無(wú)論如何都不會(huì)相等(即使這兩個(gè)對(duì)象指 向相同的數(shù)據(jù))
對(duì)象的相等與指向他們的引用相等,兩者有什么不同?
對(duì)象的相等 比的是內(nèi)存中存放的內(nèi)容是否相等而 引用相等 比較的是他們指向的 內(nèi)存地址是否相等。
九.值傳遞
當(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ù))的一些專(zhuān)業(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)容。
下面通過(guò) 3 個(gè)例子來(lái)給大家說(shuō)明
example 1
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
11 public static void swap(int a, int b) {
12 int temp = a;
13 a = b;
14 b = temp;
15
16 System.out.println("a = " + a);
17 System.out.println("b = " + b);
18 }
結(jié)果:
1 a = 20
2 b = 10
3 num1 = 10
4 num2 = 20
解析:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-9kxuHrjo-1692506313325)(01-Java基礎(chǔ)知識(shí)面試題(2020最新版).assets/image-20201106190311218.png)]
在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ì)影響到原件本身。
通過(guò)上面例子,我們已經(jīng)知道了一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類(lèi)型的參數(shù),而 對(duì)象引用作為參數(shù)就不一樣,請(qǐng)看 example2.
example 2
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
8 public static void change(int[] array) {
9 // 將數(shù)組的第一個(gè)元素變?yōu)?
10 array[0] = 0;
11 }
結(jié)果:
1 1
2 0
解析:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-oIrslCIg-1692506313325)(01-Java基礎(chǔ)知識(shí)面試題(2020最新版).assets/image-20201106190416793.png)]
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)用。有些程序員(甚至本書(shū)的作者)認(rèn)為Java程序設(shè)計(jì)語(yǔ)言對(duì)對(duì)象 采用的是引用調(diào)用,實(shí)際上,這種理解是不對(duì)的。由于這種誤解具有一定的普遍 性,所以下面給出一個(gè)反例來(lái)詳細(xì)地闡述一下這個(gè)問(wèn)題。
example 3
1 public class Test {
2
3 public static void main(String[] args) {
4 // TODO Auto‐generated method stub
5 Student s1 = new Student("小張");
6 Student s2 = new Student("小李");
7 Test.swap(s1, s2);
8 System.out.println("s1:" + s1.getName());
9 System.out.println("s2:" + s2.getName());
10 }
11
12 public static void swap(Student x, Student y) {
13 Student temp = x;
14 x = y;
15 y = temp;
16 System.out.println("x:" + x.getName());
17 System.out.println("y:" + y.getName());
18 }
19 }
結(jié)果:
1 x:小李
2 y:小張
3 s1:小張
4 s2:小李
解析:
交換之前:
交換之后:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-z5tEDeCP-1692506313326)(01-Java基礎(chǔ)知識(shí)面試題(2020最新版).assets/image-20201106190619059.png)]
通過(guò)上面兩張圖可以很清晰的看出: 方法并沒(méi)有改變存儲(chǔ)在變量 s1 和 s2 中的 對(duì)象引用。swap方法的參數(shù)x和y被初始化為兩個(gè)對(duì)象引用的拷貝,這個(gè)方法交 換的是這兩個(gè)拷貝
總結(jié)
Java程序設(shè)計(jì)語(yǔ)言對(duì)對(duì)象采用的不是引用調(diào)用,實(shí)際上,對(duì)象引用是按值傳遞的。
下面再總結(jié)一下Java中方法參數(shù)的使用情況:
- 一個(gè)方法不能修改一個(gè)基本數(shù)據(jù)類(lèi)型的參數(shù)(即數(shù)值型或布爾型》
- 一個(gè)方法可以改變一個(gè)對(duì)象參數(shù)的狀態(tài)。
- 一個(gè)方法不能讓對(duì)象參數(shù)引用一個(gè)新的對(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)存空間)。
十.Java包
JDK 中常用的包有哪些
- java.lang:這個(gè)是系統(tǒng)的基礎(chǔ)類(lèi);
- java.io:這里面是所有輸入輸出有關(guān)的類(lèi),比如文件操作等;
- java.nio:為了完善 io 包中的功能,提高 io 包中性能而寫(xiě)的一個(gè)新包;
- java.net:這里面是與網(wǎng)絡(luò)有關(guān)的類(lèi);
- java.util:這個(gè)是系統(tǒng)輔助類(lèi),特別是集合類(lèi);
- java.sql:這個(gè)是數(shù)據(jù)庫(kù)操作的類(lèi)。
import java和javax有什么區(qū)別
剛開(kāi)始的時(shí)候 JavaAPI 所必需的包是 java 開(kāi)頭的包,javax 當(dāng)時(shí)只是擴(kuò)展 API 包來(lái)說(shuō)使用。然而隨著時(shí)間的推移,javax 逐漸的擴(kuò)展成為 Java API 的組成部 分。但是,將擴(kuò)展從 javax 包移動(dòng)到 java 包將是太麻煩了,最終會(huì)破壞一堆現(xiàn) 有的代碼。因此,最終決定 javax 包將成為標(biāo)準(zhǔn)API的一部分。 所以,實(shí)際上java和javax沒(méi)有區(qū)別。這都是一個(gè)名字。
十一.IO流
java 中 IO 流分為幾種?
按照流的流向分,可以分為輸入流和輸出流; 按照操作單元?jiǎng)澐?,可以劃分為字?jié)流和字符流; 按照流的角色劃分為節(jié)點(diǎn)流和處理流。 Java Io流共涉及40多個(gè)類(lèi),這些類(lèi)看上去很雜亂,但實(shí)際上很有規(guī)則,而且彼 此之間存在非常緊密的聯(lián)系, Java I0流的40多個(gè)類(lèi)都是從如下4個(gè)抽象類(lèi)基類(lèi) 中派生出來(lái)的。
- InputStream/Reader: 所有的輸入流的基類(lèi),前者是字節(jié)輸入流,后者是字符 輸入流。
- OutputStream/Writer: 所有輸出流的基類(lèi),前者是字節(jié)輸出流,后者是字符輸 出流。
按操作方式分類(lèi)結(jié)構(gòu)圖:
IO-操作方式分類(lèi)按操作對(duì)象分類(lèi)結(jié)構(gòu)圖:
BIO,NIO,AIO 有什么區(qū)別?
簡(jiǎn)答
-
BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統(tǒng) IO,它的特點(diǎn)是模式簡(jiǎn)單使用方便,并發(fā)處理能力低。
-
NIO:Non IO 同步非阻塞 IO,是傳統(tǒng) IO 的升級(jí),客戶端和服務(wù)器端通過(guò)
Channel(通道)通訊,實(shí)現(xiàn)了多路復(fù)用。 -
AIO:Asynchronous IO 是 NIO 的升級(jí),也叫 NIO2,實(shí)現(xiàn)了異步非堵塞 IO
,異步 IO 的操作基于事件和回調(diào)機(jī)制。
詳細(xì)回答
-
BIO (Blocking I/O): 同步阻塞I/O模式,數(shù)據(jù)的讀取寫(xiě)入必須阻塞在一個(gè)線程內(nèi)等待其完成。在活動(dòng)連接數(shù)不是特別高(小于單機(jī)1000)的情況下,這種模型是比較不錯(cuò)的,可以讓每一個(gè)連接專(zhuān)注于自己的 I/O 并且編程模型簡(jiǎn)單,也不用過(guò)多考慮系統(tǒng)的過(guò)載、限流等問(wèn)題。線程池本身就是一個(gè)天然的漏斗,可以緩沖一些系統(tǒng)處理不了的連接或請(qǐng)求。但是,當(dāng)面對(duì)十萬(wàn)甚至百萬(wàn)級(jí)連接的時(shí)候,傳統(tǒng)的 BIO 模型是無(wú)能為力的。因此,我們需要一種更高效的 I/O 處理模型來(lái)應(yīng)對(duì)更高的并發(fā)量。
-
NIO (New I/O): NIO是一種同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,對(duì)應(yīng) java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的 N可以理解為Non-blocking,不單純是New。它支持面向緩沖的,基于通道的I/O操作方法。 NIO提供了與傳統(tǒng)BIO模型中的 Socket 和 ServerSocket 相對(duì)應(yīng)的 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實(shí)現(xiàn),兩種通道都支持阻塞和非阻塞兩種模式。阻塞模式使用就像傳統(tǒng)中的支持一樣,比較簡(jiǎn)單,但是性能和可靠性都不好;非阻塞模式正好與之相反。對(duì)于低負(fù)載、低并發(fā)的應(yīng)用程序,可以使用同步阻塞I/O來(lái)提升開(kāi)發(fā)速率和更好的維護(hù)性;對(duì)于高負(fù)載、高并發(fā)的(網(wǎng)絡(luò))應(yīng)用,應(yīng)使用 NIO 的非阻塞模式來(lái)開(kāi)發(fā)
-
AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改進(jìn)版 NIO 2,它是異步非阻塞的IO模型。異步 IO 是基于事件和回調(diào)機(jī)制實(shí)現(xiàn)的,也就是應(yīng)用操作之后會(huì)直接返回,不會(huì)堵塞在那里,當(dāng)后臺(tái)處理完成,操作系統(tǒng)會(huì)通知相應(yīng)的線程進(jìn)行后續(xù)的操作。AIO 是異步IO的縮寫(xiě),雖然 NIO 在網(wǎng)絡(luò)操作中,提供了非阻塞的方法,但是 NIO 的 IO 行為還是同步的。對(duì)于 NIO 來(lái)說(shuō),我們的業(yè)務(wù)線程是在 IO 操作準(zhǔn)備好時(shí),得到通知,接著就由這個(gè)線程自行進(jìn)行 IO 操作,IO操作本身是同步的。查閱網(wǎng)上相關(guān)資料,我發(fā)現(xiàn)就目前來(lái)說(shuō) AIO 的應(yīng)用還不是很廣泛,Netty 之前也嘗試使用過(guò) AIO,不過(guò)又放棄了。
Files的常用方法都有哪些?
- Files. exists():檢測(cè)文件路徑是否存在。
- Files. createFile():創(chuàng)建文件。
- Files. createDirectory():創(chuàng)建文件夾。
- Files. delete():刪除一個(gè)文件或目錄。
- Files. copy():復(fù)制文件。
- Files. move():移動(dòng)文件。
- Files. size():查看文件個(gè)數(shù)。
- Files. read():讀取文件。
- Files. write():寫(xiě)入文件。
十二.反射
什么是反射機(jī)制?
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類(lèi),都能夠知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱(chēng)為java語(yǔ)言的反射機(jī)制。
靜態(tài)編譯和動(dòng)態(tài)編譯
**靜態(tài)編譯:**在編譯時(shí)確定類(lèi)型,綁定對(duì)象
**動(dòng)態(tài)編譯:**運(yùn)行時(shí)確定類(lèi)型,綁定對(duì)象
反射機(jī)制優(yōu)缺點(diǎn)
優(yōu)點(diǎn): 運(yùn)行期類(lèi)型的判斷,動(dòng)態(tài)加載類(lèi),提高代碼靈活度。
缺點(diǎn): 性能瓶頸:反射相當(dāng)于一系列解釋操作,通知 JVM 要做的事情,性能
比直接的java代碼要慢很多。
反射機(jī)制的應(yīng)用場(chǎng)景有哪些?
反射是框架設(shè)計(jì)的靈魂。
在我們平時(shí)的項(xiàng)目開(kāi)發(fā)過(guò)程中,基本上很少會(huì)直接使用到反射機(jī)制,但這不能說(shuō)明反射機(jī)制沒(méi)有用,實(shí)際上有很多設(shè)計(jì)、開(kāi)發(fā)都與反射機(jī)制有關(guān),例如模塊化的開(kāi)發(fā),通過(guò)反射去調(diào)用對(duì)應(yīng)的字節(jié)碼;動(dòng)態(tài)代理設(shè)計(jì)模式也采用了反射機(jī)制,還有我們?nèi)粘J褂玫?Spring/Hibernate 等框架也大量使用到了反射機(jī)制。
舉例:①我們?cè)谑褂肑DBC連接數(shù)據(jù)庫(kù)時(shí)使用Class.forName()通過(guò)反射加載數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序;②Spring框架也用到很多反射機(jī)制, 經(jīng)典的就是xml的配置模式。Spring 通過(guò) XML 配置模式裝載 Bean 的過(guò)程:1) 將程序內(nèi)所有 XML 或 Properties 配置文件加載入內(nèi)存中; 2)Java類(lèi)里面解析xml或properties里面的內(nèi)容,得到對(duì)應(yīng)實(shí)體類(lèi)的字節(jié)碼字符串以及相關(guān)的屬性信息; 3)使用反射機(jī)制,根據(jù)這個(gè)字符串獲得某個(gè)類(lèi)的Class實(shí)例; 4)動(dòng)態(tài)配置實(shí)例的屬性
Java獲取反射的三種方法
1.通過(guò)new對(duì)象實(shí)現(xiàn)反射機(jī)制
2.通過(guò)路徑實(shí)現(xiàn)反射機(jī)制
3.通過(guò)類(lèi)名實(shí)現(xiàn)反射機(jī)制
1 public class Student {
2 private int id;
3 String name;
4 protected boolean sex;
5 public float score;
6 }
1 public class Get {
2 //獲取反射機(jī)制三種方式
3 public static void main(String[] args) throws ClassNotFoundException {
4 //方式一(通過(guò)建立對(duì)象)
5 Student stu = new Student();
6 Class classobj1 = stu.getClass();
7 System.out.println(classobj1.getName());
8 //方式二(所在通過(guò)路徑‐相對(duì)路徑)
9 Class classobj2 = Class.forName("fanshe.Student");
10 System.out.println(classobj2.getName());
11 //方式三(通過(guò)類(lèi)名)
12 Class classobj3 = Student.class;
13 System.out.println(classobj3.getName());
14 }
15 }
十三.網(wǎng)絡(luò)編程
網(wǎng)絡(luò)編程的面試題可以查看我的這篇文章重學(xué)TCP/IP協(xié)議和三次握手四次揮手,內(nèi)容不僅包括TCP/IP協(xié)議和三次握手四次揮手的知識(shí),還包括計(jì)算機(jī)網(wǎng)絡(luò)
體系結(jié)構(gòu),HTTP協(xié)議,get請(qǐng)求和post請(qǐng)求區(qū)別,session和cookie的區(qū)別等,歡迎大家閱讀。
十四.常用API
String相關(guān)
字符型常量和字符串常量的區(qū)別
-
形式上: 字符常量是單引號(hào)引起的一個(gè)字符 字符串常量是雙引號(hào)引起的若干個(gè)字符
-
含義上: 字符常量相當(dāng)于一個(gè)整形值(ASCII值),可以參加表達(dá)式運(yùn)算 字符串常量代表一個(gè)地址值(該字符串在內(nèi)存中存放位置)
-
占內(nèi)存大小 字符常量只占一個(gè)字節(jié) 字符串常量占若干個(gè)字節(jié)(至少一個(gè)字符結(jié)束標(biāo)志)
什么是字符串常量池?
字符串常量池位于堆內(nèi)存中,專(zhuān)門(mén)用來(lái)存儲(chǔ)字符串常量,可以提高內(nèi)存的使用率,避免開(kāi)辟多塊空間存儲(chǔ)相同的字符串,在創(chuàng)建字符串時(shí) JVM 會(huì)首先檢查字符串常量池,如果該字符串已經(jīng)存在池中,則返回它的引用,如果不存在,則實(shí)例化一個(gè)字符串放到池中,并返回其引用。
String 是最基本的數(shù)據(jù)類(lèi)型嗎
不是。Java 中的基本數(shù)據(jù)類(lèi)型只有 8 個(gè) :byte、short、int、long、float、 double、char、boolean;除了基本類(lèi)型(primitive type),剩下的都是引用類(lèi)型(referencetype),Java 5 以后引入的枚舉類(lèi)型也算是一種比較特殊的引用類(lèi)型。
這是很基礎(chǔ)的東西,但是很多初學(xué)者卻容易忽視,Java 的 8 種基本數(shù)據(jù)類(lèi)型中不包括 String,基本數(shù)據(jù)類(lèi)型中用來(lái)描述文本數(shù)據(jù)的是 char,但是它只能表示單個(gè)字符,比如 ‘a(chǎn)’,‘好’ 之類(lèi)的,如果要描述一段文本,就需要用多個(gè)
char 類(lèi)型的變量,也就是一個(gè) char 類(lèi)型數(shù)組,比如“你好” 就是長(zhǎng)度為2的數(shù)組 char[] chars = {‘你’,‘好’};
但是使用數(shù)組過(guò)于麻煩,所以就有了 String,String 底層就是一個(gè) char 類(lèi)型的數(shù)組,只是使用的時(shí)候開(kāi)發(fā)者不需要直接操作底層數(shù)組,用更加簡(jiǎn)便的方式即可完成對(duì)字符串的使用。
String有哪些特性
- 不變性:String 是只讀字符串,是一個(gè)典型的 immutable 對(duì)象,對(duì)它進(jìn)行任何操作,其實(shí)都是創(chuàng)建一個(gè)新的對(duì)象,再把引用指向該對(duì)象。不變模式的主要作用在于當(dāng)一個(gè)對(duì)象需要被多線程共享并頻繁訪問(wèn)時(shí),可以保證數(shù)據(jù)的一致性。
- 常量池優(yōu)化:String 對(duì)象創(chuàng)建之后,會(huì)在字符串常量池中進(jìn)行緩存,如果下次創(chuàng)建同樣的對(duì)象時(shí),會(huì)直接返回緩存的引用。
- final:使用 final 來(lái)定義 String 類(lèi),表示 String 類(lèi)不能被繼承,提高了系統(tǒng)的安全性。
String為什么是不可變的嗎?
簡(jiǎn)單來(lái)說(shuō)就是String類(lèi)利用了final修飾的char類(lèi)型數(shù)組存儲(chǔ)字符,源碼如下圖所以:
1 /** The value is used for character storage. */
2 private final char value[];
String真的是不可變的嗎?
我覺(jué)得如果別人問(wèn)這個(gè)問(wèn)題的話,回答不可變就可以了。 下面只是給大家看兩個(gè)有代表性的例子:
- String不可變但不代表引用不可以變
1 String str = "Hello";
2 str = str + " World";
3 System.out.println("str=" + str);
結(jié)果:
1 str=Hello World
解析:
實(shí)際上,原來(lái)String的內(nèi)容是不變的,只是str由原來(lái)指向"Hello"的內(nèi)存地址轉(zhuǎn)為指向"Hello World"的內(nèi)存地址而已,也就是說(shuō)多開(kāi)辟了一塊內(nèi)存區(qū)域給"Hello World"字符串。
- 通過(guò)反射是可以修改所謂的“不可變”對(duì)象
1 // 創(chuàng)建字符串"Hello World", 并賦給引用s
2 String s = "Hello World";
3
4 System.out.println("s = " + s); // Hello World
5
6 // 獲取String類(lèi)中的value字段
7 Field valueFieldOfString = String.class.getDeclaredField("value");
8
9 // 改變value屬性的訪問(wèn)權(quán)限
10 valueFieldOfString.setAccessible(true);
11
12 // 獲取s對(duì)象上的value屬性的值
13 char[] value = (char[]) valueFieldOfString.get(s);
14
15 // 改變value所引用的數(shù)組中的第5個(gè)字符
16 value[5] = '_';
17
18 System.out.println("s = " + s); // Hello_World
結(jié)果:
1 s = Hello World
2 s = Hello_World
解析:
用反射可以訪問(wèn)私有成員, 然后反射出String對(duì)象中的value屬性, 進(jìn)而改變通過(guò)獲得的value引用改變數(shù)組的結(jié)構(gòu)。但是一般我們不會(huì)這么做,這里只是簡(jiǎn)單提一下有這個(gè)東西。
是否可以繼承 String 類(lèi)
String 類(lèi)是 final 類(lèi),不可以被繼承。
String str="i"與 String str=new String(“i”)一樣嗎?不一樣,因?yàn)閮?nèi)存的分配方式不一樣。String str=“i"的方式,java 虛擬機(jī)會(huì)將其分配到常量池中;而 String str=new String(“i”) 則會(huì)被分到堆內(nèi)存中。 String s = new String(“xyz”);創(chuàng)建了幾個(gè)字符串對(duì)象兩個(gè)對(duì)象,一個(gè)是靜態(tài)區(qū)的"xyz”,一個(gè)是用new創(chuàng)建在堆上的對(duì)象。
1 String str1 = "hello"; //str1指向靜態(tài)區(qū)
2 String str2 = new String("hello"); //str2指向堆上的對(duì)象
3 String str3 = "hello";
4 String str4 = new String("hello");
5 System.out.println(str1.equals(str2)); //true
6 System.out.println(str2.equals(str4)); //true
7 System.out.println(str1 == str3); //true
8 System.out.println(str1 == str2); //false
9 System.out.println(str2 == str4); //false
10 System.out.println(str2 == "hello"); //false
11 str2 = str1;
12 System.out.println(str2 == "hello"); //true
如何將字符串反轉(zhuǎn)?使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。示例代碼:
1 // StringBuffer reverse
2 StringBuffer stringBuffer = new StringBuffer();
3 stringBuffer. append("abcdefg");
4 System. out. println(stringBuffer. reverse()); // gfedcba
5 // StringBuilder reverse
6 StringBuilder stringBuilder = new StringBuilder();
7 stringBuilder. append("abcdefg");
8 System. out. println(stringBuilder. reverse()); // gfedcba
數(shù)組有沒(méi)有 length()方法?String 有沒(méi)有 length()方法
數(shù)組沒(méi)有 length()方法 ,有 length 的屬性。String 有 length()方法。 JavaScript中,獲得字符串的長(zhǎng)度是通過(guò) length 屬性得到的,這一點(diǎn)容易和 Java 混淆。
String 類(lèi)的常用方法都有那些?
- indexOf():返回指定字符的索引。
- charAt():返回指定索引處的字符。
- replace():字符串替換。
- trim():去除字符串兩端空白。
- split():分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。
- getBytes():返回字符串的 byte 類(lèi)型數(shù)組。
- length():返回字符串長(zhǎng)度。
- toLowerCase():將字符串轉(zhuǎn)成小寫(xiě)字母。
- toUpperCase():將字符串轉(zhuǎn)成大寫(xiě)字符。
- substring():截取字符串。
- equals():字符串比較。
在使用 HashMap 的時(shí)候,用 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ì)象更快。
String和StringBuffer、StringBuilder的區(qū)別是什么?String 為什么是不可變的
可變性
String類(lèi)中使用字符數(shù)組保存字符串,private final char value[],所以 string對(duì)象是不可變的。StringBuilder與StringBuffer都繼承自
AbstractStringBuilder類(lèi),在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,char[] value,這兩種對(duì)象都是可變的。線程安全性
String中的對(duì)象是不可變的,也就可以理解為常量,線程安全。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類(lèi),定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對(duì)方法加了同步鎖或者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder并沒(méi)有對(duì)方法進(jìn)行加同步鎖,所以是非線程安全的。
性能
每次對(duì)String 類(lèi)型進(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
Date相關(guān)
包裝類(lèi)相關(guān)
自動(dòng)裝箱與拆箱
裝箱:將基本類(lèi)型用它們對(duì)應(yīng)的引用類(lèi)型包裝起來(lái);
拆箱:將包裝類(lèi)型轉(zhuǎn)換為基本數(shù)據(jù)類(lèi)型; int 和 Integer 有什么區(qū)別
Java 是一個(gè)近乎純潔的面向?qū)ο缶幊陶Z(yǔ)言,但是為了編程的方便還是引入了基本數(shù)據(jù)類(lèi)型,但是為了能夠?qū)⑦@些基本數(shù)據(jù)類(lèi)型當(dāng)成對(duì)象操作,Java 為每一個(gè)基本數(shù)據(jù)類(lèi)型都引入了對(duì)應(yīng)的包裝類(lèi)型(wrapper class),int 的包裝類(lèi)就是 Integer,從 Java 5 開(kāi)始引入了自動(dòng)裝箱/拆箱機(jī)制,使得二者可以相互轉(zhuǎn)換。
Java 為每個(gè)原始類(lèi)型提供了包裝類(lèi)型:
原始類(lèi)型: boolean,char,byte,short,int,long,float,double 包裝類(lèi)型:Boolean,Character,Byte,Short,Integer,Long,F(xiàn)loat,
Double
Integer a= 127 與 Integer b = 127相等嗎
對(duì)于對(duì)象引用類(lèi)型:==比較的是對(duì)象的內(nèi)存地址。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-661454.html
對(duì)于基本數(shù)據(jù)類(lèi)型:比較的是值。如果整型字面量的值在-128到127之間,那么自動(dòng)裝箱時(shí)不會(huì)new新的Integer 對(duì)象,而是直接引用常量池中的Integer對(duì)象,超過(guò)范圍 a1b1的結(jié)果是false文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-661454.html
1 public static void main(String[] args) {
2 Integer a = new Integer(3);
3 Integer b = 3; // 將3自動(dòng)裝箱成Integer類(lèi)型
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類(lèi)型再和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
16 }
者對(duì)調(diào)用的方法加了同步鎖,所以是線程安全的。StringBuilder并沒(méi)有對(duì)方法進(jìn)行加同步鎖,所以是非線程安全的。
性能
每次對(duì)String 類(lèi)型進(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
Date相關(guān)
包裝類(lèi)相關(guān)
自動(dòng)裝箱與拆箱
裝箱:將基本類(lèi)型用它們對(duì)應(yīng)的引用類(lèi)型包裝起來(lái);
拆箱:將包裝類(lèi)型轉(zhuǎn)換為基本數(shù)據(jù)類(lèi)型; int 和 Integer 有什么區(qū)別
Java 是一個(gè)近乎純潔的面向?qū)ο缶幊陶Z(yǔ)言,但是為了編程的方便還是引入了基本數(shù)據(jù)類(lèi)型,但是為了能夠?qū)⑦@些基本數(shù)據(jù)類(lèi)型當(dāng)成對(duì)象操作,Java 為每一個(gè)基本數(shù)據(jù)類(lèi)型都引入了對(duì)應(yīng)的包裝類(lèi)型(wrapper class),int 的包裝類(lèi)就是 Integer,從 Java 5 開(kāi)始引入了自動(dòng)裝箱/拆箱機(jī)制,使得二者可以相互轉(zhuǎn)換。
Java 為每個(gè)原始類(lèi)型提供了包裝類(lèi)型:
原始類(lèi)型: boolean,char,byte,short,int,long,float,double 包裝類(lèi)型:Boolean,Character,Byte,Short,Integer,Long,F(xiàn)loat,
Double
Integer a= 127 與 Integer b = 127相等嗎
對(duì)于對(duì)象引用類(lèi)型:==比較的是對(duì)象的內(nèi)存地址。
對(duì)于基本數(shù)據(jù)類(lèi)型:比較的是值。如果整型字面量的值在-128到127之間,那么自動(dòng)裝箱時(shí)不會(huì)new新的Integer 對(duì)象,而是直接引用常量池中的Integer對(duì)象,超過(guò)范圍 a1b1的結(jié)果是false
1 public static void main(String[] args) {
2 Integer a = new Integer(3);
3 Integer b = 3; // 將3自動(dòng)裝箱成Integer類(lèi)型
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類(lèi)型再和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
16 }
到了這里,關(guān)于2023面試八股文 ——Java基礎(chǔ)知識(shí)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!