溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java基礎(chǔ)知識(shí)面試題有哪些

發(fā)布時(shí)間:2021-11-24 15:16:17 來(lái)源:億速云 閱讀:140 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“Java基礎(chǔ)知識(shí)面試題有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Java基礎(chǔ)知識(shí)面試題有哪些”吧!

Java概述

何為編程

編程就是讓計(jì)算機(jī)為解決某個(gè)問(wèn)題而使用某種程序設(shè)計(jì)語(yǔ)言編寫(xiě)程序代碼,并最終得到結(jié)果的過(guò)程。

為了使計(jì)算機(jī)能夠理解人的意圖,人類就必須要將需解決的問(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 以前稱為 J2SE。它允許開(kāi)發(fā)和部署在桌面、服務(wù)器、嵌入式環(huán)境和實(shí)時(shí)環(huán)境中使用的 Java 應(yīng)用程序。Java SE 包含了支持 Java Web 服務(wù)開(kāi)發(fā)的類,并為Java EE和Java ME提供基礎(chǔ)。

  • Java EE(J2EE,Java 2 Platform Enterprise Edition,企業(yè)版)
    Java EE 以前稱為 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 以前稱為 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程序所需的核心類庫(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)等

JVM&JRE&JDK關(guān)系圖

Java基礎(chǔ)知識(shí)面試題有哪些

什么是跨平臺(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)類型機(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é)碼并不專對(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程序的主類?應(yīng)用程序和小程序的主類有何不同?

一個(gè)程序中可以有多個(gè)類,但只能有一個(gè)類是主類。在Java應(yīng)用程序中,這個(gè)主類是指包含main()方法的類。而在Java小程序中,這個(gè)主類是一個(gè)繼承自系統(tǒng)類JApplet或Applet的子類。應(yīng)用程序的主類不一定要求是public類,但小程序的主類要求必須是public類。主類是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的小游戲類似。

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的類是單繼承的,C++支持多重繼承;雖然Java的類不可以多繼承,但是接口可以多繼承。

  • Java有自動(dòng)內(nèi)存管理機(jī)制,不需要程序員手動(dòng)釋放無(wú)用內(nèi)存

Oracle JDK 和 OpenJDK 的對(duì)比

  1. Oracle JDK版本將每三年發(fā)布一次,而OpenJDK版本每三個(gè)月發(fā)布一次;

  2. OpenJDK 是一個(gè)參考模型并且是完全開(kāi)源的,而Oracle JDK是OpenJDK的一個(gè)實(shí)現(xiàn),并不是完全開(kāi)源的;

  3. Oracle JDK 比 OpenJDK 更穩(wěn)定。OpenJDK和Oracle JDK的代碼幾乎相同,但Oracle JDK有更多的類和一些錯(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)題;

  4. 在響應(yīng)性和JVM性能方面,Oracle JDK與OpenJDK相比提供了更好的性能;

  5. Oracle JDK不會(huì)為即將發(fā)布的版本提供長(zhǎng)期支持,用戶每次都必須通過(guò)更新到最新版本獲得支持來(lái)獲取最新版本;

  6. Oracle JDK根據(jù)二進(jìn)制代碼許可協(xié)議獲得許可,而OpenJDK根據(jù)GPL v2許可獲得許可。

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

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

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基本數(shù)據(jù)類型圖

Java基礎(chǔ)知識(shí)面試題有哪些

switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java5 開(kāi)始,Java 中引入了枚舉類型,expr 也可以是 enum 類型,從 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)行下取整。

float f=3.4;是否正確

不正確。3.4 是雙精度數(shù),將雙精度型(double)賦值給浮點(diǎn)型(float)屬于下轉(zhuǎn)型(down-casting,也稱為窄化)會(huì)造成精度損失,因此需要強(qiáng)制類型轉(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 類型,因此 s1+1 運(yùn)算結(jié)果也是 int型,需要強(qiáng)制轉(zhuǎn)換類型才能賦值給 short 型。

而 short s1 = 1; s1 += 1;可以正確編譯,因?yàn)?s1+= 1;相當(dāng)于 s1 = (short(s1 + 1);其中有隱含的強(qiáng)制類型轉(zhuǎn)換。

編碼

Java語(yǔ)言采用何種編碼方案?有何特點(diǎn)?

Java語(yǔ)言采用Unicode編碼標(biāo)準(zhǔn),Unicode(標(biāo)準(zhǔn)碼),它為每個(gè)字符制訂了一個(gè)唯一的數(shù)值,因此在任何的語(yǔ)言,平臺(tái),程序都可以放心的使用。

注釋

什么Java注釋

定義:用于解釋說(shuō)明程序的文字

分類

  • 單行注釋
    格式: // 注釋文字

  • 多行注釋
    格式: /* 注釋文字 */

  • 文檔注釋
    格式:/** 注釋文字 */

作用

在程序中,尤其是復(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ì)類、變量、方法和構(gòu)造方法的訪問(wèn)。Java 支持 4 種不同的訪問(wèn)權(quán)限。

分類

private : 在同一類內(nèi)可見(jiàn)。使用對(duì)象:變量、方法。 注意:不能修飾類(外部類)
default (即缺省,什么也不寫(xiě),不使用任何關(guān)鍵字): 在同一包內(nèi)可見(jiàn),不使用任何修飾符。使用對(duì)象:類、接口、變量、方法。
protected : 對(duì)同一包內(nèi)的類和所有子類可見(jiàn)。使用對(duì)象:變量、方法。 注意:不能修飾類(外部類)。
public : 對(duì)所有類可見(jiàn)。使用對(duì)象:類、接口、變量、方法

訪問(wèn)修飾符圖

Java基礎(chǔ)知識(shí)面試題有哪些

運(yùn)算符

&和&&的區(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)算符(||)的差別也是如此。

關(guān)鍵字

Java 有沒(méi)有 goto

goto 是 Java 中的保留字,在目前版本的 Java 中沒(méi)有使用。

final 有什么用?

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

  • 被final修飾的類不可以被繼承

  • 被final修飾的方法不可以被重寫(xiě)

  • 被final修飾的變量不可以被改變,被final修飾不可變的是變量的引用,而不是引用指向的內(nèi)容,引用指向的內(nèi)容是可以改變的

final finally finalize區(qū)別
  • final可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫(xiě)、修飾變量表
    示該變量是一個(gè)常量不能被重新賦值。

  • finally一般作用在try-catch代碼塊中,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊
    中,表示不管是否出現(xiàn)異常,該代碼塊都會(huì)執(zhí)行,一般用來(lái)存放一些關(guān)閉資源的代碼。

  • finalize是一個(gè)方法,屬于Object類的一個(gè)方法,而Object類是所有類的父類,該方法一般由垃圾回收器來(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ū)分:

public Person(String name, int age) {
    this.name = name;
    this.age = age;
}

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

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;
    }
}
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ū)分

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();
 
    }
}

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

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

  • super(參數(shù)):調(diào)用父類中的某一個(gè)構(gòu)造函數(shù)(應(yīng)該為構(gòu)造函數(shù)中的第一條語(yǔ)句)。

  • this(參數(shù)):調(diào)用本類中另一種形式的構(gòu)造函數(shù)(應(yīng)該為構(gòu)造函數(shù)中的第一條語(yǔ)句)。

