java面試知識點易考總結(基礎知識)

1.java語言的特性:
(1)與c++相比:

      Java是一門面向對象編程語言,不僅吸收了C++語言的各種優點,還摒棄了C++裏難以理解的多繼承、指針等概念,因此Java語言具有功能強大和簡單易用兩個特徵。

         二者相比:

  • 都是面向對象的語言,都支持封裝、繼承和多態
  • Java不提供指針來直接訪問內存,程序內存更加安全
  • Java的類是單繼承的,C++支持多重繼承;雖然Java的類不可以多繼承,但是接口可以多繼承。
  • Java有自動內存管理機制,不需要程序員手動釋放無用內存

(2)Java語言有哪些特點:

簡單易學(Java語言的語法與C語言和C++語言很接近)

面向對象(封裝,繼承,多態)

平臺無關性(Java虛擬機實現平臺無關性)

支持網絡編程並且很方便(Java語言誕生本身就是爲簡化網絡編程設計的)

支持多線程(多線程機制使應用程序在同一時間並行執行多項任)

健壯性(Java語言的強類型機制、異常處理、垃圾的自動收集等)

安全性
 

2.JVM、JRE和JDK的關係

JVM
Java Virtual Machine是Java虛擬機,Java程序需要運行在虛擬機上,不同的平臺有自己的虛擬機,因此Java語言可以實現跨平臺。

這裏有兩個知識點:

第一:這裏引申出來跨平臺性:所謂跨平臺性,是指java語言編寫的程序,一次編譯後,可以在多個系統平臺上運行。

第二:字節碼:

字節碼:Java源代碼經過虛擬機編譯器編譯後產生的文件(即擴展爲.class的文件),它不面向任何特定的處理器,只面向虛擬機。

採用字節碼的好處:

Java語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。所以Java程序運行時比較高效,而且,由於字節碼並不專對一種特定的機器,因此,Java程序無須重新編譯便可在多種不同的計算機上運行。

先看下java中的編譯器和解釋器:

Java中引入了虛擬機的概念,即在機器和編譯程序之間加入了一層抽象的虛擬機器。這臺虛擬的機器在任何平臺上都提供給編譯程序一個的共同的接口。編譯程序只需要面向虛擬機,生成虛擬機能夠理解的代碼,然後由解釋器來將虛擬機代碼轉換爲特定系統的機器碼執行。在Java中,這種供虛擬機理解的代碼叫做字節碼(即擴展爲.class的文件),它不面向任何特定的處理器,只面向虛擬機。每一種平臺的解釋器是不同的,但是實現的虛擬機是相同的。Java源程序經過編譯器編譯後變成字節碼,字節碼由虛擬機解釋執行,虛擬機將每一條要執行的字節碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然後在特定的機器上運行,這就是上面提到的Java的特點的編譯與解釋並存的解釋。

Java源代碼---->編譯器---->jvm可執行的Java字節碼(即虛擬指令)---->jvm---->jvm中解釋器----->機器可執行的二進制機器碼---->程序運行。

 

JRE
Java Runtime Environment包括Java虛擬機和Java程序所需的核心類庫等。核心類庫主要是java.lang包:包含了運行Java程序必不可少的系統類,如基本數據類型、基本數學函數、字符串處理、線程、異常處理類等,系統缺省加載這個包

如果想要運行一個開發好的Java程序,計算機中只需要安裝JRE即可。

JDK
Java Development Kit是提供給Java開發人員使用的,其中包含了Java的開發工具,也包括了JRE。所以安裝了JDK,就無需再單獨安裝JRE了。其中的開發工具:編譯工具(javac.exe),打包工具(jar.exe)等

JVM&JRE&JDK關係圖

 

3.基礎語法:

定義:Java語言是強類型語言,對於每一種數據都定義了明確的具體的數據類型,在內存中分配了不同大小的內存空間。

Java基本數據類型圖

 

筆試題考過:

switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java5 開始,Java 中引入了枚舉類型,expr 也可以是 enum 類型,從 Java 7 開始,expr 還可以是字符串(String),但是長整型(long)在目前所有的版本中都是不可以的。

