【JavaGuide筆記】2.1 Java 基礎(chǔ)

原文:JavaGuide

2.1 Java 基礎(chǔ)

1. 面向?qū)ο蠛兔嫦蜻^程的區(qū)別

  • 面向過程:面向過程的性能比面向?qū)ο蟮母?。因為累調(diào)用時需要實例化,開銷比較大,比較消耗資源。但面向過程沒有想象對象易維護、易復(fù)用、易擴展。
  • 面向?qū)ο螅好嫦驅(qū)ο笠拙S護、易復(fù)用、易擴展。因為面向?qū)ο笥蟹庋b、繼承、多態(tài)的特性。

注意: Java 性能差的主要原因不是因為它是面向?qū)ο笳Z言,而是因為Java是半編譯語言,最終執(zhí)行的代碼并不是CPU直接執(zhí)行的二進制。

2. Java 語言有哪些特點

  • 1.簡單易學(xué)
  • 2.面向?qū)ο螅ǚ庋b、繼承、多態(tài))
  • 3.平臺無關(guān)性(Java虛擬機)
  • 4.可靠性
  • 5.安全性
  • 6.支持多線程(C++需要調(diào)用操作系統(tǒng)的多線程功能)
  • 7.支持網(wǎng)絡(luò)編程并且很方便。
  • 8.編譯與解釋并存

3. JVM、JDK、JRE

JVM

Java虛擬機(JVM)是運行Java字節(jié)碼的虛擬機。JVM 有針對不同系統(tǒng)的特定實現(xiàn)(Windows、Linux、MacOS),目的是使用相同的字節(jié)碼,他們都會給出相同的結(jié)果。

Java字節(jié)碼

在Java中,JVM可以理解的代碼就叫做字節(jié)碼(擴展名為.class的文件),它不面向任何特定的處理器,只面向虛擬機。
Java 語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時又保留了解釋型語言可移植的特點。所以Java程序運行時比較高效,并且無序重新編譯便可在不同操作系統(tǒng)的計算機上運行。

Java 代碼編譯:


image.png

Java字節(jié)碼 == JVM ==> 二進制機器碼時,JVM類加載器首先加載字節(jié)碼文件,然后通過解釋器逐行解釋執(zhí)行。這種方式的執(zhí)行速度相對比較慢。而且有些方法和代碼塊是經(jīng)常需要被調(diào)用的(熱點代碼),所以后面引進了JIT編譯器。JIT屬于運行時編譯,JIT完成一次編譯后,會將字節(jié)碼對應(yīng)的機器碼保存下來,下次可以直接使用。

Java字節(jié)碼和不同系統(tǒng)的JVM實現(xiàn)是Java語言“Write Once,Run Anywhere”的關(guān)鍵所在。

JDK 和 JRE

JRE:Java運行時環(huán)境。它是運行已編譯Java 程序所需的所有內(nèi)容的集合。包括Java虛擬機(JVM)、Java類庫、Java命令和其他一些基礎(chǔ)構(gòu)件。但是它不能用于創(chuàng)建新程序。

JDK:Java Development Kit,它是功能齊全的Java SDK。他包含Java運行環(huán)境(JRE)、編譯器(javac)和工具(javadoc和jdb)。JDK能夠創(chuàng)建和編譯程序。

4. Oracle JDK 和 OpenJDK的對比

對于Java 7, 這兩個沒有關(guān)鍵不同的地方。
OpenJDK 是基于Sum捐贈的HotSpot源代碼。

    1. Open JDK 是一個參考模型并且是完全開源的,而Oracle JDK是 OpenJDK的一個實現(xiàn),并不是完全開源的。
    1. Oracle JDK 比 Open JDK 更穩(wěn)定。Open JDK 和 Oracle JDK 的代碼幾乎相同,但 Oracle JDK 有更多的類和一些bug修復(fù),并且Oracle JDK 經(jīng)過了徹底的測試。
    1. 在響應(yīng)性和JVM性能方面,Oracle JDK 相比 Open JDK 提供了更好的性能。

5. Java 和 C++ 的區(qū)別

  • 1.都是面向?qū)ο蟮恼Z言,都支持封裝、繼承和多態(tài)。
    1. Java不提供指針來直接訪問內(nèi)存,程序內(nèi)存更加安全。
    1. Java的類是單繼承的,C++支持多繼承。不過雖然Java的類不支持多繼承,但接口可以多繼承。
  • 4.C語言中,字符串或字符數(shù)組的最后有一個結(jié)束符'\0',Java中沒有結(jié)束符的概念。

6.Java程序的主類

一個程序可以有多個類,但是只能有一個類是主類,包含main()
方法。