this與super的區(qū)別
  • super: 它引用當(dāng)前對(duì)象的直接父類中的成員(用來(lái)訪問(wèn)直接父類中被隱藏的父類中成員數(shù)據(jù)或函數(shù),基類與派生類中有相同成員定義時(shí)如:super.變量名 super.成員函數(shù)據(jù)名(實(shí)參)

  • this:它代表當(dāng)前對(duì)象名(在程序中易產(chǎn)生二義性之處,應(yīng)使用this來(lái)指明當(dāng)前對(duì)象;如果函數(shù)的形參與類中的成員數(shù)據(jù)同名,這時(shí)需用this來(lái)指明成員變量名)

  • super()和this()類似,區(qū)別是,super()在子類中調(diào)用父類的構(gòu)造方法,this()在本類內(nèi)調(diào)用本類的其它構(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塊可以置于類中的任何地方,類中可以有多個(gè)static塊。在類初次被加載的時(shí)候,會(huì)按照static塊的順序來(lái)執(zhí)行每個(gè)static塊,并且只會(huì)執(zhí)行一次。

為什么說(shuō)static塊可以用來(lái)優(yōu)化程序性能,是因?yàn)樗奶匦?只會(huì)在類加載的時(shí)候執(zhí)行一次。因此,很多時(shí)候會(huì)將一些只需要進(jìn)行一次的初始化操作都放在static代碼塊中進(jìn)行。

static的獨(dú)特之處

1、被static修飾的變量或者方法是獨(dú)立于該類的任何對(duì)象,也就是說(shuō),這些變量和方法不屬于任何一個(gè)實(shí)例對(duì)象,而是被類的實(shí)例對(duì)象所共享

怎么理解 “被類的實(shí)例對(duì)象所共享” 這句話呢?就是說(shuō),一個(gè)類的靜態(tài)成員,它是屬于大伙的【大伙指的是這個(gè)類的多個(gè)對(duì)象實(shí)例,我們都知道一個(gè)類可以創(chuàng)建多個(gè)實(shí)例!】,所有的類對(duì)象共享的,不像成員變量是自個(gè)的【自個(gè)指的是這個(gè)類的單個(gè)實(shí)例對(duì)象】…我覺(jué)得我已經(jīng)講的很通俗了,你明白了咩?

2、在該類被第一次加載的時(shí)候,就會(huì)去加載被static修飾的部分,而且只在類第一次使用時(shí)加載并進(jìn)行初始化,注意這是第一次用就要初始化,后面根據(jù)需要是可以再次賦值的。

3、static變量值在類加載的時(shí)候分配空間,以后創(chuàng)建類對(duì)象的時(shí)候不會(huì)重新分配。賦值的話,是可以任意賦值的!

4、被static修飾的變量或者方法是優(yōu)先于對(duì)象存在的,也就是說(shuō)當(dāng)一個(gè)類加載完畢之后,即便沒(méi)有創(chuàng)建對(duì)象,也可以去訪問(wèn)。

static應(yīng)用場(chǎng)景

因?yàn)閟tatic是被類的實(shí)例對(duì)象所共享,因此如果某個(gè)成員變量是被所有對(duì)象所共享的,那么這個(gè)成員變量就應(yīng)該定義為靜態(tài)變量。