用最有效率的方法計算 2 乘以 8
2 << 3(左移 3 位相當於乘以 2 的 3 次方,右移 3 位相當於除以 2 的 3 次方)。

Math.round(11.5) 等於多少?Math.round(-11.5)等於多少
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四捨五入的原理是在參數上加 0.5 然後進行下取整。

float f=3.4;是否正確
不正確。3.4 是雙精度數,將雙精度型(double)賦值給浮點型(float)屬於下轉型(down-casting,也稱爲窄化)會造成精度損失,因此需要強制類型轉換float f =(float)3.4; 或者寫成 float f =3.4F;。

short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎
對於 short s1 = 1; s1 = s1 + 1;由於 1 是 int 類型,因此 s1+1 運算結果也是 int型,需要強制轉換類型才能賦值給 short 型。

而 short s1 = 1; s1 += 1;可以正確編譯,因爲 s1+= 1;相當於 s1 = (short(s1 + 1);其中有隱含的強制類型轉換。
 

4.Java語言採用何種編碼方案?有何特點?

Java語言採用Unicode編碼標準,Unicode(標準碼),它爲每個字符制訂了一個唯一的數值,因此在任何的語言,平臺,程序都可以放心的使用。

5.訪問修飾符 public,private,protected,以及不寫(默認)時的區別
定義:Java中,可以使用訪問修飾符來保護對類、變量、方法和構造方法的訪問。Java 支持 4 種不同的訪問權限。

分類

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

訪問修飾符圖

 

6.final 有什麼用?
用於修飾類、屬性和方法;

被final修飾的類不可以被繼承
被final修飾的方法不可以被重寫
被final修飾的變量不可以被改變,被final修飾不可變的是變量的引用,而不是引用指向的內容,引用指向的內容是可以改變的
final finally finalize區別
final可以修飾類、變量、方法,修飾類表示該類不能被繼承、修飾方法表示該方法不能被重寫、修飾變量表
示該變量是一個常量不能被重新賦值。
finally一般作用在try-catch代碼塊中,在處理異常的時候,通常我們將一定要執行的代碼方法finally代碼塊
中,表示不管是否出現異常,該代碼塊都會執行,一般用來存放一些關閉資源的代碼。
finalize是一個方法,屬於Object類的一個方法,而Object類是所有類的父類,該方法一般由垃圾回收器來調
用,當我們調用System.gc() 方法的時候,由垃圾回收器調用finalize(),回收垃圾,一個對象是否可回收的
最後判斷。
 

7.什麼是靜態代碼塊:

靜態代碼塊:執行優先級高於非靜態的初始化塊,它會在類初始化的時候執行一次,執行完成便銷燬,它僅能初始化類變量,即static修飾的數據成員。

非靜態代碼塊:執行的時候如果有靜態初始化塊,先執行靜態初始化塊再執行非靜態初始化塊,在每個對象生成時都會被執行一次,它可以初始化類的實例變量。非靜態初始化塊會在構造函數執行時,在構造函數主體代碼執行之前被運行。

靜態代碼塊的執行順序靜態代碼塊----->非靜態代碼塊-------->構造函數

 

易考點:繼承

父類:

子類:

在子類中執行main方法,可以看到控制檯打印出來的結果

 

static關鍵字還有一個比較關鍵的作用就是 用來形成靜態代碼塊以優化程序性能。static塊可以置於類中的任何地方,類中可以有多個static塊。在類初次被加載的時候,會按照static塊的順序來執行每個static塊,並且只會執行一次。

static的獨特之處
1、被static修飾的變量或者方法是獨立於該類的任何對象,也就是說,這些變量和方法不屬於任何一個實例對象,而是被類的實例對象所共享。

2、在該類被第一次加載的時候,就會去加載被static修飾的部分,而且只在類第一次使用時加載並進行初始化,注意這是第一次用就要初始化,後面根據需要是可以再次賦值的。

3、static變量值在類加載的時候分配空間,以後創建類對象的時候不會重新分配。賦值的話,是可以任意賦值的!

4、被static修飾的變量或者方法是優先於對象存在的,也就是說當一個類加載完畢之後,即便沒有創建對象,也可以去訪問。
 

 

8.break ,continue ,return 的區別及作用(筆試考過)
break 跳出總上一層循環,不再執行循環(結束當前的循環體)

continue 跳出本次循環,繼續執行下次循環(結束正在執行的循環 進入下一個循環條件)

return 程序返回,不再執行下面的代碼(結束當前的方法 直接返回)
 

9.面向對象和麪向過程的區別
面向過程:

優點:性能比面向對象高,因爲類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般採用面向過程開發,性能是最重要的因素。

缺點:沒有面向對象易維護、易複用、易擴展

面向對象:

優點:易維護、易複用、易擴展,由於面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易於維護

缺點:性能比面向過程低

面向過程是具體化的,流程化的,解決一個問題,你需要一步一步的分析,一步一步的實現。

面向對象是模型化的,你只需抽象出一個類,這是一個封閉的盒子,在這裏你擁有數據也擁有解決問題的方法。需要什麼功能直接使用就可以了,不必去一步一步的實現,至於這個功能是如何實現的,管我們什麼事?我們會用就可以了。

面向對象的底層其實還是面向過程,把面向過程抽象成類,然後封裝,方便我們使用的就是面向對象了。
 

 

10.什麼是抽象:

抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。抽象只關注對象有哪些屬性和行爲,並不關注這些行爲的細節是什麼。

 

11.面向對象三大特性

封裝

隱藏對象的屬性和實現細節,僅對外提供公共訪問方式,將變化隔離,便於使用,提高複用性和安全性。

繼承

繼承是使用已存在的類的定義作爲基礎建立新類的技術,新類的定義可以增加新的數據或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過使用繼承可以提高代碼複用性。繼承是多態的前提。

關於繼承如下 3 點請記住:

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

子類可以擁有自己屬性和方法,即子類可以對父類進行擴展。

子類可以用自己的方式實現父類的方法。(以後介紹)。

 

多態

一、什麼是多態?

        簡單的來說同一操作作用於不同的對象,可以產生不同的效果。

        父類類型的變量指向子類創建的對象,使用該變量調用父類中一個被子類重寫的方法,則父類中的方法呈現出不同的行爲特徵,這就是多態。

       

多態又分爲 編譯時多態和運行時多態。
編譯時多態:比如重載
運行時多態:比如重寫

  • 靜態分派:所有依賴靜態類型來定位方法執行版本的分派動作。靜態分派發生在編譯階段,因此確定靜態分派的動作實際上不是由虛擬機來執行的,而是由編譯器來完成。(編譯時多態)
  • 動態分派:在運行期根據實際類型確定方法執行版本的分派動作。(運行時多態)

二、爲什麼使用多態?

1.可替換性(substitutability)。多態對已存在代碼具有可替換性。例如,多態對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。

2.可擴充性(extensibility)。多態對代碼具有可擴充性。增加新的子類不影響已存在類的多態性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態功能。例如,在實現了圓錐、半圓錐以及半球體的多態基礎上,很容易增添球體類的多態性。

3.接口性(interface-ability)。多態是超類通過方法簽名,向子類提供了一個共同接口,由子類來完善或者覆蓋它而實現的。如圖8.3 所示。圖中超類Shape規定了兩個實現多態的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere爲了實現多態,完善或者覆蓋這兩個接口方法。

4.靈活性(flexibility)。它在應用中體現了靈活多樣的操作,提高了使用效率。

5.簡化性(simplicity)。多態簡化對應用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤爲突出和重要。

三、多態的實現方式(3種)

接口實現,繼承父類進行方法重寫,同一個類中進行方法重載。

 

多態存在的三個必要條件

一、要有繼承;
二、要有重寫;
三、父類引用指向子類對象。

 

12.面向對象五大基本原則是什麼(可選)
單一職責原則SRP(Single Responsibility Principle)
類的功能要單一,不能包羅萬象,跟雜貨鋪似的。


開放封閉原則OCP(Open-Close Principle)
一個模塊對於拓展是開放的,對於修改是封閉的,想要增加功能熱烈歡迎,想要修改,哼,一萬個不樂意。


裏式替換原則LSP(the Liskov Substitution Principle LSP)
子類可以替換父類出現在父類能夠出現的任何地方。比如你能代表你爸去你姥姥家幹活。哈哈~~


依賴倒置原則DIP(the Dependency Inversion Principle DIP)
高層次的模塊不應該依賴於低層次的模塊,他們都應該依賴於抽象。抽象不應該依賴於具體實現,具體實現應該依賴於抽象。就是你出國要說你是中國人,而不能說你是哪個村子的。比如說中國人是抽象的,下面有具體的xx省,xx市,xx縣。你要依賴的抽象是中國人,而不是你是xx村的。


接口分離原則ISP(the Interface Segregation Principle ISP)
設計時採用多個與特定客戶類有關的接口比採用一個通用的接口要好。就比如一個手機擁有打電話,看視頻,玩遊戲等功能,把這幾個功能拆分成不同的接口,比在一個接口裏要好的多。
 

13.類,接口,抽象類區別:

:使用class關鍵字標識

抽象類:使用abstract關鍵字標識抽象類,使用extends關鍵字繼承抽象類

接口:使用interface關鍵字標識接口,使用implements關鍵字實現接口

抽象類和接口的對比

抽象類是對類的抽象,是一種模板設計,接口是行爲的抽象,是一種行爲的規範。

相同點:

  • 接口和抽象類都不能實例化
  • 都位於繼承的頂端,用於被其他實現或繼承
  • 都包含抽象方法,其子類都必須覆寫這些抽象方法

不同點:

 

普通類和抽象類有哪些區別?

  • 普通類不能包含抽象方法,抽象類可以包含抽象方法。
  • 抽象類不能直接實例化,普通類可以直接實例化。

 

13.抽象類能使用 final 修飾嗎?

不能,定義抽象類就是讓其他類繼承的,如果定義爲 final 該類就不能被繼承,這樣彼此就會產生矛盾,所以 final 不能修飾抽象類

 

14.創建一個對象用什麼關鍵字?對象實例與對象引用有何不同?
new關鍵字,new創建對象實例(對象實例在堆內存中),對象引用指向對象實例(對象引用存放在棧內存中)。一個對象引用可以指向0個或1個對象(一根繩子可以不繫氣球,也可以系一個氣球);一個對象可以有n個引用指向它(可以用n條繩子繫住一個氣球)
 

15.成員變量與局部變量的區別有哪些

變量:在程序執行的過程中,在某個範圍內其值可以發生改變的量。從本質上講,變量其實是內存中的一小塊區域

成員變量:方法外部,類內部定義的變量

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

作用域

成員變量:針對整個類有效。
局部變量:只在某個範圍內有效。(一般指的就是方法,語句體內)

存儲位置

成員變量:隨着對象的創建而存在,隨着對象的消失而消失,存儲在堆內存中
局部變量:在方法被調用,或者語句被執行的時候存在,存儲在棧內存中。當方法調用完,或者語句結束後,就自動釋放

生命週期

成員變量:隨着對象的創建而存在,隨着對象的消失而消失
局部變量:當方法調用完,或者語句結束後,就自動釋放

初始值

成員變量:有默認初始值

局部變量:沒有默認初始值,使用前必須賦值

使用原則

在使用變量時需要遵循的原則爲:就近原則
首先在局部範圍找,有就使用;接着在成員位置找
 

16.什麼是內部類?

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

內部類的分類有哪些

內部類可以分爲四種:成員內部類、局部內部類、匿名內部類和靜態內部類

靜態內部類

定義在類內部的靜態類,就是靜態內部類。

public class Outer {

    private static int radius = 1;

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

靜態內部類可以訪問外部類所有的靜態變量,而不可訪問外部類的非靜態變量;靜態內部類的創建方式,new 外部類.靜態內部類(),如下:

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

成員內部類

定義在類內部,成員位置上的非靜態類,就是成員內部類。

public class Outer {

    private static  int radius = 1;
    private int count =2;
    
     class Inner {
        public void visit() {
            System.out.println("visit outer static  variable:" + radius);
            System.out.println("visit outer   variable:" + count);
        }
    }
}

成員內部類可以訪問外部類所有的變量和方法,包括靜態和非靜態,私有和公有。成員內部類依賴於外部類的實例,它的創建方式外部類實例.new 內部類(),如下:

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

局部內部類

定義在方法中的內部類,就是局部內部類。

public class Outer {

    private  int out_a = 1;
    private static int STATIC_b = 2;

    public void testFunctionClass(){
        int inner_c =3;
        class Inner {
            private void fun(){
                System.out.println(out_a);
                System.out.println(STATIC_b);
                System.out.println(inner_c);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
    public static void testStaticFunctionClass(){
        int d =3;
        class Inner {
            private void fun(){
                // System.out.println(out_a); 編譯錯誤,定義在靜態方法中的局部類不可以訪問外部類的實例變量
                System.out.println(STATIC_b);
                System.out.println(d);
            }
        }
        Inner  inner = new Inner();
        inner.fun();
    }
}

定義在實例方法中的局部類可以訪問外部類的所有變量和方法,定義在靜態方法中的局部類只能訪問外部類的靜態變量和方法。局部內部類的創建方式,在對應方法內,new 內部類(),如下:

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

匿名內部類

匿名內部類就是沒有名字的內部類,日常開發中使用的比較多。

public class Outer {

    private void test(final int i) {
        new Service() {
            public void method() {
                for (int j = 0; j < i; j++) {
                    System.out.println("匿名內部類" );
                }
            }
        }.method();
    }
 }
 //匿名內部類必須繼承或實現一個已有的接口 
 interface Service{
    void method();
}

除了沒有名字,匿名內部類還有以下特點:

  • 匿名內部類必須繼承一個抽象類或者實現一個接口。
  • 匿名內部類不能定義任何靜態成員和靜態方法。
  • 當所在的方法的形參需要被匿名內部類使用時,必須聲明爲 final。
  • 匿名內部類不能是抽象的,它必須要實現繼承的類或者實現的接口的所有抽象方法。

匿名內部類創建方式:

new 類/接口{ 
  //匿名內部類實現部分
}

內部類的優點

我們爲什麼要使用內部類呢?因爲它有以下優點:

  • 一個內部類對象可以訪問創建它的外部類對象的內容,包括私有數據!
  • 內部類不爲同一包的其他類所見,具有很好的封裝性;
  • 內部類有效實現了“多重繼承”,優化 java 單繼承的缺陷。
  • 匿名內部類可以很方便的定義回調。

內部類有哪些應用場景

  1. 一些多算法場合
  2. 解決一些非面向對象的語句塊。
  3. 適當使用內部類,使得代碼更加靈活和富有擴展性。
  4. 當某個類除了它的外部類,不再被其他的類使用時。

內部類相關,看程序說出運行結果

public class Outer {
    private int age = 12;

    class Inner {
        private int age = 13;
        public void print() {
            int age = 14;
            System.out.println("局部變量:" + age);
            System.out.println("內部類變量:" + this.age);
            System.out.println("外部類變量:" + Outer.this.age);
        }
    }

    public static void main(String[] args) {
        Outer.Inner in = new Outer().new Inner();
        in.print();
    }

}

運行結果:

局部變量:14
內部類變量:13
外部類變量:12

 

17.構造器(constructor)是否可被重寫(override)

構造器不能被繼承,因此不能被重寫,但可以被重載。

 

18.重載(Overload)和重寫(Override)的區別。重載的方法能否根據返回類型進行區分?

方法的重載和重寫都是實現多態的方式,區別在於前者實現的是編譯時的多態性,而後者實現的是運行時的多態性。

重載:發生在同一個類中,方法名相同參數列表不同(參數類型不同、個數不同、順序不同),與方法返回值和訪問修飾符無關,即重載的方法不能根據返回類型進行區分

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

 

19.對象相等判斷

== 和 equals 的區別是什麼

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

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

情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個對象時,等價於通過“==”比較這兩個對象。

情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來兩個對象的內容相等;若它們的內容相等,則返回 true (即,認爲這兩個對象相等)。

舉個例子:

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

說明:

  • String中的equals方法是被重寫過的,因爲object的equals方法是比較的對象的內存地址,而String的equals方法比較的是對象的值。
  • 當創建String類型的對象時,虛擬機會在常量池中查找有沒有已經存在的值和要創建的值相同的對象,如果有就把它賦給當前引用。如果沒有就在常量池中重新創建一個String對象。

 

20.hashCode 與 equals

我們以“HashSet 如何檢查重複”爲例子來說明爲什麼要有 hashCode

當你把對象加入 HashSet 時,HashSet 會先計算對象的 hashcode 值來判斷對象加入的位置,同時也會與其他已經加入的對象的 hashcode 值作比較,如果沒有相符的hashcode,HashSet會假設對象沒有重複出現。但是如果發現有相同 hashcode 值的對象,這時會調用 equals()方法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同,HashSet 就不會讓其加入操作成功。如果不同的話,就會重新散列到其他位置。(摘自我的Java啓蒙書《Head first java》第二版)。這樣我們就大大減少了 equals 的次數,相應就大大提高了執行速度。

hashCode()與equals()的相關規定

如果兩個對象相等,則hashcode一定也是相同的

兩個對象相等,對兩個對象分別調用equals方法都返回true

兩個對象有相同的hashcode值,它們也不一定是相等的

 

21.JDK 中常用的包有哪些

  • java.lang:這個是系統的基礎類;
  • java.io:這裏面是所有輸入輸出有關的類,比如文件操作等;
  • java.nio:爲了完善 io 包中的功能,提高 io 包中性能而寫的一個新包;
  • java.net:這裏面是與網絡有關的類;
  • java.util:這個是系統輔助類,特別是集合類;
  • java.sql:這個是數據庫操作的類。

 

22.IO流

java 中 IO 流分爲幾種?

  • 按照流的流向分,可以分爲輸入流和輸出流;
  • 按照操作單元劃分,可以劃分爲字節流和字符流;
  • 按照流的角色劃分爲節點流和處理流。

Java Io流共涉及40多個類,這些類看上去很雜亂,但實際上很有規則,而且彼此之間存在非常緊密的聯繫, Java I0流的40多個類都是從如下4個抽象類基類中派生出來的。

  • InputStream/Reader: 所有的輸入流的基類,前者是字節輸入流,後者是字符輸入流。
  • OutputStream/Writer: 所有輸出流的基類,前者是字節輸出流,後者是字符輸出流

 

BIO,NIO,AIO 有什麼區別?

簡答

  • BIO:Block IO 同步阻塞式 IO,就是我們平常使用的傳統 IO,它的特點是模式簡單使用方便,併發處理能力低。
  • NIO:Non IO 同步非阻塞 IO,是傳統 IO 的升級,客戶端和服務器端通過 Channel(通道)通訊,實現了多路複用。
  • AIO:Asynchronous IO 是 NIO 的升級,也叫 NIO2,實現了異步非堵塞 IO ,異步 IO 的操作基於事件和回調機制。

詳細回答

  • BIO (Blocking I/O): 同步阻塞I/O模式,數據的讀取寫入必須阻塞在一個線程內等待其完成。在活動連接數不是特別高(小於單機1000)的情況下,這種模型是比較不錯的,可以讓每一個連接專注於自己的 I/O 並且編程模型簡單,也不用過多考慮系統的過載、限流等問題。線程池本身就是一個天然的漏斗,可以緩衝一些系統處理不了的連接或請求。但是,當面對十萬甚至百萬級連接的時候,傳統的 BIO 模型是無能爲力的。因此,我們需要一種更高效的 I/O 處理模型來應對更高的併發量。
  • NIO (New I/O): NIO是一種同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,對應 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解爲Non-blocking,不單純是New。它支持面向緩衝的,基於通道的I/O操作方法。 NIO提供了與傳統BIO模型中的 Socket 和 ServerSocket 相對應的 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實現,兩種通道都支持阻塞和非阻塞兩種模式。阻塞模式使用就像傳統中的支持一樣,比較簡單,但是性能和可靠性都不好;非阻塞模式正好與之相反。對於低負載、低併發的應用程序,可以使用同步阻塞I/O來提升開發速率和更好的維護性;對於高負載、高併發的(網絡)應用,應使用 NIO 的非阻塞模式來開發
  • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改進版 NIO 2,它是異步非阻塞的IO模型。異步 IO 是基於事件和回調機制實現的,也就是應用操作之後會直接返回,不會堵塞在那裏,當後臺處理完成,操作系統會通知相應的線程進行後續的操作。AIO 是異步IO的縮寫,雖然 NIO 在網絡操作中,提供了非阻塞的方法,但是 NIO 的 IO 行爲還是同步的。對於 NIO 來說,我們的業務線程是在 IO 操作準備好時,得到通知,接着就由這個線程自行進行 IO 操作,IO操作本身是同步的。查閱網上相關資料,我發現就目前來說 AIO 的應用還不是很廣泛,Netty 之前也嘗試使用過 AIO,不過又放棄了。

Files的常用方法都有哪些?

  • Files. exists():檢測文件路徑是否存在。
  • Files. createFile():創建文件。
  • Files. createDirectory():創建文件夾。
  • Files. delete():刪除一個文件或目錄。
  • Files. copy():複製文件。
  • Files. move():移動文件。
  • Files. size():查看文件個數。
  • Files. read():讀取文件。
  • Files. write():寫入文件。

 

23.反射

什麼是反射機制?

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。

靜態編譯和動態編譯

  • **靜態編譯:**在編譯時確定類型,綁定對象
  • **動態編譯:**運行時確定類型,綁定對象

反射機制優缺點

  • 優點: 運行期類型的判斷,動態加載類,提高代碼靈活度。
  • 缺點: 性能瓶頸:反射相當於一系列解釋操作,通知 JVM 要做的事情,性能比直接的java代碼要慢很多。

反射機制的應用場景有哪些?

反射是框架設計的靈魂。

在我們平時的項目開發過程中,基本上很少會直接使用到反射機制,但這不能說明反射機制沒有用,實際上有很多設計、開發都與反射機制有關,例如模塊化的開發,通過反射去調用對應的字節碼;動態代理設計模式也採用了反射機制,還有我們日常使用的 Spring/Hibernate 等框架也大量使用到了反射機制。

舉例:①我們在使用JDBC連接數據庫時使用Class.forName()通過反射加載數據庫的驅動程序;②Spring框架也用到很多反射機制,最經典的就是xml的配置模式。Spring 通過 XML 配置模式裝載 Bean 的過程:1) 將程序內所有 XML 或 Properties 配置文件加載入內存中; 2)Java類裏面解析xml或properties裏面的內容,得到對應實體類的字節碼字符串以及相關的屬性信息; 3)使用反射機制,根據這個字符串獲得某個類的Class實例; 4)動態配置實例的屬性

 

Java獲取反射的三種方法

1.通過new對象實現反射機制 2.通過路徑實現反射機制 3.通過類名實現反射機制

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

 

24.String相關

字符型常量和字符串常量的區別

  1. 形式上: 字符常量是單引號引起的一個字符 字符串常量是雙引號引起的若干個字符
  2. 含義上: 字符常量相當於一個整形值(ASCII值),可以參加表達式運算 字符串常量代表一個地址值(該字符串在內存中存放位置)
  3. 佔內存大小 字符常量只佔一個字節 字符串常量佔若干個字節(至少一個字符結束標誌)

什麼是字符串常量池?

字符串常量池位於堆內存中,專門用來存儲字符串常量,可以提高內存的使用率,避免開闢多塊空間存儲相同的字符串,在創建字符串時 JVM 會首先檢查字符串常量池,如果該字符串已經存在池中,則返回它的引用,如果不存在,則實例化一個字符串放到池中,並返回其引用。

String 是最基本的數據類型嗎

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

這是很基礎的東西,但是很多初學者卻容易忽視,Java 的 8 種基本數據類型中不包括 String,基本數據類型中用來描述文本數據的是 char,但是它只能表示單個字符,比如 ‘a’,‘好’ 之類的,如果要描述一段文本,就需要用多個 char 類型的變量,也就是一個 char 類型數組,比如“你好” 就是長度爲2的數組 char[] chars = {‘你’,‘好’};

但是使用數組過於麻煩,所以就有了 String,String 底層就是一個 char 類型的數組,只是使用的時候開發者不需要直接操作底層數組,用更加簡便的方式即可完成對字符串的使用。

String有哪些特性

  • 不變性:String 是隻讀字符串,是一個典型的 immutable 對象,對它進行任何操作,其實都是創建一個新的對象,再把引用指向該對象。不變模式的主要作用在於當一個對象需要被多線程共享並頻繁訪問時,可以保證數據的一致性。

  • 常量池優化:String 對象創建之後,會在字符串常量池中進行緩存,如果下次創建同樣的對象時,會直接返回緩存的引用。

  • final:使用 final 來定義 String 類,表示 String 類不能被繼承,提高了系統的安全性。

String爲什麼是不可變的嗎?

簡單來說就是String類利用了final修飾的char類型數組存儲字符,源碼如下圖所以:

/** The value is used for character storage. */
private final char value[];

 

是否可以繼承 String 類

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

 

String str="i"與 String str=new String(“i”)一樣嗎?

不一樣,因爲內存的分配方式不一樣。String str="i"的方式,java 虛擬機會將其分配到常量池中;而 String str=new String(“i”) 則會被分到堆內存中。

 

String s = new String(“xyz”);創建了幾個字符串對象

兩個對象,一個是靜態區的"xyz",一個是用new創建在堆上的對象。

String str1 = "hello"; //str1指向靜態區
String str2 = new String("hello");  //str2指向堆上的對象
String str3 = "hello";
String str4 = new String("hello");
System.out.println(str1.equals(str2)); //true
System.out.println(str2.equals(str4)); //true
System.out.println(str1 == str3); //true
System.out.println(str1 == str2); //false
System.out.println(str2 == str4); //false
System.out.println(str2 == "hello"); //false
str2 = str1;
System.out.println(str2 == "hello"); //true

 

如何將字符串反轉?

使用 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

數組有沒有 length()方法?String 有沒有 length()方法

數組沒有 length()方法 ,有 length 的屬性。String 有 length()方法。JavaScript中,獲得字符串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆。

 

String 類的常用方法都有那些?

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引處的字符。
  • replace():字符串替換。
  • trim():去除字符串兩端空白。
  • split():分割字符串,返回一個分割後的字符串數組。
  • getBytes():返回字符串的 byte 類型數組。
  • length():返回字符串長度。
  • toLowerCase():將字符串轉成小寫字母。
  • toUpperCase():將字符串轉成大寫字符。
  • substring():截取字符串。
  • equals():字符串比較。

 

 

25.String和StringBuffer、StringBuilder的區別是什麼?String爲什麼是不可變的

可變性

String類中使用字符數組保存字符串,private final char value[],所以string對象是不可變的。StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,char[] value,這兩種對象都是可變的。

線程安全性

String中的對象是不可變的,也就可以理解爲常量,線程安全。AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。

性能

每次對String 類型進行改變的時候,都會生成一個新的String對象,然後將指針指向新的String 對象。StringBuffer每次都會對StringBuffer對象本身進行操作,而不是生成新的對象並改變對象引用。相同情況下使用StirngBuilder 相比使用StringBuffer 僅能獲得10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。

對於三者使用的總結

如果要操作少量的數據用 = String

單線程操作字符串緩衝區 下操作大量數據 = StringBuilder

多線程操作字符串緩衝區 下操作大量數據 = StringBuffer

 

網絡編程:https://blog.csdn.net/ThinkWon/article/details/104903925

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章