7、Java 應(yīng)用程序 VS Java 小程序

  • Java 應(yīng)用程序:從主線程main()方法啟動
  • Java 小程序: 沒喲main方法,主要是嵌在瀏覽器上面運行(調(diào)用 init()或者run()來啟動)

8. 字符型常量 VS 字符串常量

字符型常量 字符串常量
形式 單引號表示的一個字符,例如 'k' 雙引號引起的若干個字符,例如"linyk3"
含義 相當于一個整型值,可以參加表達式運算 代表一個地址,表示該字符串在內(nèi)存中存放的位置
內(nèi)存大小 Java中char占2個字節(jié) 若干個字節(jié)

注意:Java中每一種基本類型所占的存儲空間是不變的:


image.png

9. 構(gòu)造器Constructor 能否被重寫override?

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

10.重寫和重載的區(qū)別

  • 重載:發(fā)生在同一個類中。方法名相同,參數(shù)類型、參數(shù)個數(shù)、參數(shù)順序不同。 方法的返回值和訪問修飾符可以不同。
  • 重寫:發(fā)生在子類中。子類對父類的允許訪問的方法的實現(xiàn)過程進行重新編寫。方法名、參數(shù)列表必須相同,返回值范圍小于等于父類,拋出的異常范圍小于等于父類,訪問修飾符大于等于父類。(方法提供的行為改變,而方法的外貌并沒有改變

11.Java 面向?qū)ο缶幊痰娜筇匦裕?封裝、繼承、多態(tài)

封裝

封裝把一個對象的屬性私有化,同時提供一些可以被外界訪問的屬性的方法。

繼承

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

  • 1.子類擁有父類對象所有的屬性和方法(包括私有屬性和私有方法),但是父類中的私有屬性和方法子類是無法訪問的,只是擁有。
  • 2.子類可以擁有自己屬性和方法,即子類可以對父類進行擴展。
  • 3.子類可以用自己的方式實現(xiàn)父類的方法。
多態(tài)

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

在Java 中有兩種形式可以實現(xiàn)多態(tài):

  • 1.繼承:多個子類對同一個方法的重寫。
  • 2.接口:實現(xiàn)接口并覆蓋接口中的同一方法。

12.String、StringBuffer 和 StringBuilder

String :
Java 9 之前: private final char[] value
Java 9 之后: private final byte[] value

StringBuilder 和 StringBuffer 都繼承自 AbstractStringBuilder 類,char[] value,沒有使用 final 關(guān)鍵字。

每次對String類型進行改變的時候,都會生成一個新的String對象,然后將變量指向新的String對象。StringBuffer 每次都會對自己進行操作,而不是生成新的對象。

特性 String StringBuffer StringBuilder
可變性 不可變 可變 可變
線程安全型 不可變常量,線程安全 同步鎖,線程安全 非線程安全
性能 性能慢 性能快 比StringBuffer性能提升10%-15%

總結(jié):

  • 1.操作少量數(shù)據(jù):適用String
  • 2.單線程操作大量數(shù)據(jù):適用StringBuilder
  • 3.多線程操作大量數(shù)據(jù):適用StringBuffer;

13.自動裝箱和拆箱

  • 裝箱:基本類型 => 包裝類型
  • 拆箱:包裝類型 => 基本類型

14.靜態(tài)方法內(nèi)調(diào)用一個非靜態(tài)成員是非法的

靜態(tài)方法可以通過類調(diào)用,不必通過生成對象來進行調(diào)用。
而非靜態(tài)成員需要通過對象來調(diào)用。

15.Java定義一個無參構(gòu)造方法的作用

Java 程序在執(zhí)行子類的構(gòu)造方法之前,如果沒有用 super()來調(diào)用父類特定的構(gòu)造方法,則會調(diào)用父類中無參構(gòu)造方法,因此,如果父類中只定義了有參數(shù)的構(gòu)造方法,而在子類的構(gòu)造方法中沒有用super() 來調(diào)用父類中特定的構(gòu)造方法,則編譯時間發(fā)生錯誤:Java程序在父類中找不到無參構(gòu)造方法可供執(zhí)行。
解決方案就是在父類中加上一個不做事且沒有參數(shù)的構(gòu)造方法。

16. 略過