因此比較常見(jiàn)的static應(yīng)用場(chǎng)景有:

1、修飾成員變量 2、修飾成員方法 3、靜態(tài)代碼塊 4、修飾類【只能修飾內(nèi)部類也就是靜態(tài)內(nè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)的。

流程控制語(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)。例如:

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;
            }

        }
    }
}

面向?qū)ο?/h3>

面向?qū)ο蟾攀?/h4>

面向?qū)ο蠛兔嫦蜻^(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ū)ο?/strong>:

優(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ū)ο笕筇匦?/h4>
面向?qū)ο蟮奶卣饔心男┓矫?/h5>

面向?qū)ο蟮奶卣髦饕幸韵聨讉€(gè)方面

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

封裝

封裝把一個(gè)對(duì)象的屬性私有化,同時(shí)提供一些可以被外界訪問(wèn)的屬性的方法,如果屬性不想被外界訪問(wèn),我們大可不必提供方法給外界訪問(wèn)。但是如果一個(gè)類沒(méi)有提供給外界訪問(wèn)的方法,那么這個(gè)類也沒(méi)有什么意義了。

繼承

繼承是使用已存在的類的定義作為基礎(chǔ)建立新類的技術(shù),新類的定義可以增加新的數(shù)據(jù)或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過(guò)使用繼承我們能夠非常方便地復(fù)用以前的代碼。

關(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)接口并覆蓋接口中同一方法)。

其中Java 面向?qū)ο缶幊倘筇匦裕悍庋b 繼承 多態(tài)

封裝:隱藏對(duì)象的屬性和實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外提供公共訪問(wèn)方式,將變化隔離,便于使用,提高復(fù)用性和安全性。

繼承:繼承是使用已存在的類的定義作為基礎(chǔ)建立新類的技術(shù),新類的定義可以增加新的數(shù)據(jù)或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過(guò)使用繼承可以提高代碼復(fù)用性。繼承是多態(tài)的前提。

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

  1. 子類擁有父類非 private 的屬性和方法。

  2. 子類可以擁有自己屬性和方法,即子類可以對(duì)父類進(jìn)行擴(kuò)展。

  3. 子類可以用自己的方式實(shí)現(xiàn)父類的方法。

多態(tài)性:父類或接口定義的引用變量可以指向子類或具體實(shí)現(xiàn)類的實(shí)例對(duì)象。提高了程序的拓展性。

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

方法重載(overload)實(shí)現(xiàn)的是編譯時(shí)的多態(tài)性(也稱為前綁定),而方法重寫(xiě)(override)實(shí)現(xiàn)的是運(yùn)行時(shí)的多態(tài)性(也稱為后綁定)。

一個(gè)引用變量到底會(huì)指向哪個(gè)類的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。運(yùn)行時(shí)的多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)多態(tài)需要做兩件事:

  • 方法重寫(xiě)(子類繼承父類并重寫(xiě)父類中已有的或抽象的方法);

  • 對(duì)象造型(用父類型引用子類型對(duì)象,這樣同樣的引用調(diào)用同樣的方法就會(huì)根據(jù)子類對(duì)象的不同而表現(xiàn)出不同的行為)。