17. 接口和抽象類

  • 1.接口的方法默認是 public的,所有方法在接口中不能有實現(xiàn)(Java 8 開始接口方法可以有默認實現(xiàn)),而抽象類可以有非抽象的方法。
  • 2.接口中除了static、final 變量,不能有其他變量,而抽象類中則不一定。
  • 3.一個類中可以實現(xiàn)多個接口,但只能實現(xiàn)一個抽象類。接口自己本身可以通過 extends 關(guān)鍵字擴展多個接口。
  • 4.接口方法默認修飾符是public,抽象方法可以有public、protected和default這些修飾符。(抽象類就是為了被重寫,所以不能使用private 關(guān)鍵字修飾)
  • 5.設(shè)計層面來說,抽象是對類的抽象,是一種模板設(shè)計,而接口是對行為的抽象,是一種行為的規(guī)范。

備注:
1.JDK8中,接口也可以定義靜態(tài)方法,可以直接用接口名調(diào)用。實現(xiàn)類和實現(xiàn)是不可以調(diào)用的。 如果直接實現(xiàn)兩個接口,接口中定義了一樣的默認方法,則必須重寫,不然會報錯。
2.JDK9中,接口被允許定義私有化方法。

Java 接口在JDK7 => JDK9 的變化:

  • 1.JDK7或之前的版本,接口里面只能有常量變量和抽象方法。這些接口方法必須由實現(xiàn)類來實現(xiàn)。
  • 2.JDK8 接口允許有默認方法和靜態(tài)方法功能
    1. JDK9 在接口中引入了私有方法和私有靜態(tài)方法。

18.成員變量 VS 局部變量

成員變量: 屬于類,可以被public、private、static等修飾符所修飾。
局部變量: 方法中定義的變量或方法的參數(shù),不能被訪問控制修飾符及static修飾。
但是成員變量和局部變量都能被final所修飾。

成員變量如果是static 修飾,則屬于類的變量,如果沒有使用staitc修飾,則屬于實例對象的。對象是存在于堆內(nèi)存,局部變量存在于棧內(nèi)存。

成員對象是對象的一部分,隨對象的創(chuàng)建而存在,而局部變量隨著方法的調(diào)用而自動消失。

如果成員變量沒有被賦初始值,則會自動以類型的默認值賦值(如果是final,則必須被顯式的賦值)。局部變量不會自動賦值。

19.創(chuàng)建對象

使用 new 運算符來創(chuàng)建對象實例。對象實例存儲在堆內(nèi)存中,對象引用存儲在棧內(nèi)存中,對象引用指向?qū)ο髮嵗?/p>

20.返回值

方法的返回值:指我們獲取都的某個方法中的代碼執(zhí)行后產(chǎn)生的結(jié)果
返回值的作用:接收結(jié)果,并用于其他操作

21. 構(gòu)造方法

類的構(gòu)造方法:作用是完成對類對象的初始化工作。
如果一個類么有聲明構(gòu)造方法,也可以正確執(zhí)行。因為一個類即使沒有聲明構(gòu)造方法,也會有默認的無參構(gòu)造方法。

22. 構(gòu)造方法的特性

  • 1.函數(shù)名與類名相同
  • 2.沒有返回值,也不能用void聲明構(gòu)造函數(shù)
  • 3.生成類的對象時自動執(zhí)行,無需調(diào)用。

23.靜態(tài)方法 VS 實例方法

  1. 可以通過類或?qū)ο髞碚{(diào)用靜態(tài)方法:類名.方法名,對象名.方法名
  2. 調(diào)用實例方法是能通過對象名.方法名,需要創(chuàng)建對象后才能調(diào)用。
    靜態(tài)方法在訪問本類的成員時,只能訪問靜態(tài)成員,而不允許訪問實例成員變量和實例方法。實例方法無此限制。

24.對象的相等 VS 引用的相等

對象相等:內(nèi)存中存放的內(nèi)容是否相等
引用相等:指向的內(nèi)存地址是否相等

25.子類構(gòu)造方法里調(diào)用父類無參構(gòu)造方法

在調(diào)用子類構(gòu)造方法之前會調(diào)用父類無參構(gòu)造方法,目的是為了幫助子類做初始化工作。

26. == VS equals

  • == : 判斷兩個對象是不是相等。(基本數(shù)據(jù)類型比較的是值,引用類型比較的是內(nèi)存地址)
  • equals: 判斷兩個對象是否相等。Object.equals() 默認是等價于 "==",比較兩個對象的內(nèi)存地址。一般會覆蓋 equals 方法來比較兩個對象的內(nèi)容。
public class test {
    public static void main(String[] args) {
        String a = new String("ab");   // a 為一個引用
        String b = new String("ab");   // b 為另一個引用,內(nèi)容一樣,內(nèi)存地址不一樣
        String aa = "ab";    // 放在常量池中
        String bb = "ab";    // 從常量池中查找
        System.out.println(a == b);       // false
        System.out.println(aa == bb);     // true 
        System.out.println(a.equals(b));  // true
        System.out.println(42 == 42.0);   // true
    }
}

String 的equals 方法是被重寫過的,比較的是兩個對象的內(nèi)容。
當創(chuàng)建String類型的對象時,虛擬機在常量池中查找有沒有已經(jīng)存在的值, 如果有就直接賦值給當前引用, 沒有就重新創(chuàng)建一個String對象。

27 hashCode 與 equals

  • hashCode() : 是在Object 對象中的函數(shù),可以獲取哈希碼,也稱散列碼,是一個int整數(shù)。在哈希表中用來確定索引的位置,在其他地方?jīng)]有作用。

hashCode() 默認的行為是對堆上的對象產(chǎn)生獨特的值。如果沒有重寫hashCode(), 則該class的兩個對象無論如何都不會相等。

28.Java中只有值傳遞

29.線程、進程、程序

程序:含有指令和數(shù)據(jù)的文件,程序是靜態(tài)的代碼。
進程:是系統(tǒng)運行的基本單位,是操作系統(tǒng)分配CPU時間、內(nèi)存空間、文件和輸入輸出設(shè)備使用權(quán)的單位。
線程:線程是進程劃分為更小的運行單位,一個進程可以包含1個或多個線程。

30. 線程基本狀態(tài)

Java 線程在運行的生命周期有6種不同的狀態(tài):

狀態(tài)名稱 說明
new 初始狀態(tài),線程被構(gòu)建,但是還沒有調(diào)用start()方法
runnable 運行狀態(tài),Java線程將就緒和運行時籠統(tǒng)的成為運行中
blocked 阻塞狀態(tài),線程阻塞于鎖
waiting 等待狀態(tài),線程進入等待狀態(tài),需要等待其他線程做出一些特定動作(通知或中斷)
time_waiting 超時等待狀態(tài),相比于wating,它可以在指定時間內(nèi)自行返回
terminated 終止狀態(tài),表示當前線程已經(jīng)執(zhí)行完畢
image.png

31.final 關(guān)鍵字

  • 1.final 修飾變量:不可變。如果是基本類型,則其數(shù)值在初始化之后不能更改,如果是引用類型,則在初始化之后不能指向另一個對象。
  • 2.final 修飾方法:一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率,因為早期的Java會將final轉(zhuǎn)化為內(nèi)嵌調(diào)用。類中所有private的方法都隱式地指定為final。
  • 3.final 修飾類: 表示這個類不能被繼承,final類中的所有成員方法都會被隱式的指定為final方法。

32. Java 異常

image.png

Java中,所有的異常都有一個共同的祖先:java.lang.Throwable 類。它有兩個重要的子類Exception(異常)Error(錯誤)。

  • Error(錯誤):是程序無法處理的錯誤,表示運行應(yīng)用程序中較嚴重的問題。
  • Exception(異常):程序本身可以處理的異常。
異常處理:
  • try:用來捕獲異常,其后可接0個或多個catch塊,如果沒有catch塊,則必須接一個finally塊。
  • catch: 用來處理try 捕獲到的異常。
  • finally:無論是否捕獲或處理異常,finally的語句都會被執(zhí)行。當在try 塊或 catch 塊遇到 return語句時,finally 語句塊將在方法返回之前被執(zhí)行。

finally 塊不會被執(zhí)行的情況:

  • 1.在finally語句塊的第一行發(fā)生了異常。
  • 2.已經(jīng)執(zhí)行了 System.exit(int) 退出程序。
  • 3.程序所在的程序死亡。
  • 4.關(guān)閉CPU。

注意:當try語句和finally語句都有return語句時,在方法返回之前,finally語句的內(nèi)容將被執(zhí)行,并且finally語句的返回值會覆蓋原來的返回值:

public static int f(int value) {
      try {
           return value * value;
      } finally {
           if(value == 2) {
                  return 0;
           }
      }
}

如果調(diào)用f(2), 返回值將是0.

33.Java 序列化

當一個類實現(xiàn)了serializable接口,如果沒有顯式的定義 serialVersionUID,Java 序列化機制會根據(jù)編譯的Class自動生成一個serialVersionUID,用作序列化版本比對。如果Class文件沒有發(fā)生變化,就算編譯多次, serialVersionUID 也不會變化。
如果我們不想通過編譯來強制劃分軟件版本,集實現(xiàn)序列化接口的實體能夠兼容先前的版本,就需要顯式的定義序列化版本UID,這樣即使Class 文件變化了,只要serialVersionUID的值不變,就可以進行正確的序列化和反序列化。
private static final long serialVersionUID = 1L