什么是多態(tài)機(jī)制?Java語(yǔ)言是如何實(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)行期間才能決定。因?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)性。

多態(tài)的實(shí)現(xiàn)

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í)行不同的行為。

對(duì)于Java而言,它多態(tài)的實(shí)現(xiàn)機(jī)制遵循一個(gè)原則:當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰(shuí)的成員方法,但是這個(gè)被調(diào)用的方法必須是在超類中定義過(guò)的,也就是說(shuō)被子類覆蓋的方法。

面向?qū)ο笪宕蠡驹瓌t是什么(可選)
  • 單一職責(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)的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~

  • 依賴倒置原則DIP(the Dependency Inversion Principle DIP)
    高層次的模塊不應(yīng)該依賴于低層次的模塊,他們都應(yīng)該依賴于抽象。抽象不應(yīng)該依賴于具體實(shí)現(xiàn),具體實(shí)現(xiàn)應(yīng)該依賴于抽象。就是你出國(guó)要說(shuō)你是中國(guó)人,而不能說(shuō)你是哪個(gè)村子的。比如說(shuō)中國(guó)人是抽象的,下面有具體的xx省,xx市,xx縣。你要依賴的抽象是中國(guó)人,而不是你是xx村的。

  • 接口分離原則ISP(the Interface Segregation Principle ISP)
    設(shè)計(jì)時(shí)采用多個(gè)與特定客戶類有關(guān)的接口比采用一個(gè)通用的接口要好。就比如一個(gè)手機(jī)擁有打電話,看視頻,玩游戲等功能,把這幾個(gè)功能拆分成不同的接口,比在一個(gè)接口里要好的多。

類與接口

抽象類和接口的對(duì)比

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

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

相同點(diǎn)

  • 接口和抽象類都不能實(shí)例化

  • 都位于繼承的頂端,用于被其他實(shí)現(xiàn)或繼承

  • 都包含抽象方法,其子類都必須覆寫(xiě)這些抽象方法

不同點(diǎn)

Java基礎(chǔ)知識(shí)面試題有哪些

備注:Java8中接口中引入默認(rèn)方法和靜態(tài)方法,以此來(lái)減少抽象類和接口之間的差異。

現(xiàn)在,我們可以為接口提供默認(rèn)實(shí)現(xiàn)的方法了,并且不用強(qiáng)制子類來(lái)實(shí)現(xiàn)它。

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

  • 行為模型應(yīng)該總是通過(guò)接口而不是抽象類定義,所以通常是優(yōu)先選用接口,盡量少用抽象類。

  • 選擇抽象類的時(shí)候通常是如下情況:需要定義子類的行為,又要為子類提供通用的功能。

普通類和抽象類有哪些區(qū)別?
  • 普通類不能包含抽象方法,抽象類可以包含抽象方法。

  • 抽象類不能直接實(shí)例化,普通類可以直接實(shí)例化。

抽象類能使用 final 修飾嗎?

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

創(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ū)域

成員變量:方法外部,類內(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)初始值,使用前必須賦值。

使用原則

在使用變量時(shí)需要遵循的原則為:就近原則
首先在局部范圍找,有就使用;接著在成員位置找。

在Java中定義一個(gè)不做事且沒(méi)有參數(shù)的構(gòu)造方法的作用

Java程序在執(zhí)行子類的構(gòu)造方法之前,如果沒(méi)有用super()來(lái)調(diào)用父類特定的構(gòu)造方法,則會(huì)調(diào)用父類中“沒(méi)有參數(shù)的構(gòu)造方法”。因此,如果父類中只定義了有參數(shù)的構(gòu)造方法,而在子類的構(gòu)造方法中又沒(méi)有用super()來(lái)調(diào)用父類中特定的構(gòu)造方法,則編譯時(shí)將發(fā)生錯(cuò)誤,因?yàn)镴ava程序在父類中找不到?jīng)]有參數(shù)的構(gòu)造方法可供執(zhí)行。解決辦法是在父類里加上一個(gè)不做事且沒(méi)有參數(shù)的構(gòu)造方法。

在調(diào)用子類構(gòu)造方法之前會(huì)先調(diào)用父類沒(méi)有參數(shù)的構(gòu)造方法,其目的是?

幫助子類做初始化工作。

一個(gè)類的構(gòu)造方法的作用是什么?若一個(gè)類沒(méi)有聲明構(gòu)造方法,改程序能正確執(zhí)行嗎?為什么?

主要作用是完成對(duì)類對(duì)象的初始化工作。可以執(zhí)行。因?yàn)橐粋€(gè)類即使沒(méi)有聲明構(gòu)造方法也會(huì)有默認(rèn)的不帶參數(shù)的構(gòu)造方法。