對于不想進行序列化的變量,可以使用 transient 關(guān)鍵字修飾。
transient:阻止實例中用此關(guān)鍵字修飾的變量序列化。當反序列化時,被修飾的變量不會被持久化和恢復(fù)。
只能修飾變量,不能修飾類和方法。

34. 獲取鍵盤輸入的兩種方法

方法1. 通過Scanner
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
方法2. 通過BufferedReader
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();

35.Java中IO流

Java中IO流分為幾種?
  • 流的流向分,可以分為輸入流和輸出流;
  • 操作單元分,可以分為字節(jié)流和字符流;
  • 流的角色分,可以分為節(jié)點流和處理流。

Java IO流共涉及40多個類,都是從如下4個抽象類基類中派生出來的:

  • InputStream/ Reader:所有輸入流的基類,前者是字節(jié)輸入流,后者是字符輸入流。
  • OutputStream/ Writer:所有輸出流的基類,前者是字節(jié)輸出流,后者是字符輸出流。
既然有了字節(jié)流,為什么還要有字符流

不管是文件讀寫還是網(wǎng)絡(luò)發(fā)送和接收,信息的最小存儲單元都是字節(jié)。
字符流是由Java虛擬機將字節(jié)轉(zhuǎn)換得到的,但是轉(zhuǎn)換過程非常耗時,并且很容易因為編碼類型出現(xiàn)編碼問題,所有干脆提供直接操作字符的接口,方便平時對字符進行流操作。
如果是音頻文件、圖片等媒體文件,建議用字節(jié)流;
如果涉及到字符,建議用字符流。

BIO,NIO,AIO有什么區(qū)別
  • BIO(Blocking I/O):同步阻塞I/O模式,數(shù)據(jù)的讀取寫入必須阻塞在一個線程內(nèi)等待其完成。適用于活動連接數(shù)不是特別高(小于單機1000)的情況,可以讓每一個連接專注于自己的I/O并且編程模型簡單,也不用考慮系統(tǒng)的過載、限流等問題。線程池本身就是一個天然漏斗,可以緩沖一些系統(tǒng)處理不了的連接或請求。但是當面對十萬甚至百萬級連接時,就不適用了,需要一種更高效的I/O處理模型來應(yīng)對更高的并發(fā)量。

  • NIO(New I/O): 同步非阻塞I/O模式,NIO的N可以理解為 Non-blocking, 不單純是New。它支持面向緩沖的,基于通道的I/O操作方法。 在Java1.4引入NIO框架,對應(yīng) java.nio 包,提供了Channel,Selector, Buffer等抽象。NIO 提供了與傳統(tǒng)BIO模型中 Socket 和 ServerSocket 相對應(yīng)的 SocketChannel 和 ServerSocketChannel 兩種不同的套接字通道實現(xiàn)。 兩種通道都支持阻塞(性能和可靠性不好)和非阻塞(性能和可靠性好)兩種模式。

    • 低負載、低并發(fā) => 采用BIO模式
    • 高負載、高并發(fā) => 采用NIO非阻塞模式
  • AIO(Asynchronous I/O): AIO異步非阻塞IO模型。是基于事件和回調(diào)機制實現(xiàn)的,也即是應(yīng)操作之后會直接返回,不會堵塞在那里,當后臺處理完成,操作系統(tǒng)會通知相應(yīng)的線程進行后續(xù)的操作。AIO也就是NIO2,Java7中引入NIO的改進版NIO2。

36. 常見關(guān)鍵字總結(jié):final/static/this/super

final 關(guān)鍵字

final 關(guān)鍵字主要用在3個地方:變量、方法、類。

  • 1.final修飾變量:如果是基本類型,則其數(shù)值在初始化之后便不能修改;如果是引用類型,則在初始化之后不能再指向另一個對象。
  • 2.final修飾方法:第一個原因是把方法鎖定,以防任何繼承的類修改它的含義。第二個原因是效率,早期Java會把final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用,現(xiàn)在的Java已經(jīng)不采用了內(nèi)嵌優(yōu)化了。類中所有的private 方法都隱式的指定為final。
  • 3.final修飾:表明這個類已經(jīng)不能被繼承。final類中的所有成員方法都會被隱式的指定為final方法。
static 關(guān)鍵字

static 關(guān)鍵字主要有以下四種使用場景:

  • 1.修飾成員變量和成員方法:被static修飾的成員屬于類,不屬于單個對象,成員被所有對象共享,并且可以通過類名直接調(diào)用。靜態(tài)變量存放在Java內(nèi)存區(qū)域的方法區(qū)。調(diào)用格式:類名.靜態(tài)變量名類名.靜態(tài)方法名()
  • 2.靜態(tài)代碼塊:靜態(tài)代碼塊定義在類的方法外,不管創(chuàng)建多少對象,靜態(tài)代碼塊只執(zhí)行一次。靜態(tài)代碼塊在非靜態(tài)代碼塊之前執(zhí)行。(靜態(tài)代碼塊 => 非靜態(tài)代碼塊 => 構(gòu)造方法)
  • 3.靜態(tài)內(nèi)部類:static修飾類的話只能修飾內(nèi)部類,靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類之間一個最大的區(qū)別就是:非靜態(tài)內(nèi)部類在編譯完成之后會隱含的保存著一個引用,指向創(chuàng)建它的外圍類。但是靜態(tài)內(nèi)部類沒有這個引用,這也意味著1.靜態(tài)內(nèi)部類的創(chuàng)建不需要依賴外圍類的創(chuàng)建;2.它不能使用任何外圍類的非static成員變量和方法。
// 靜態(tài)內(nèi)部類實現(xiàn)單例模式
public class Singleton {
    // 聲明為 private 避免調(diào)用默認構(gòu)造方法創(chuàng)建對象
    private Singleton() {}

    // 聲明為private,表明靜態(tài)內(nèi)部類只能在Singleton類中訪問
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance() {
        return SingletonHolder.INSTANCE;
    }
}
  • 4.靜態(tài)導(dǎo)包:Java1.5之后的新特性,可以用來導(dǎo)入類中的靜態(tài)資源。格式為 import static 這兩個關(guān)鍵字連用可以指定導(dǎo)入某個類中的指定靜態(tài)資源,并且不需要使用類名調(diào)用類中的靜態(tài)成員,可以直接使用類中靜態(tài)成員變量和方法。
this 關(guān)鍵字

this 關(guān)鍵字用于引用類的當前實例,例如

class Manager {
    Employees[] employees;
    void manageEmployees() {
        int totalEmp = this.employees.length;
        System.out.println("Total employees: " + totalEmp)'
        this.report();
    }

    void report() { }
}

上面的例子中,this關(guān)鍵字用于兩個地方:

  • this.employees.length: 訪問類Manager的當前實例的變量。
  • this.report(): 調(diào)用Manager的當前實例的方法。
    this 關(guān)鍵字在這里也是可以省略的。
super 關(guān)鍵字

super 關(guān)鍵字用于從子類訪問父類的變量和方法,例如:

public class SupperClass {
    protected int number;
    protected showNumber() {      
        System.out.println("number = " + number);
    }
}

public class SubClass extends SupperClass {
    void bar() {
        super.number = 10;
        super.showNumber();
    }
 }

上面的例子中,SubClass 訪問父類的成員變量number 并調(diào)用父類的showNumber() 方法。

注意:在構(gòu)造方法中使用super() 調(diào)用父類中的其他構(gòu)造方法時,該語句必須處于構(gòu)造器的首行,否則編譯器會報錯。另外,this調(diào)用本類中其他構(gòu)造方法時,也要放在首行。
this 和 super 不能用在static 方法中。

37.Collections 工具類和Arrays 工具類常見方法總結(jié)

Collections 工具類常用方法
  • 1.排序
  • 2.查找
  • 3.同步控制(不推薦,需要線程安全的集合類型時請考慮使用JUC包下的并發(fā)集合)
排序操作
void reverse(List list); // 反轉(zhuǎn)
void shuffle(List list); // 隨機排序
void sort(List list); // 按照自然排序的升序
void sort(List list, Comparator c); // 定制排序,由Comparator控制排序邏輯
void swap(List list, int i, int j); // 交換兩個索引位置的元素
void swap(List list, int distance); // 旋轉(zhuǎn),當distance為整數(shù),將list后distance個元素整體移到前面,當distance為負數(shù),將list的前distance個元素整體移到后面。
查找、替換操作:
int binarySearch(List list, Object key); // 二分查找,返回索引,注意list要求是有序的
int max(Collection coll); // 根據(jù)元素的自然順序,返回最大的元素
int max(Collection coll, Comparator c); // 根據(jù)定制順序,返回最大的元素
void fill(List list, Object obj); //用指定元素obj替換list中所有元素
void frequency(Collection c, Object o) ; // 統(tǒng)計元素c出現(xiàn)的次數(shù)
void indexOfSubList(List list, List target); // 統(tǒng)計target在list中第一次出現(xiàn)的索引,找不到就返回-1. 類比于 int lastIndexOfSubList(List list, List target)
boolean replaceAll(List list, Object oldVal, Object newVal); // 用新元素替換舊元素
同步控制