構(gòu)造方法有哪些特性?

名字與類名相同;

沒(méi)有返回值,但不能用void聲明構(gòu)造函數(shù);

生成類的對(duì)象時(shí)自動(dòng)執(zhí)行,無(wú)需調(diào)用。

靜態(tài)變量和實(shí)例變量區(qū)別

靜態(tài)變量: 靜態(tài)變量由于不屬于任何實(shí)例對(duì)象,屬于類的,所以在內(nèi)存中只會(huì)有一份,在類的加載過(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變量也稱作靜態(tài)變量,靜態(tài)變量和非靜態(tài)變量的區(qū)別是:靜態(tài)變量被所有的對(duì)象所共享,在內(nèi)存中只有一個(gè)副本,它當(dāng)且僅當(dāng)在類初次加載時(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è)方面:

  1. 在外部調(diào)用靜態(tài)方法時(shí),可以使用"類名.方法名"的方式,也可以使用"對(duì)象名.方法名"的方式。而實(shí)例方法只有后面這種方式。也就是說(shuō),調(diào)用靜態(tài)方法可以無(wú)需創(chuàng)建對(duì)象。

  2. 靜態(tài)方法在訪問(wèn)本類的成員時(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é)果?。ㄇ疤崾窃摲椒赡墚a(chǎn)生結(jié)果)。返回值的作用:接收出結(jié)果,使得它可以用于其他的操作!

內(nèi)部類

什么是內(nèi)部類?

在Java中,可以將一個(gè)類的定義放在另外一個(gè)類的定義內(nèi)部,這就是內(nèi)部類。內(nèi)部類本身就是類的一個(gè)屬性,與其他屬性定義方式一致。

內(nèi)部類的分類有哪些

內(nèi)部類可以分為四種:成員內(nèi)部類、局部?jī)?nèi)部類、匿名內(nèi)部類和靜態(tài)內(nèi)部類。

靜態(tài)內(nèi)部類

定義在類內(nèi)部的靜態(tài)類,就是靜態(tài)內(nèi)部類。

public class Outer {

    private static int radius = 1;

    static class StaticInner {
        public void visit() {
            System.out.println("visit outer static  variable:" + radius);
        }
    }
}

靜態(tài)內(nèi)部類可以訪問(wèn)外部類所有的靜態(tài)變量,而不可訪問(wèn)外部類的非靜態(tài)變量;靜態(tài)內(nèi)部類的創(chuàng)建方式,new 外部類.靜態(tài)內(nèi)部類(),如下:

Outer.StaticInner inner = new Outer.StaticInner();
inner.visit();

成員內(nèi)部類

定義在類內(nèi)部,成員位置上的非靜態(tài)類,就是成員內(nèi)部類。

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);
        }
    }
}

成員內(nèi)部類可以訪問(wèn)外部類所有的變量和方法,包括靜態(tài)和非靜態(tài),私有和公有。成員內(nèi)部類依賴于外部類的實(shí)例,它的創(chuàng)建方式外部類實(shí)例.new 內(nèi)部類(),如下:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.visit();

局部?jī)?nèi)部類

定義在方法中的內(nèi)部類,就是局部?jī)?nèi)部類

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); 編譯錯(cuò)誤,定義在靜態(tài)方法中的局部類不可以訪問(wèn)外部類的實(shí)例變量
                System.out.println(STATIC_b);
                System.out.println(d);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
}

定義在實(shí)例方法中的局部類可以訪問(wèn)外部類的所有變量和方法,定義在靜態(tài)方法中的局部類只能訪問(wèn)外部類的靜態(tài)變量和方法。局部?jī)?nèi)部類的創(chuàng)建方式,在對(duì)應(yīng)方法內(nèi),new 內(nèi)部類(),如下:

public static void testStaticFunctionClass(){
    class Inner {
    }
    Inner  inner = new Inner();
 }

匿名內(nèi)部類

匿名內(nèi)部類就是沒(méi)有名字的內(nèi)部類,日常開(kāi)發(fā)中使用的比較多。

public class Outer {

    private void test(final int i) {
        new Service() {
            public void method() {
                for (int j = 0; j < i; j++) {
                    System.out.println("匿名內(nèi)部類" );
                }
            }
        }.method();
    }
 }
 //匿名內(nèi)部類必須繼承或?qū)崿F(xiàn)一個(gè)已有的接口 
 interface Service{
    void method();
}