Collections 提供了多個synchronizedXxx()方法,該方法可以將指定集合包裝成線程同步的集合,從而解決多線程并發(fā)訪問集合時的線程安全問題。不過最好不要使用,英文效率非常低,建議使用JUC包下的并發(fā)集合。
HashSet、TreeSet、ArrayList、LinkedList、HashMap、TreeMap 都是線程不安全的。

synchronizedCollection(Collection<T> c); // 返回線程安全的collection
synchronizedList(List<T> list); // 返回線程安全的list
synchronizedMap(Map<K,V> map); // 返回線程安全的map
synchronizedSet(Set<T> set); // 返回線程安全的set;

Collections 還可以設(shè)置不可變集合:

  • emptyXxx(): 返回一個空的、不可變的集合對象。
  • singletonXxx():返回一個只包含指定對象的不可變集合。
  • unmodifiableXxx():返回指定集合對象的不可變視圖。
// Collection.emptyXxx(); 創(chuàng)建一個空的、不可改變的Xxx對象
List<Object> list = Collections.emptyList();
Set<Object> set = Collections.emptySet();
Map<Object, Object> map = Collections.emptyMap();

ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(1);
arrayList.add(3);
arrayList.add(3);
HashSet<Integer> integers1 = new HashSet<>();
integers1.add(1);
integers1.add(3);
integers1.add(2);

//Collections.emptyXXX();創(chuàng)建一個空的、不可改變的XXX對象
List<Object> list = Collections.emptyList();  // []
Set<Object> objects = Collections.emptySet(); // []
  Map<Object, Object> objectObjectMap = Collections.emptyMap(); // {}

//Collections.singletonXXX();
List<ArrayList<Integer>> arrayLists = Collections.singletonList(arrayList);  // [[1,3, 3]]
Set<ArrayList<Integer>> singleton = Collections.singleton(arrayList); // [[1,3]]
Map<String, String> nihao = Collections.singletonMap("1", "你好"); //{1=你好}

//unmodifiableXXX();創(chuàng)建普通XXX對象對應(yīng)的不可變版本
List<Integer> integers = Collections.unmodifiableList(arrayList);  // [[1,3, 3]]
Set<Integer> integers2 = Collections.unmodifiableSet(integers1); //[1, 2, 3]

//添加出現(xiàn)異常:java.lang.UnsupportedOperationException
// list.add(1);
// arrayLists.add(arrayList);
// integers.add(1);
Arrays 類的常見操作
  • 1.排序 sort()parallelSort()
int a[] = { 1, 3, 2, 7, 6, 5, 4, 9 };
Arrays.sort(a); // sort(int[] a)方法按照數(shù)字順序排列指定的數(shù)組。
Arrays.sort(a, 2, 6);  // sort(int[] a,int fromIndex,int toIndex)按升序排列數(shù)組的指定范圍
Arrays.parallelSort(c);  // parallelSort(int[] a) 按照數(shù)字順序排列指定的數(shù)組(并行的)。同sort方法一樣也有按范圍的排序
char d[] = { 'a', 'f', 'b', 'c', 'e', 'A', 'C', 'B' };
Arrays.parallelSort(d); // parallelSort給字符數(shù)組排序,sort也可以
String[] strs = { "abcdehg", "abcdefg", "abcdeag" };   
Arrays.sort(strs); // parallelSort給字符串排序,sort也可以
System.out.println(Arrays.toString(strs));//[abcdeag, abcdefg, abcdehg]
  • 2.查找 binarySearch()
char[] e = { 'a', 'f', 'b', 'c', 'e', 'A', 'C', 'B' };
Arrays.sort(e);  // 排序后再進行二分查找,否則找不到
int s = Arrays.binarySearch(e, 'c');
System.out.println("字符c在數(shù)組的位置:" + s);
  • 3.比較 equals()
char[] e = { 'a', 'f', 'b', 'c', 'e', 'A', 'C', 'B' };
char[] f = { 'a', 'f', 'b', 'c', 'e', 'A', 'C', 'B' };
Arrays.equals(e, f) // true
  • 4.填充 fill()
int[] g = { 1, 2, 3, 3, 3, 3, 6, 6, 6 };
Arrays.fill(g, 3);  //333333333
int[] h = { 1, 2, 3, 3, 3, 3, 6, 6, 6, };
Arrays.fill(h, 0, 2, 9); // 993333666 數(shù)組中指定范圍元素重新分配值  
  • 5.轉(zhuǎn)列表 asList()
List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
  • 6.轉(zhuǎn)字符串 toString()