除了沒(méi)有名字,匿名內(nèi)部類還有以下特點(diǎn):

  • 匿名內(nèi)部類必須繼承一個(gè)抽象類或者實(shí)現(xiàn)一個(gè)接口。

  • 匿名內(nèi)部類不能定義任何靜態(tài)成員和靜態(tài)方法。

  • 當(dāng)所在的方法的形參需要被匿名內(nèi)部類使用時(shí),必須聲明為 final。

  • 匿名內(nèi)部類不能是抽象的,它必須要實(shí)現(xiàn)繼承的類或者實(shí)現(xiàn)的接口的所有抽象方法。

匿名內(nèi)部類創(chuàng)建方式:

new 類/接口{ 
  //匿名內(nèi)部類實(shí)現(xiàn)部分
}
內(nèi)部類的優(yōu)點(diǎn)

我們?yōu)槭裁匆褂脙?nèi)部類呢?因?yàn)樗幸韵聝?yōu)點(diǎn):

  • 一個(gè)內(nèi)部類對(duì)象可以訪問(wèn)創(chuàng)建它的外部類對(duì)象的內(nèi)容,包括私有數(shù)據(jù)!

  • 內(nèi)部類不為同一包的其他類所見(jiàn),具有很好的封裝性;

  • 內(nèi)部類有效實(shí)現(xiàn)了“多重繼承”,優(yōu)化 java 單繼承的缺陷。

  • 匿名內(nèi)部類可以很方便的定義回調(diào)。

內(nèi)部類有哪些應(yīng)用場(chǎng)景
  1. 一些多算法場(chǎng)合

  2. 解決一些非面向?qū)ο蟮恼Z(yǔ)句塊。

  3. 適當(dāng)使用內(nèi)部類,使得代碼更加靈活和富有擴(kuò)展性。

  4. 當(dāng)某個(gè)類除了它的外部類,不再被其他的類使用時(shí)。

局部?jī)?nèi)部類和匿名內(nèi)部類訪問(wèn)局部變量的時(shí)候,為什么變量必須要加上final?

局部?jī)?nèi)部類和匿名內(nèi)部類訪問(wèn)局部變量的時(shí)候,為什么變量必須要加上final呢?它內(nèi)部原理是什么呢?

先看這段代碼:

public class Outer {

    void outMethod(){
        final int a =10;
        class Inner {
            void innerMethod(){
                System.out.println(a);
            }

        }
    }
}

以上例子,為什么要加final呢?是因?yàn)?strong>生命周期不一致, 局部變量直接存儲(chǔ)在棧中,當(dāng)方法執(zhí)行結(jié)束后,非final的局部變量就被銷毀。而局部?jī)?nèi)部類對(duì)局部變量的引用依然存在,如果局部?jī)?nèi)部類要調(diào)用局部變量時(shí),就會(huì)出錯(cuò)。加了final,可以確保局部?jī)?nèi)部類使用的變量與外層的局部變量區(qū)分開(kāi),解決了這個(gè)問(wèn)題。

內(nèi)部類相關(guān),看程序說(shuō)出運(yùn)行結(jié)果

運(yùn)行結(jié)果: 

局部變量:14
內(nèi)部類變量:13
外部類變量:12

重寫(xiě)與重載

構(gòu)造器(constructor)是否可被重寫(xiě)(override)

構(gòu)造器不能被繼承,因此不能被重寫(xiě),但可以被重載。

重載(Overload)和重寫(xiě)(Override)的區(qū)別。重載的方法能否根據(jù)返回類型進(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è)類中,方法名相同參數(shù)列表不同(參數(shù)類型不同、個(gè)數(shù)不同、順序不同),與方法返回值和訪問(wèn)修飾符無(wú)關(guān),即重載的方法不能根據(jù)返回類型進(jìn)行區(qū)分

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

對(duì)象相等判斷

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

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

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

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

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

舉個(gè)例子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 為一個(gè)引用
        String b = new String("ab"); // b為另一個(gè)引用,對(duì)象的內(nèi)容一樣
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 從常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一對(duì)象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

說(shuō)明:

  • String中的equals方法是被重寫(xiě)過(guò)的,因?yàn)閛bject的equals方法是比較的對(duì)象的內(nèi)存地址,而String的equals方法比較的是對(duì)象的值。

  • 當(dāng)創(chuàng)建String類型的對(duì)象時(shí),虛擬機(jī)會(huì)在常量池中查找有沒(méi)有已經(jīng)存在的值和要?jiǎ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() 的作用是獲取哈希碼,也稱為散列碼;它實(shí)際上是返回一個(gè)int整數(shù)。這個(gè)哈希碼的作用是確定該對(duì)象在哈希表中的索引位置。hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有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ù))的一些專業(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

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);
}

結(jié)果

a = 20
b = 10
num1 = 10
num2 = 20

解析

Java基礎(chǔ)知識(shí)面試題有哪些

在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ù)類型的參數(shù),而對(duì)象引用作為參數(shù)就不一樣,請(qǐng)看 example2.

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) {
        // 將數(shù)組的第一個(gè)元素變?yōu)?
        array[0] = 0;
    }

結(jié)果

1
0

解析

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

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());
    }
}

結(jié)果

x:小李
y:小張
s1:小張
s2:小李

解析

交換之前:

Java基礎(chǔ)知識(shí)面試題有哪些

交換之后:

Java基礎(chǔ)知識(shí)面試題有哪些

通過(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ù)類型的參數(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ǔ)類;

  • java.io:這里面是所有輸入輸出有關(guān)的類,比如文件操作等;

  • java.nio:為了完善 io 包中的功能,提高 io 包中性能而寫(xiě)的一個(gè)新包;

  • java.net:這里面是與網(wǎng)絡(luò)有關(guān)的類;

  • java.util:這個(gè)是系統(tǒng)輔助類,特別是集合類;

  • java.sql:這個(gè)是數(shù)據(jù)庫(kù)操作的類。

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è)類,這些類看上去很雜亂,但實(shí)際上很有規(guī)則,而且彼此之間存在非常緊密的聯(lián)系, Java I0流的40多個(gè)類都是從如下4個(gè)抽象類基類中派生出來(lái)的。

  • InputStream/Reader: 所有的輸入流的基類,前者是字節(jié)輸入流,后者是字符輸入流。

  • OutputStream/Writer: 所有輸出流的基類,前者是字節(jié)輸出流,后者是字符輸出流。

按操作方式分類結(jié)構(gòu)圖:

Java基礎(chǔ)知識(shí)面試題有哪些

按操作對(duì)象分類結(jié)構(gòu)圖:

Java基礎(chǔ)知識(shí)面試題有哪些

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è)連接專注于自己的 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è)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語(yǔ)言的反射機(jī)制。

靜態(tài)編譯和動(dòng)態(tài)編譯

  • **靜態(tài)編譯:**在編譯時(shí)確定類型,綁定對(duì)象

  • **動(dòng)態(tài)編譯:**運(yùn)行時(shí)確定類型,綁定對(duì)象

反射機(jī)制優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn): 運(yùn)行期類型的判斷,動(dòng)態(tà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類里面解析xml或properties里面的內(nèi)容,得到對(duì)應(yīng)實(shí)體類的字節(jié)碼字符串以及相關(guān)的屬性信息; 3)使用反射機(jī)制,根據(jù)這個(gè)字符串獲得某個(gè)類的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ò)類名實(shí)現(xiàn)反射機(jī)制

public class Student {
    private int id;
    String name;
    protected boolean sex;
    public float score;
}
public class Get {
    //獲取反射機(jī)制三種方式
    public static void main(String[] args) throws ClassNotFoundException {
        //方式一(通過(guò)建立對(duì)象)
        Student stu = new Student();
        Class classobj1 = stu.getClass();
        System.out.println(classobj1.getName());
        //方式二(所在通過(guò)路徑-相對(duì)路徑)
        Class classobj2 = Class.forName("fanshe.Student");
        System.out.println(classobj2.getName());
        //方式三(通過(guò)類名)
        Class classobj3 = Student.class;
        System.out.println(classobj3.getName());
    }
}

網(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ū)別
  1. 形式上: 字符常量是單引號(hào)引起的一個(gè)字符 字符串常量是雙引號(hào)引起的若干個(gè)字符

  2. 含義上: 字符常量相當(dāng)于一個(gè)整形值(ASCII值),可以參加表達(dá)式運(yùn)算 字符串常量代表一個(gè)地址值(該字符串在內(nèi)存中存放位置)

  3. 占內(nèi)存大小 字符常量只占一個(gè)字節(jié) 字符串常量占若干個(gè)字節(jié)(至少一個(gè)字符結(jié)束標(biāo)志)

什么是字符串常量池?

字符串常量池位于堆內(nèi)存中,專門(mén)用來(lái)存儲(chǔ)字符串常量,可以提高內(nèi)存的使用率,避免開(kāi)辟多塊空間存儲(chǔ)相同的字符串,在創(chuàng)建字符串時(shí) JVM 會(huì)首先檢查字符串常量池,如果該字符串已經(jīng)存在池中,則返回它的引用,如果不存在,則實(shí)例化一個(gè)字符串放到池中,并返回其引用。

String 是最基本的數(shù)據(jù)類型嗎