char[] k = { 'a', 'f', 'b', 'c', 'e', 'A', 'C', 'B' };
System.out.println(Arrays.toString(k));// [a, f, b, c, e, A, C, B]
  • 7.復(fù)制 copyOf()
int[] h = { 1, 2, 3, 3, 3, 3, 6, 6, 6, };
int i[] = Arrays.copyOf(h, 6);   //123333  copyOf 方法實現(xiàn)數(shù)組復(fù)制,h為數(shù)組,6為復(fù)制的長度
// copyOfRange將指定數(shù)組的指定范圍復(fù)制到新數(shù)組中
int j[] = Arrays.copyOfRange(h, 6, 11); //結(jié)果66600(h數(shù)組只有9個元素這里是從索引6到索引11復(fù)制所以不足的就為0)

38.深拷貝 VS 淺拷貝

  • 深拷貝:基本類型進行值傳遞,對引用類型,創(chuàng)建一個新的對象,并復(fù)制其內(nèi)容。
  • 淺拷貝:基本類型進行值傳遞,對引用類型,進行引用傳遞的拷貝。


    image.png

39. 補充: 抽象類 VS 接口

參考:深入理解Java的接口和抽象類

1 抽象方法

抽象方法是一種頁數(shù)的方法,它只有聲明,沒有具體的實現(xiàn)。

abstract void fun()
2 抽象類

如果一個類含有抽象方法,就稱這個類是抽象類。抽象類在類前用 abstract 關(guān)鍵字修飾。

[public] abstract class ClassName {
    abstract void fun();
}

抽象類就是為了繼承而存在的。
包含抽象方法的類成為抽象類,但抽象類中也可以有非抽象方法。抽象類和普通方法一樣,可以擁有成員變量和普通的成員方法。
抽象類和普通類的區(qū)別:

    1. 抽象類必須為public 或 protected,默認是public(為了繼承)
    1. 抽象類不能用來實例化,也就是不能用來創(chuàng)建對象。
  • 3.如果一個類繼承了抽象類,則子類必須實現(xiàn)父類的抽象方法。
    除了這3點,其他和普通類沒有區(qū)別。
3. 接口

接口泛指提供給別人調(diào)用的方法或函數(shù),接口是對行為的抽象。

[public] interface InterfaceName {

}

接口中可以含有變量和方法,但是接口中的變量和方法會被隱式的指定

  • 接口變量: public static final
  • 接口方法: public abstract
    接口中不能有具體的實現(xiàn),接口中的方法都必須是抽象方法。
    所以,可以把接口認為是一種極度抽象的類型。
4. 抽象類和接口的區(qū)別
  • 1.抽象類是對一種事物的抽象,是對類的整體(屬性+行為)的抽象
  • 2.接口是對行為的抽象。

類比:飛機和鳥是不同的事物,但有一個共性,都會飛行。
所以可以將飛機設(shè)計為一個類Airplane,將鳥設(shè)計為一個類Bird。但是不能將飛行也設(shè)計為類。可以將飛行設(shè)計為一個接口Fly,里面包含了飛行的方法fly().
不同類型的飛機和鳥直接繼承Airplane 和 Bird類即可,然后根據(jù)需要去實現(xiàn)Fly 接口。
也就是說,一個類繼承了抽象類,則子類必須是抽象類的種類。而接口實現(xiàn)表示的是有沒有,具不具備這種行為。(能飛,則可以實現(xiàn)Fly接口,不能飛則不行)

設(shè)計層面,抽象類是作為很多子類的父類,是一種模板設(shè)計。
接口是一種行為規(guī)范,是一種輻射式設(shè)計。
對于抽象類,如果添加了新的方法,子類可以不進行變更。
如果接口進行了變更,則實現(xiàn)這個接口的類都必須進行相應(yīng)的改動。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,812評論 0 11
  • 面向?qū)ο笾饕槍γ嫦蜻^程。 面向過程的基本單元是函數(shù)。 什么是對象:EVERYTHING IS OBJECT(萬物...
    sinpi閱讀 1,220評論 0 4
  • 第6章類文件結(jié)構(gòu) 6.1 概述 6.2 無關(guān)性基石 6.3 Class類文件的結(jié)構(gòu) java虛擬機不和包括java...
    kennethan閱讀 1,070評論 0 2
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法,可以作為本類的靜態(tài)方法來...
    XLsn0w閱讀 1,427評論 0 2
  • 今天閱讀第五章 戰(zhàn)爭開始。人渣阿塞夫登場。阿富汗的世界變了。國王跑了,要共和了。 但是,少爺還是少爺,...
    田邊細語閱讀 176評論 0 0

友情鏈接更多精彩內(nèi)容