不是。Java 中的基本數(shù)據(jù)類型只有 8 個(gè) :byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type),剩下的都是引用類型(referencetype),Java 5 以后引入的枚舉類型也算是一種比較特殊的引用類型。

這是很基礎(chǔ)的東西,但是很多初學(xué)者卻容易忽視,Java 的 8 種基本數(shù)據(jù)類型中不包括 String,基本數(shù)據(jù)類型中用來(lái)描述文本數(shù)據(jù)的是 char,但是它只能表示單個(gè)字符,比如 ‘a(chǎn)’,‘好’ 之類的,如果要描述一段文本,就需要用多個(gè) char 類型的變量,也就是一個(gè) char 類型數(shù)組,比如“你好” 就是長(zhǎng)度為2的數(shù)組 char[] chars = {‘你’,‘好’};

但是使用數(shù)組過(guò)于麻煩,所以就有了 String,String 底層就是一個(gè) char 類型的數(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 類,表示 String 類不能被繼承,提高了系統(tǒng)的安全性。

String為什么是不可變的嗎?

簡(jiǎn)單來(lái)說(shuō)就是String類利用了final修飾的char類型數(shù)組存儲(chǔ)字符,源碼如下圖所以:

/** The value is used for character storage. */
private final char value[];
String真的是不可變的嗎?

我覺(jué)得如果別人問(wèn)這個(gè)問(wèn)題的話,回答不可變就可以了。 下面只是給大家看兩個(gè)有代表性的例子:

1) String不可變但不代表引用不可以變

String str = "Hello";
str = str + " World";
System.out.println("str=" + str);

結(jié)果:

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"字符串。

2) 通過(guò)反射是可以修改所謂的“不可變”對(duì)象

// 創(chuàng)建字符串"Hello World", 并賦給引用s
String s = "Hello World";

System.out.println("s = " + s); // Hello World

// 獲取String類中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");

// 改變value屬性的訪問(wèn)權(quán)限
valueFieldOfString.setAccessible(true);

// 獲取s對(duì)象上的value屬性的值
char[] value = (char[]) valueFieldOfString.get(s);

// 改變value所引用的數(shù)組中的第5個(gè)字符
value[5] = '_';

System.out.println("s = " + s); // Hello_World

結(jié)果:

s = Hello World
s = Hello_World

解析:

用反射可以訪問(wèn)私有成員, 然后反射出String對(duì)象中的value屬性, 進(jìn)而改變通過(guò)獲得的value引用改變數(shù)組的結(jié)構(gòu)。但是一般我們不會(huì)這么做,這里只是簡(jiǎn)單提一下有這個(gè)東西。

是否可以繼承 String 類

String 類是 final 類,不可以被繼承。

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ì)象。

String str1 = "hello"; //str1指向靜態(tài)區(qū)
String str2 = new String("hello");  //str2指向堆上的對(duì)象
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
如何將字符串反轉(zhuǎn)?

使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

示例代碼:

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
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 類的常用方法都有那些?
  • indexOf():返回指定字符的索引。

  • charAt():返回指定索引處的字符。

  • replace():字符串替換。

  • trim():去除字符串兩端空白。

  • split():分割字符串,返回一個(gè)分割后的字符串?dāng)?shù)組。

  • getBytes():返回字符串的 byte 類型數(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類中使用字符數(shù)組保存字符串,private final char value[],所以string對(duì)象是不可變的。StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數(shù)組保存字符串,char[] value,這兩種對(duì)象都是可變的。

線程安全性

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

Date相關(guān)

包裝類相關(guān)

自動(dòng)裝箱與拆箱

裝箱:將基本類型用它們對(duì)應(yīng)的引用類型包裝起來(lái);

拆箱:將包裝類型轉(zhuǎn)換為基本數(shù)據(jù)類型;

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

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

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

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

public static void main(String[] args) {
    Integer a = new Integer(3);
    Integer b = 3;  // 將3自動(dòng)裝箱成Integer類型
    int c = 3;
    System.out.println(a == b); // false 兩個(gè)引用沒(méi)有引用同一對(duì)象
    System.out.println(a == c); // true a自動(dòng)拆箱成int類型再和c比較
    System.out.println(b == c); // true

    Integer a1 = 128;
    Integer b1 = 128;
    System.out.println(a1 == b1); // false

    Integer a2 = 127;
    Integer b2 = 127;
    System.out.println(a2 == b2); // true
}

感謝各位的閱讀,以上就是“Java基礎(chǔ)知識(shí)面試題有哪些”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Java基礎(chǔ)知識(shí)面試題有哪些這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI