Java基礎知識點——常見面試題總結

目錄

1 、什麼是B/S架構?什麼是C/S架構

  1. B/S(Browser/Server),瀏覽器/服務器程序
  2. C/S(Client/Server),客戶端/服務端,桌面應用程序

2 、Java都有那些開發平臺?

  1. JAVA SE:主要用在客戶端開發

  2. JAVA EE:主要用在web應用程序開發

  3. JAVA ME:主要用在嵌入式應用程序開發

3 、什麼是JDK?什麼是JRE?

  1. JDK:java development kit:java開發工具包,是開發人員所需要安裝的環境
  2. JRE:java runtime environment:java運行環境,java程序運行所需要安裝的環境
    在這裏插入圖片描述

4 、Java語言有哪些特點

  1. 簡單易學、有豐富的類庫
  2. 面向對象(Java最重要的特性,讓程序耦合度更低,內聚性更高)
  3. 與平臺無關性(JVM是Java跨平臺使用的根本)
  4. 可靠安全
  5. 支持多線程

5 、面向對象和麪向過程的區別

1. 面向過程:

一種較早的編程思想,顧名思義就是該思想是站着過程的角度思考問題,強調的就是功能行爲,功能的執行過程,即先後順序,而每 一個功能我們都使用函數(類似於方法)把這些步驟一步一步實現。使用的時候依次調用函數就可以了。

2. 面向對象:

一種基於面向過程的新編程思想,顧名思義就是該思想是站在對象的角度思考問題,我們把多個功能合理放到不同對象裏,強調的是 具備某些功能的對象。

具備某種功能的實體,稱爲對象。面向對象最小的程序單元是:類。面向對象更加符合常規的思維方式,穩定性好,可重用性強,易 於開發大型軟件產品,有良好的可維護性。

在軟件工程上,面向對象可以使工程更加模塊化,實現更低的耦合和更高的內聚。

6 、什麼是數據結構?

計算機保存,組織數據的方式

7 、Java的數據結構有那些?

1.線性表(ArrayList)
2.鏈表(LinkedList)
3.棧(Stack)
4.隊列(Queue )
5.圖(Map)
6.樹(Tree)

8 、什麼是OOP?

面向對象編程

9 、類與對象的關係?

類是對象的抽象,對象是類的具體,類是對象的模板,對象是類的實例

10 、Java中有幾種數據類型

整形:byte,short,int,long
浮點型:float,double
字符型:char
布爾型:boolean

11 、標識符的命名規則。

1. 標識符的含義:

是指在程序中,我們自己定義的內容,譬如,類的名字,方法名稱以及變量名稱等等,都是標識符。

2. 命名規則:(硬性要求)

標識符可以包含英文字母,0-9的數字,$以及_

標識符不能以數字開頭

標識符不是關鍵字

3. 命名規範:(非硬性要求)

類名規範:首字符大寫,後面每個單詞首字母大寫(大駝峯式)。

變量名規範:首字母小寫,後面每個單詞首字母大寫(小駝峯式)。

方法名規範:同變量名。

12 、instanceof關鍵字的作用

instanceof 嚴格來說是Java中的一個雙目運算符,用來測試一個對象是否爲一個類的實例,用法爲:

boolean result = obj instanceof Class

其中 obj 爲一個對象,Class 表示一個類或者一個接口,當 obj 爲 Class 的對象,或者是其直接或間接子類,或者是其接口的實現類,結果result 都返回 true,否則返回false。

注意:編譯器會檢查 obj 是否能轉換成右邊的class類型,如果不能轉換則直接報錯,如果不能確定類型,則通過編譯,具體看運行時定。

inti=0;
System.out.println(i instanceof Integer);//編譯不通過i必須是引用類型,不能是基本類型
System.out.println(i instanceof Object);//編譯不通過
Integer integer=newInteger(1);
System.out.println(integer instanceof Integer);//true
//false,在JavaSE規範中對instanceof運算符的規定就是:如果obj爲null,那麼將返回false。
System.out.println(nullinstanceofObject);

13 、什麼是隱式轉換,什麼是顯式轉換

顯示轉換就是類型強轉,把一個大類型的數據強制賦值給小類型的數據;隱式轉換就是大範圍的變量能夠接受小範圍的數據;隱式轉換和顯 式轉換其實就是自動類型轉換和強制類型轉換。

14 、Char類型能不能轉成int類型?能不能轉化成string類型,能不能轉成double類型

Char在java中也是比較特殊的類型,它的int值從 1 開始,一共有 2 的 16 次方個數據;

Char<int<long<float<double;Char類型可以隱式轉成int,double類型,但是不能隱式轉換成string;如果char類型轉成byte,short類型的時候,需要強轉。

15 、什麼是拆裝箱?

  1. 裝箱就是自動將基本數據類型轉換爲包裝器類型(int–>Integer);調用方法:Integer的
    valueOf(int) 方法
    拆箱就是自動將包裝器類型轉換爲基本數據類型(Integer–>int)。調用方法:Integer的intValue方 法
    在Java SE5之前,如果要生成一個數值爲 10 的Integer對象,必須這樣進行:
Integer i = new Integer(10);

而在從Java SE5開始就提供了自動裝箱的特性,如果要生成一個數值爲 10 的Integer對象,只需要這
樣就可以了:

Integer i = 10;

面試題 1 : 以下代碼會輸出什麼?

public class Main {
 public static void main(String[] args) {
        Integer i1 = 100;
        Integer i2 = 100;
        Integer i3 = 200;
        Integer i4 = 200;
        System.out.println(i1==i2);
        System.out.println(i3==i4);
 } }

結果:

true
false

16 、Java中的包裝類都是那些?

byte:Byte,short:Short,int:Integer,long:Long,float:Float,double:Double,char:Character ,boolean:Boolean

17 、一個java類中包含那些內容?

屬性、方法、內部類、構造方法、代碼塊。

18 、那針對浮點型數據運算出現的誤差的問題,你怎麼解決?

使用Bigdecimal類進行浮點型數據的運算

19 、面向對象的特徵有哪些方面?

抽象:

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

繼承:

繼承是從已有類得到繼承信息創建新類的過程.提供繼承信息的類被稱爲父類(超類、基類) ;得到繼承信息的類被稱爲子類(派生類)。繼承讓變化中的軟件系統有了一定的延續性 ,同時繼承也是封裝程序中可變因素的重要手段。

封裝:

通常認爲封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(可以想想普通洗衣機和全自動洗衣機的差別,明顯全自動洗衣機封裝更好因此操作起來更簡單;我們現在使用的智能手機也是封裝得足夠好的,因爲幾個按鍵就搞定了所有的事情)。

多態性:

多態性是指允許不同子類型的對象對同一消息作出不同的響應。簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。多態性分爲編譯時的多態性和運行時的多態性。如果將對象的方法視爲對象向外界提供的服務,那麼運行時的多態性可以解釋爲:當 A 系統訪問 B 系統提供的服務時,B系統有多種提供服務的方式,但一切對 A 系統來說都是透明的(就像電動剃鬚刀是 A 系統,它的供電系統是 B 系統,B 系統可以使用電池供電或者用交流電,甚至還有可能是太陽能,A 系統只會通過 B 類對象調用供電的方法,但並不知道供電系統的底層實現是什麼,究竟通過何種方式獲得了動力)。方法重載(overload)實現的是編譯時的多態性(也稱爲前綁定),而方法(override)
實現的是運行時的多態性(也稱爲後綁定)。運行時的多態是面向對象最精髓的東西,要實現多態需要做兩件事:1). 方法重寫(子類繼承父類並重寫父類中已有的或抽象的方法);2). 對象造型(用父類型引用引用子類型對象,這樣同樣的引用調用同樣的方法就會根據子類對象的不同而表現出不同的行爲)。

20 、 訪問修飾符 public,private,protected,以及不寫(默認) 時的區別?

修飾符 當前類 同 包 子 類 其他包
public
protected 不能
default 不能 不能
private 不能 不能 不能

類的成員不寫訪問修飾時默認爲 default。默認對於同一個包中的其他類相當於公 開(public),對於不是同一個包中的其他類相當於私有
(private)。受保護 (protected)對子類相當於公開,對不是同一包中的沒有父子關係的類相當於私 有。Java 中,外部類的修飾符只能
是 public 或默認,類的成員(包括內部類)的 修飾符可以是以上四種。

21 、String 是最基本的數據類型嗎?

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

22 、float f=3.4;是否正確?

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

23 、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);其中有隱含的強制類型轉換。

24 、 重載和重寫的區別

重寫* (Override)*

從字面上看,重寫就是 重新寫一遍的意思。其實就是在子類中把父類本身有的方法重新寫一遍。子類繼承了父類原有的方法,但有時子類並不想原封不動的繼承父類中的某個方法,所以在方法名,參數列表,返回類型(除過子 類中方法的返回值是父類中方法返回值的子類時)都相同的情況下, 對方法體進行修改或重寫,這就是重寫。但要 注意子類函數的訪問修飾權限不能少於父類的。

public class Father {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Son s = new Son();
        s.sayHello();
   }
    public void sayHello() {
   System.out.println("Hello");
   }
}
class Son extends Father{
    @Override
    public void sayHello() {
        // TODO Auto-generated method stub
        System.out.println("hello by ");
   }
}

原因: 在某個範圍內的整型數值的個數是有限的,而浮點數卻不是。

重寫 總結:

1.發生在父類與子類之間
2.方法名,參數列表,返回類型(除過子類中方法的返回類型是父類中返回類型的子類)必須相同
3.訪問修飾符的限制一定要大於被重寫方法的訪問修飾符(public>protected>default>private)
4.重寫方法一定不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的檢查型異常

重載(Overload)

在一個類中,同名的方法如果有不同的參數列表( 參數類型不同、參數個數不同甚至是參數順序不同

則視爲重載。同時,重載對返回類型沒有要求,可以相同也可以不同,但 不能通過返回類型是否相同來

判斷重載

public class Father {
 public static void main(String[] args) {
        // TODO Auto-generated method stub
        Father s = new Father();
        s.sayHello();
        s.sayHello("wintershii");
     }
    public void sayHello() {
   System.out.println("Hello");
   }
    public void sayHello(String name) {
   System.out.println("Hello" + " " + name);
   }
}

重載總結:

1.重載Overload是一個類中多態性的一種表現

2.重載要求同名方法的參數列表不同(參數類型,參數個數甚至是參數順序)

3.重載的時候,返回值類型可以相同也可以不相同。無法以返回型別作爲重載函數的區分標準

25 、equals與==的區別

==:

== 比較的是變量(棧)內存中存放的對象的(堆)內存地址,用來判斷兩個對象的地址是否相同,即是否是指相同一個對象。比較的是真正意義上的指針操作。
1 、比較的是操作符兩端的操作數是否是同一個對象。
2 、兩邊的操作數必須是同一類型的(可以是父子類之間)才能編譯通過。
3 、比較的是地址,如果是具體的阿拉伯數字的比較,值相等則爲true,如:

int a=10 與 long b=10L 與 double c=10.0都是相同的(爲true),因爲他們都指向地址爲 10 的堆。

equals:

equals用來比較的是兩個對象的內容是否相等,由於所有的類都是繼承自java.lang.Object類的,所以適用於所有對象,如果沒有對該方法進行覆蓋的話,調用的仍然是Object類中的方法,而Object中的equals方法返回的卻是==的判斷。

總結:

所有比較是否相等時,都是用equals 並且在對常量相比較時,把常量寫在前面,因爲使用object的equals object可能爲null 則空指針在阿里的代碼規範中只使用equals ,阿里插件默認會識別,並可以快速修改,推薦安裝阿里插件來排查老代碼使用“==”,替換成equals

36 、++i與i++的區別

i++:先賦值,後計算
++i:先計算,後賦值
這裏更細緻的解釋參見:
鏈接: 面試時經常被問到的問題:i++與++i的區別?圖文詳解.

37 、程序的結構有那些?

順序結構
選擇結構
循環結構

38 、數組實例化有幾種方式?

靜態實例化:

創建數組的時候已經指定數組中的元素,

int [] a= new int[]{ 1 , 3 , 3}

動態實例化:

實例化數組的時候,只指定了數組長度,數組中所有元素都是數組類型的默認值

39 、Java中各種數據默認值

Byte,short,int,long默認是都是 0

Boolean默認值是false

Char類型的默認值是’’

Float與double類型的默認是0.

對象類型的默認值是null

40 、Java常用包有那些?

Java.lang
Java.io
Java.sql
Java.util
Java.awt
Java.net
Java.math

41 、Object類常用方法有那些?

Equals
Hashcode
toString
wait
notify
clone
getClass

42 、java中有沒有指針?

有指針,但是隱藏了,開發人員無法直接操作指針,由jvm來操作指針

43 、java中是值傳遞引用傳遞?

理論上說,java都是引用傳遞,對於基本數據類型,傳遞是值的副本,而不是值本身。對於對象類型,傳遞是對象的引用,當在一個方法操
作操作參數的時候,其實操作的是引用所指向的對象。

44 、實例化數組後,能不能改變數組長度呢?

不能,數組一旦實例化,它的長度就是固定的

45 、假設數組內有 5 個元素,如果對數組進行反序,該如何做?

創建一個新數組,從後到前循環遍歷每個元素,將取出的元素依次順序放入新數組中

46 、形參與實參區別

實參(argument):

全稱爲"實際參數"是在調用時傳遞給函數的參數. 實參可以是常量、變量、表達式、函數等, 無論實參是何種類型的量,在進行函數調用
時,它們都必須具有確定的值, 以便把這些值傳送給形參。 因此應預先用賦值,輸入等辦法使實參獲得確定值。

形參(parameter):

全稱爲"形式參數" 由於它不是實際存在變量,所以又稱虛擬變量。是在定義函數名和函數體的時候使用的參數,目的是用來接收調用該函數
時傳入的參數.在調用函數時,實參將賦值給形參。因而,必須注意實參的個數,類型應與形參一一對應,並且實參必須要有確定的值。

形參出現在 函數定義 中,在整個函數體內都可以使用, 離開該函數則不能使用。

實參出現在 主調函數中,進入被調函數後,實參變量也不能使用

形參和實參的功能是作數據傳送。發生函數調用時, 主調函數把實參的值傳送給被調函數的形參從而實現主調函數向被調函數的數據傳
送 。

1.形參變量只有在被調用時才分配內存單元, 在調用結束時, 即刻釋放所分配的內存單元 。因此,形參只有在函數內部有效。 函數調用結束返回主調函數後則不能再使用該形參變量。

2.實參可以是常量、變量、表達式、函數等, 無論實參是何種類型的量,在進行函數調用時,它們都必須具有確定的值, 以便把這些值傳
送給形 參。 因此應預先用賦值,輸入等辦法使實參獲得確定值。

3.實參和形參在數量上,類型上,順序上應嚴格一致, 否則會發生“類型不匹配”的錯誤。

4 . 函數調用中發生的數據傳送是單向的 。 即只能把實參的值傳送給形參,而不能把形參的值反向地傳送給實參。 因此在函數調用過程中,形參的值發生改變,而實參中的值不會變化。

5.當形參和實參不是指針類型時,在該函數運行時, 形參和實參是不同的變量,他們在內存中位於不同的位置,形參將實參的內容複製一
份,在該 函數運行結束的時候形參被釋放,而實參內容不會改變 。

而 如果函數的參數是指針類型變量 , 在調用該函數的過程中,傳給函數的是實參的地址,在函數體內部使用的也是實參的地址,即使用的就 是實參本身 。所以在函數體內部可以改變實參的值。

47 、構造方法能不能顯式調用?

不能,構造方法當成普通方法調用,只有在創建對象的時候它纔會被系統調用

48 、什麼是方法重載?

方法的重載就是在同一個類中允許同時存在一個以上的同名方法,只要它們的參數個數或者類型不同即可。在這種情況下,該方法就叫被重載了,這個過程稱爲方法的重載(override)

49 、構造方法能不能重寫?能不能重載?

可以重載,但不能重寫。

50 、內部類與靜態內部類的區別?

靜態內部類相對與外部類是獨立存在的,在靜態內部類中無法直接訪問外部類中變量、方法。如果要訪問的話,必須要new一個外部類的對
象,使用new出來的對象來訪問。但是可以直接訪問靜態的變量、調用靜態的方法;

普通內部類作爲外部類一個成員而存在,在普通內部類中可以直接訪問外部類屬性,調用外部類的方法。

如果外部類要訪問內部類的屬性或者調用內部類的方法,必須要創建一個內部類的對象,使用該對象訪問屬性或者調用方法。

如果其他的類要訪問普通內部類的屬性或者調用普通內部類的方法,必須要在外部類中創建一個普通內部類的對象作爲一個屬性,外同類可
以通過該屬性調用普通內部類的方法或者訪問普通內部類的屬性

如果其他的類要訪問靜態內部類的屬性或者調用靜態內部類的方法,直接創建一個靜態內部類對象即可。

51 、Static關鍵字有什麼作用?

Static可以修飾內部類、方法、變量、代碼塊

Static修飾的類是靜態內部類

Static修飾的方法是靜態方法,表示該方法屬於當前類的,而不屬於某個對象的,靜態方法也不能被重寫,可以直接使用類名來調用。在
static方法中不能使用this或者super關鍵字。

Static修飾變量是靜態變量或者叫類變量,靜態變量被所有實例所共享,不會依賴於對象。靜態變量在內存中只有一份拷貝,在JVM加載類
的時候,只爲靜態分配一次內存。

Static修飾的代碼塊叫靜態代碼塊,通常用來做程序優化的。靜態代碼塊中的代碼在整個類加載的時候只會執行一次。靜態代碼塊可以有多
個,如果有多個,按照先後順序依次執行。

52 、final在java中的作用,有哪些用法?

final也是很多面試喜歡問的地方,但我覺得這個問題很無聊,通常能回答下以下 5 點就不錯了:

  1. 被fifinal修飾的類不可以被繼承
  2. 被fifinal修飾的方法不可以被重寫
  3. 被fifinal修飾的變量不可以被改變.如果修飾引用,那麼表示引用不可變,引用指向的內容可變.
  4. 被fifinal修飾的方法,JVM會嘗試將其內聯,以提高運行效率
  5. 被fifinal修飾的常量,在編譯階段會存入常量池中.

除此之外,編譯器對fifinal域要遵守的兩個重排序規則更好:

在構造函數內對一個fifinal域的寫入,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操作之間不能重排序

初次讀一個包含fifinal域的對象的引用,與隨後初次讀這個fifinal域,這兩個操作之間不能重排序

53 、StringString StringBuffffer 和 StringBuilder 的區別是什麼?

String是隻讀字符串,它並不是基本數據類型,而是一個對象。從底層源碼來看是一個fifinal類型的字符

數組,所引用的字符串不能被改變,一經定義,無法再增刪改。每次對String的操作都會生成新的

String對象

private final char value[];

每次+操作 : 隱式在堆上new了一個跟原字符串相同的StringBuilder對象,再調用append方法 拼接+後面的字符。

StringBuffer與StringBuilder都繼承了AbstractStringBulder類,而AbtractStringBuilder又實現了CharSequence接口,兩個類都是用來進
行字符串操作的。

在做字符串拼接修改刪除替換時,效率比string更高。

StringBuffer是線程安全的,Stringbuilder是非線程安全的。所以Stringbuilder比stringbuffer效率更高,StringBuffer的方法大多都加了
synchronized關鍵字

54 、String str=”aaa”,與String str=new String(“aaa”)一樣嗎?

一共有兩個引用,三個對象。因爲”aa”與”bb”都是常量,常量的值不能改變,當執行字符串拼接時候,會創建一個新的常量是” aabbb”,有將
其存到常量池中。

55 、講下java中的math類有那些常用方法?

Pow():冪運算
Sqrt():平方根
Round():四捨五入
Abs():求絕對值
Random():生成一個0-1的隨機數,包括 0 不包括 1

56 、String類的常用方法有那些?

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

57 、Java中的繼承是單繼承還是多繼承

Java中既有單繼承,又有多繼承。對於java類來說只能有一個父類,對於接口來說可以同時繼承多個接口

58 、Super與this表示什麼?

Super表示當前類的父類對象
This表示當前類的對象

59 、普通類與抽象類有什麼區別?

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

60 、什麼是接口?爲什麼需要接口?

接口就是某個事物對外提供的一些功能的聲明,是一種特殊的java類,接口彌補了java單繼承的缺點

61 、接口有什麼特點?

接口中聲明全是public static final修飾的常量
接口中所有方法都是抽象方法
接口是沒有構造方法的
接口也不能直接實例化
接口可以多繼承

62 、抽象類和接口的區別?

抽象類:

  1. 抽象方法,只有行爲的概念,沒有具體的行爲實現。使用abstract關鍵字修飾,沒有方法體。子類必須重寫這些抽象方法。
  2. 包含抽象方法的類,一定是抽象類。
  3. 抽象類只能被繼承,一個類只能繼承一個抽象類。

接口:

  1. 全部的方法都是抽象方法,屬性都是常量

  2. 不能實例化,可以定義變量。

  3. 接口變量可以引用具體實現類的實例

  4. 接口只能被實現,一個具體類實現接口,必須實現全部的抽象方法

  5. 接口之間可以多實現

  6. 一個具體類可以實現多個接口,實現多繼承現象

63 、Hashcode的作用

java的集合有兩類,一類是List,還有一類是Set。前者有序可重複,後者無序不重複。當我們在set中插入的時候怎麼判斷是否已經存在該
元素呢,可以通過equals方法。但是如果元素太多,用這樣的方法就會比較滿。

於是有人發明了哈希算法來提高集合中查找元素的效率。 這種方式將集合分成若干個存儲區域,每個對象可以計算出一個哈希碼,可以將 哈希碼分組,每組分別對應某個存儲區域,根據一個對象的哈希碼就可以確定該對象應該存儲的那個區域。

hashCode方法可以這樣理解:它返回的就是根據對象的內存地址換算出的一個值。這樣一來,當集合要添加新的元素時,先調用這個元素
的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行
任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。這
樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。

64 、 Java的四種引用,強弱軟虛

強引用

強引用是平常中使用最多的引用,強引用在程序內存不足(OOM)的時候也不會被回收,使用方式:

String str = new String("str");

軟引用

軟引用在程序內存不足時,會被回收,使用方式:

// 注意:wrf這個引用也是強引用,它是指向SoftReference這個對象的,
// 這裏的軟引用指的是指向new String("str")的引用,也就是SoftReference類中T
SoftReference<String> wrf = new SoftReference<String>(new String("str"));

可用場景: 創建緩存的時候,創建的對象放進緩存中,當內存不足時,JVM就會回收早先創建的對象。

弱引用

弱引用就是隻要JVM垃圾回收器發現了它,就會將之回收,使用方式:

WeakReference<String>wrf=newWeakReference<String>(str);

可用場景: Java源碼中的java.util.WeakHashMap中的key就是使用弱引用,我的理解就是,一旦我不需要某個引用,JVM會自動幫我處理它,這樣我就不需要做其它操作。

虛引用

虛引用的回收機制跟弱引用差不多,但是它被回收之前,會被放入ReferenceQueue中。注意哦,其它引用是被JVM回收後才被傳入
ReferenceQueue中的。由於這個機制,所以虛引用大多被用於引用銷燬前的處理工作。還有就是,虛引用創建的時候,必須帶有
ReferenceQueue,使用

例子:

PhantomReference<String>prf=newPhantomReference<String>(new
String("str"),newReferenceQueue<>());

可用場景: 對象銷燬前的一些操作,比如說資源釋放等。** Object.finalize() 雖然也可以做這類動作,但是這個方式即不安全又低效

上訴所說的幾類引用,都是指對象本身的引用,而不是指 Reference 的四個子類的引用( SoftReference 等)。

65 、Java創建對象有幾種方式?

java中提供了以下四種創建對象的方式:

  1. new創建新對象
  2. 通過反射機制
  3. 採用clone機制
  4. 通過序列化機制

66 、有沒有可能兩個不相等的對象有相同的hashcode

有可能.在產生hash衝突時,兩個不相等的對象就會有相同的 hashcode 值.當hash衝突產生時,一般有以下幾種方式來處理:

  1. 拉鍊法:每個哈希表節點都有一個next指針,多個哈希表節點可以用next指針構成一個單向鏈表,被分配到同一個索引上的多個節點可以
    用這個單向鏈表進行存儲.
  2. 開放定址法:一旦發生了衝突,就去尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到,並將記錄存入
  3. 再哈希:又叫雙哈希法,有多個不同的Hash函數.當發生衝突時,使用第二個,第三個…等哈希函數計算地址,直到無衝突.

67 、拷貝和淺拷貝的區別是什麼?

淺拷貝:

被複制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象.換言之,淺拷貝僅僅複製所考慮的對象,而不復制它所引用的對象.

深拷貝:

被複制對象的所有變量都含有與原來的對象相同的值.而那些引用其他對象的變量將指向被複制過的新對象.而不再是原有的那些被引用的對象.換言之.深拷貝把要複製的對象所引用的對象都複製了一遍.

68 、static都有哪些用法?

所有的人都知道static關鍵字這兩個基本的用法:靜態變量和靜態方法.也就是被static所修飾的變量/方法都屬於類的靜態資源,類實例所共享.除了靜態變量和靜態方法之外,static也用於靜態塊,多用於初始化操作:

public calss PreCache{
    static{
    //執行相關操作
   }
}

此外static也多用於修飾內部類,此時稱之爲靜態內部類.

最後一種用法就是靜態導包,即 import static .import static是在JDK 1.5之後引入的新特性,可以用來指定導入某個類中的靜態資源,並且不需
要使用類名,可以直接使用資源名,比如:

import static java.lang.Math.*;
public class Test{
    public static void main(String[] args){
        //System.out.println(Math.sin(20));傳統做法
        System.out.println(sin(20));
   }
}

69 、a=a+b與a+=b有什麼區別嗎?

+= 操作符會進行隱式自動類型轉換,此處a+=b隱式的將加操作的結果類型強制轉換爲持有結果的類型, 而a=a+b則不會自動進行類型轉換.
如:

byte a = 127;
byte b = 127; b = a + b; // 報編譯錯誤:cannot convert from int to byte
b += a;

以下代碼是否有錯,有的話怎麼改?

short s1= 1;
s1 = s1 + 1;

有錯誤.short類型在進行運算時會自動提升爲int類型,也就是說 s1+1 的運算結果是int類型,而s1是short類型,此時編譯器會報錯.
正確寫法:

short s1= 1;
s1 += 1;

+=操作符會對右邊的表達式結果強轉匹配左邊的數據類型,所以沒錯.

70 、final、finalize()、finally

性質不同

  1. final爲關鍵字;
  2. finalize()爲方法;
  3. finally爲區塊標誌,用於try語句中;

作用

  1. final爲用於標識常量的關鍵字,final標識的關鍵字存儲在常量池中(在這裏final常量的具體用法將在下面進行介紹);
  2. finalize()方法在Object中進行了定義,用於在對象“消失”時,由JVM進行調用用於對對象進行垃圾回收,類似於C++中的析構函數;用
    戶自定義時,用於釋放對象佔用的資源(比如進行I/0操作);
  3. finally{}用於標識代碼塊,與try{}進行配合,不論try中的代碼執行完或沒有執行完(這裏指有異常),該代碼塊之中的程序必定會進
    行;

71 、JDBC操作的步驟

1.加載數據庫驅動類
2.打開數據庫連接
3.執行sql語句
4.處理返回結果
5.關閉資源

72 、在使用jdbc的時候,如何防止出現sql注入的問題。

使用PreparedStatement類,而不是使用Statement類

73 、怎麼在JDBC內調用一個存儲過程

使用CallableStatement

74 、是否瞭解連接池,使用連接池有什麼好處?

數據庫連接是非常消耗資源的,影響到程序的性能指標。連接池是用來分配、管理、釋放數據庫連接的,可以使應用程序重複使用同一個據庫連接,而不是每次都創建一個新的數據庫連接。通過釋放空閒時間較長的數據庫連接避免數據庫因爲創建太多的連接而造成的連接遺漏
問題,提高了程序性能。

75 、你所瞭解的數據源技術有那些?使用數據源有什麼好處?

dbcp,c3p0,druid等,用的最多還是druid,因爲druid更加穩定,安全,還有後臺監控;通過配置文件的形式來維護數據庫信息,而不是通過硬編碼。當連接的數據庫信息發生改變時,不需要再更改程序代碼就實現了數據庫信息的更新。

Druid可以做什麼?

  1. 可以監控數據庫訪問性能,Druid內置提供了一個功能強大的StatFilter插件,能夠詳細統計SQL的執行性能,這對於線上分析數據庫訪問性能有幫助。

  2. 替換DBCP和C3P0。Druid提供了一個高效、功能強大、可擴展性好的數據庫連接池。

  3. 數據庫密碼加密。直接把數據庫密碼寫在配置文件中,這是不好的行爲,容易導致安全問題。DruidDruiver和DruidDataSource都支持PasswordCallback。

  4. SQL執行日誌,Druid提供了不同的LogFilter,能夠支持Common-Logging、Log4j和JdkLog,你可以按需要選擇相應的LogFilter,監控你應用的數據庫訪問情況。

76 、&和&&的區別

&是位運算符。&&是布爾邏輯運算符,在進行邏輯判斷時用&處理的前面爲false後面的內容仍需處理,用&&處理的前面爲false不再處理後
面的內容。

77 、靜態內部類如何定義

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

public class Out {
     private static int a;
     private int b;
     public static class Inner {
         public void print() {
         System.out.println(a);
         }
     }
}
  1. 靜態內部類可以訪問外部類所有的靜態變量和方法,即使是 private 的也一樣。
  2. 靜態內部類和一般類一致,可以定義靜態變量、方法,構造方法等。
  3. 其它類使用靜態內部類需要使用“外部類.靜態內部類”方式,如下所示:Out.Inner inner = new Out.Inner();inner.print();
  4. Java集合類HashMap內部就有一個靜態內部類Entry。Entry是HashMap存放元素的抽象,HashMap 內部維護 Entry 數組用了存放元
    素,但是 Entry 對使用者是透明的。像這種和外部類關係密切的,且不依賴外部類實例的,都可以使用靜態內部類。

78 、什麼是成員內部類

定義在類內部的非靜態類,就是成員內部類。成員內部類不能定義靜態方法和變量(final修飾的除外)。這是因爲成員內部類是非靜態的,
類初始化的時候先初始化靜態成員,如果允許成員內部類定義靜態變量,那麼成員內部類的靜態變量初始化順序是有歧義的。
實例:

public class Out {
     private static int a;
     private int b;
     public class Inner {
         public void print() {
             System.out.println(a);
             System.out.println(b);
         }
 }
}

79 、Static Nested Class 和 Inner Class的不同

Nested Class (一般是C++的說法),Inner Class (一般是JAVA的說法)。Java內部類與C++嵌套類最大的不同就在於是否有指向外部的引用上。
注: 靜態內部類(Inner Class)意味着 1 創建一個static內部類的對象,不需要一個外部類對象, 2 不能從一個static內部類的一個對象訪問一個外部類對象.

80 、什麼時候用assert

assertion(斷言)在軟件開發中是一種常用的調試方式,很多開發語言中都支持這種機制。在實現中,assertion就是在程序中的一條語句,
它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;如果該值爲false,說明程序已經處於不正確的
狀態下,系統將給出警告或退出。一般來說,assertion用於保證程序最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啓。爲
了提高性能,在軟件發佈後,assertion檢查通常是關閉的

81 、Java有沒有goto

java中的保留字,現在沒有在java中使用

82 、 數組有沒有length()這個方法? String有沒有length()這個方法

數組沒有length()這個方法,有length的屬性。String有有length()這個方法

83 、 用最有效率的方法算出 2 乘以 8 等於幾

移位操作:<<
2 << 3

84 、float型float f=3.4是否正確?

不正確。精度不準確,應該用強制類型轉換,如下所示:float f=(float)3.

85 、 排序都有哪幾種方法?請列舉

排序的方法有:插入排序(直接插入排序、希爾排序),交換排序(冒泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸併排序,分配排序(箱排序、基數排序)快速排序的僞代碼。
/ /使用快速排序方法對a[ 0 :n- 1 ]排序從a[ 0 :n- 1 ]中選擇一個元素作爲middle,該元素爲支點把餘下的元素分割爲兩段left 和right,使得left中的元素都小於等於支點,而right 中的元素都大於等於支點遞歸地使用快速排序方法對left 進行排序遞歸地使用快速排序方法對right 進行排序所得結果爲 left+middle+right.

86 、 靜態變量和實例變量的區別?

static i = 10; //常量 class A a; a.i =10;//可變

87 、 說出一些常用的類,包,接口,請各舉 5 個

常用的類:BufferedReader BufferedWriter FileReader FileWirter String Integer常用的包:java.lang java.awt java.io java.util java.sql常用的接口:Remote List Map Document NodeList

88 、a.hashCode() 有什麼用?與 a.equals(b) 有什麼關係?

hashCode() 方法是相應對象整型的 hash 值。它常用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap 等等。它與
equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hash code。

89 、Java 中的編譯期常量是什麼?使用它又什麼風險?

公共靜態不可變(public static final )變量也就是我們所說的編譯期常量,這裏的 public 可選的。實際上這些變量在編譯時會被替換掉,因爲編譯器知道這些變量的值,並且知道這些變量在運行時不能改變。這種方式存在的一個問題是你使用了一個內部的或第三方庫中的公有編譯時常量,但是這個值後面被其他人改變了,但是你的客戶端仍然在使用老的值,甚至你已經部署了一個新的 jar。爲了避免這種情況,當你在更新依賴 JAR 文件時,確保重新編譯你的程序

90 、在 Java 中,如何跳出當前的多重嵌套循環?

在最外層循環前加一個標記如 A,然後用 break A;可以跳出多重循環。(Java 中支持帶標籤的 break 和 continue 語句,作用有點類似於 C
和 C++中的 goto 語句,但是就像要避免使用 goto 一樣,應該避免使用帶標籤的 break 和 continue,因爲它不會讓你的程序變得更優雅,很多時候甚至有相反的作用,所以這種語法其實不知道更好)

91 、構造器(constructor)是否可被重寫(override)?

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

92 、兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?

不對,如果兩個對象 x 和 y 滿足 x.equals(y) == true,它們的哈希碼(hash code)應當相同。Java 對於 eqauls 方法和 hashCode 方法是這樣規定的:
(1)如果兩個 對象相同(equals 方法返回 true),那麼它們的 hashCode 值一定要相同;
(2)如果兩個對象的 hashCode 相同,它們並不一定相同。當然,你未必要按照要求去做,但是如果你違背了上述原則就會發現在使用容器時,相同的對象可以出現在 Set 集合中,同時增加新元素的效率會大大下降(對於使用哈希存儲的系統,如果哈希碼頻繁的衝突將會造成存
取性能急劇下降)。

93 、是否可以繼承 String 類?

String 類是 final 類,不可以被繼承,繼承 String 本身就是一個錯誤的行爲,對 String 類型最好的重用方式是關聯關係(Has-A)和依賴關係(Use-A)而不是繼承關係(Is-A)。

94 、當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏到底是值傳遞還是引用傳遞?

是值傳遞。Java 語言的方法調用只支持參數的值傳遞。當一個對象實例作爲一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對
象的屬性可以在被調用過程中被改變,但對對象引用的改變是不會影響到調用者的。C++和 C#中可以通過傳引用或傳輸出參數來改變傳入
的參數的值。在 C#中可以編寫如下所示的代碼,但是在 Java 中卻做不到。

using System;
namespace CS01 {
	 class Program {
		 public static void swap(ref int x, ref int y) {
			  int temp = x;
			 x = y;
			 y = temp;
			 } p
			 ublic static void Main (string[] args) {
			 int a = 5, b = 10;
			 swap (ref a, ref b);
			// a = 10, b = 5;
			 Console.WriteLine ("a = {0}, b = {1}", a, b);
		}
     } 
 }

說明:Java 中沒有傳引用實在是非常的不方便,這一點在 Java 8 中仍然沒有得到改進,正是如此在 Java 編寫的代碼中才會出現大量的Wrapper 類(將需要通過方法調用修改的引用置於一個 Wrapper 類中,再將 Wrapper 對象傳入方法),這樣的做法只會讓代碼變得臃腫,尤其是讓從 C 和 C++轉型爲 Java 程序員的開發者無法容忍。

95 、String 和 StringBuilder、StringBuffer 的區別?

Java 平臺提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。其中 String 是隻讀字符串,也就意味着 String 引用的字符串內容是不能被改變的。而 StringBuffer/StringBuilder 類表示的字符串對象可以直接進行修改。StringBuilder 是Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在於它是在單線程環境下使用的,因爲它的所有方面都沒有被synchronized 修飾,因此它的效率也比 StringBuffer 要高。

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

方法的重載和重寫都是實現多態的方式,區別在於前者實現的是編譯時的多態性,而後者實現的是運行時的多態性。重載發生在一個類中,同名的方法如果有不同的參數列表(參數類型不同、參數個數不同或者二者都不同)則視爲重載;重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常(里氏代換則)。重載對返回類型沒有特殊的要求。

97 、char 型變量中能不能存貯一箇中文漢字,爲什麼?

char 類型可以存儲一箇中文漢字,因爲 Java 中使用的編碼是 Unicode(不選擇任何特定的編碼,直接使用字符在字符集中的編號,這是統一的唯一方法),一個 char 類型佔 2 個字節( 16 比特),所以放一箇中文是沒問題的。

補充: 使用 Unicode 意味着字符在 JVM 內部和外部有不同的表現形式,在 JVM內部都是 Unicode,當這個字符被從 JVM 內部轉移到外部時(例如存入文件系統中),需要進行編碼轉換。所以 Java 中有字節流和字符流,以及在字符流和字節流之間進行轉換的轉換流,如
InputStreamReader 和 OutputStreamReader,這兩個類是字節流和字符流之間的適配器類,承擔了編碼轉換的任務;對於 C 程序員來說,要完成這樣的編碼轉換恐怕要依賴於 union(聯合體/共用體)共享內存的特徵來實現了。

98 、抽象類(abstract class)和接口(interface)有什麼異同 ?

抽象類和接口都不能夠實例化,但可以定義抽象類和接口類型的引用。一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明爲抽象類。接口比抽象類更加抽象,因爲抽象類中可以定義構造器,可以有抽象方法和具體
方法,而接口中不能定義構造器而且其中的方法全部都是抽象方法。抽象類中的成員可以是 private、默認、protected、public 的,而接口
中的成員全都是 public 的。抽象類中可以定義成員變量,而接口中定義的成員變量實際上都是常量。有抽象方法的類必須被聲明爲抽象類,而抽象類未必要有抽象方法。

99 、靜態嵌套類(Static Nested Class)和內部類(Inner Class)的不同?

Static Nested Class 是被聲明爲靜態(static)的內部類,它可以不依賴於外部類實例被實例化。而通常的內部類需要在外部類實例化後才
能實例化,其語法看起來挺詭異的,如下所示

/**
* 撲克類(一副撲克)
*/
public class Poker {
	 private static String[] suites = {"黑桃", "紅桃", "草花", "方塊"};
	 private static int[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
	 private Card[] cards;
	 /**
	 * 構造器
	 * */
	 public Poker() {
		 cards = new Card[52];
		 for(int i = 0; i < suites.length; i++) {
			 for(int j = 0; j < faces.length; j++) {
			 	cards[i * 13 + j] = new Card(suites[i], faces[j]);
			 }
		 }
	  }
	 /**
	 * 洗牌 (隨機亂序)
	 * */
	 public void shuffle() {
		 for(int i = 0, len = cards.length; i < len; i++) {
			 int index = (int) (Math.random() * len);
			 Card temp = cards[index];
			 cards[index] = cards[i];
			 cards[i] = temp;
		 }
	 }
	 /**
	 * 發牌
	 * @param index 發牌的位置
	 * */
	 public Card deal(int index) {
	 	return cards[index];
	 }
	 /**
	 * 卡片類(一張撲克)
	 * [內部類]
	 * */
	 public class Card {
	 private String suite; // 花色
	 private int face; // 點數
	 public Card(String suite, int face) {
		 this.suite = suite;
		 this.face = face;
	 }
	 @Override
	 public String toString() {
		 String faceStr = "";
		 switch(face) {
			 case 1: faceStr = "A"; break;
			 case 11: faceStr = "J"; break;
			 case 12: faceStr = "Q"; break;
			 case 13: faceStr = "K"; break;
			 default: faceStr = String.valueOf(face);
			 } 
			 return suite + faceStr;
	}
  } 
 }
//測試類
class PokerTest {
	 public static void main(String[] args) {
		 Poker poker = new Poker();
		 poker.shuffle(); // 洗牌
		 Poker.Card c1 = poker.deal(0); // 發第一張牌
		 // 對於非靜態內部類 Card
		 // 只有通過其外部類 Poker 對象才能創建 Card 對象
		 Poker.Card c2 = poker.new Card("紅心", 1); // 自己創建一張牌
		 System.out.println(c1); // 洗牌後的第一張
		 System.out.println(c2); // 打印: 紅心 A
	 } 
 }

100 、Java 中會存在內存泄漏嗎,請簡單描述。

理論 上 Java 因爲 有垃 圾回 收機 制( GC)不 會存 在內 存泄 露問 題( 這也 是 Java 被廣泛 使用 於服 務器 端編 程的 一個 重要 原因 );
然而 在實 際開 發中 ,可 能會 存在 無用但 可達 的對 象,這些 對象 不能 被 GC 回收 ,因此 也會 導致 內存 泄露 的發 生 。

例 如Hibernate 的 Session( 一級 緩存 )中的 對象 屬於 持久 態,垃圾 回收 器是 不會 回收這些 對象 的,然而 這些 對象 中可 能存 在無
用的 垃圾 對象 ,如果 不及 時關 閉(close)或清 空( flush)一 級緩 存就 可能 導致 內存 泄露 。下 面例 子中 的代 碼也 會導 致內 存泄露.

import java.util.Arrays;
import java.util.EmptyStackException;
public class MyStack<T> {
	 private T[] elements;
	 private int size = 0;
	 private static final int INIT_CAPACITY = 16;
	 public MyStack() {
	 elements = (T[]) new Object[INIT_CAPACITY];
	 }
	 public void push(T elem) {
	 ensureCapacity();
	 elements[size++] = elem;
	 }
	 public T pop() {
		if(size == 0)
	       throw new EmptyStackException();
		return elements[--size];
	 }
	 private void ensureCapacity() {
		 if(elements.length == size) {
		 elements = Arrays.copyOf(elements, 2 * size + 1);
		 }
	 } 
 }

上面的代碼實現了一個棧(先進後出(FILO))結構,乍看之下似乎沒有什麼明顯的問題,它甚至可以通過你編寫的各種單元測試。然而其
中的 pop 方法卻存在內存泄露的問題,當我們用 pop 方法彈出棧中的對象時,該對象不會被當作垃圾回收,即使使用棧的程序不再引用這些對象,因爲棧內部維護着對這些對象的過期引用(obsolete reference)。在支持垃圾回收的語言中,內存泄露是很隱蔽的,這種內存泄
露其實就是無意識的對象保持。如果一個對象引用被無意識的保留起來了,那麼垃圾回收器不會處理這個對象,也不會處理該對象引用的其他對象,即使這樣的對象只有少數幾個,也可能會導致很多的對象被排除在垃圾回收之外,從而對性能造成重大影響,極端情況下會引發Disk Paging(物理內存與硬盤的虛擬內存交換數據),甚至造成 OutOfMemoryError。

101 、抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本地方法(native),是否可同時被 synchronized修飾?

都不能。抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。本地方法是由本地代碼(如 C 代碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。synchronized 和方法的實現細節有關,抽象方法不涉及實現細節,因此也是相互矛盾的。

102 、是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的調用?

不可以,靜態方法只能訪問靜態成員,因爲非靜態方法的調用要先創建對象,在調用靜態方法時可能對象並沒有被初始化。

103 、如何實現對象克隆?

有兩種方式:

1). 實現 Cloneable 接口並重寫 Object 類中的 clone()方法;
2). 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真
正的深度克隆,代碼如下。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyUtil {
	 private MyUtil() {
	 	throw new AssertionError();
	 }
	 @SuppressWarnings("unchecked")
	 public static <T extends Serializable> T clone(T obj) throws
	 Exception {
		 ByteArrayOutputStream bout = new ByteArrayOutputStream();
		 ObjectOutputStream oos = new ObjectOutputStream(bout);
		 oos.writeObject(obj);
		 ByteArrayInputStream bin = new
		 ByteArrayInputStream(bout.toByteArray());
		 ObjectInputStream ois = new ObjectInputStream(bin);
		 return (T) ois.readObject();
	// 說明:調用 ByteArrayInputStream 或 ByteArrayOutputStream對象的 close 方法沒有任何意義
	// 這兩個基於內存的流只要垃圾回收器清理對象就能夠釋放資源,這一點不同於對外部資源(如文件流)的釋放
	 } 
 }

測試代碼:

import java.io.Serializable;
class Person implements Serializable {
	 private static final long serialVersionUID = -9102017020286042305L;
	 private String name; // 姓名
	 private int age; // 年齡
	 private Car car; // 座駕
	 public Person(String name, int age, Car car) {
		 this.name = name;
		 this.age = age;
		 this.car = car;
	 }
	 public String getName() {
		 return name;
	 }
	 public void setName(String name) {
		 this.name = name;
	  }
	 public int getAge() {
		 return age;
	 }
	 public void setAge(int age) {
		 this.age = age;
	 }
	 public Car getCar() {
		 return car;
	 }
	 public void setCar(Car car) {
		 this.car = car;
	 }
	 @Override
	 public String toString() {
		 return "Person [name=" + name + ", age=" + age + ", car=" +
		 car + "]";
	 } 
}
class Car implements Serializable {
	 private static final long serialVersionUID = -5713945027627603702L;
	 private String brand; // 品牌
	 private int maxSpeed; // 最高時速
	 public Car(String brand, int maxSpeed) {
		 this.brand = brand;
		 this.maxSpeed = maxSpeed;
	 }
	 public String getBrand() {
		 return brand;
	 }
	 public void setBrand(String brand) {
		 this.brand = brand;
	 }
	 public int getMaxSpeed() {
		 return maxSpeed;
	 }
	 public void setMaxSpeed(int maxSpeed) {
		 this.maxSpeed = maxSpeed;
	 }
	 @Override
	 public String toString() {
		 return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed +
		 "]";
	 }
}
class CloneTest {
	 public static void main(String[] args) {
		 try {
			 Person p1 = new Person("Hao LUO", 33, new Car("Benz",
			 300));
			 Person p2 = MyUtil.clone(p1); // 深度克隆
			 p2.getCar().setBrand("BYD");
			 // 修改克隆的 Person 對象 p2 關聯的汽車對象的品牌屬性
			 // 原來的 Person 對象 p1 關聯的汽車不會受到任何影響
			 // 因爲在克隆 Person 對象時其關聯的汽車對象也被克隆了
			 System.out.println(p1);
			 } catch (Exception e) {
			 e.printStackTrace();
		 	}
	 } 
 }

注意: 基於 序列 化和 反序 列化 實現 的克 隆不 僅僅 是深 度克 隆, 更重 要的 是通 過泛型限 定,可以 檢查 出要 克隆 的對 象是 否支 持序 列化 ,這 項檢 查是 編譯 器完 成的 ,不是 在運 行時 拋出 異常 ,這種 是方 案明 顯優 於使 用 Object 類的 clone 方法 克隆 對象。 讓問題在 編譯 的時 候暴 露出 來總 是好 過把 問題 留到 運行 時。

104 、接口是否可繼承(extends)接口?抽象類是否可實現(implements)接口?抽象類是否可繼承具體類(concreteclass)?

接口 可以繼承接口 ,而且支持多重繼承 。抽象類可以實現(implements)接口 ,抽象類可繼承具體類也可以繼承抽象類 。

105 、一個".java"源文件中是否可以包含多個類(不是內部類)?有什麼限制?

可以,但一個源文件中最多隻能有一個公開類(public class)而且文件名必須和公開類的類名完全保持一致。

106 、Anonymous Inner Class(匿名內部類)是否可以繼承其它類?是否可以實現接口?

可以繼承其他類或實現其他接口,在 Swing 編程和 Android 開發中常用此方式來實現事件監聽和回調。

107 、內部類可以引用它的包含類(外部類)的成員嗎?有沒有什麼限制?

一個內部類對象可以訪問創建它的外部類對象的成員,包括私有成員。

108 、Java 中的 final 關鍵字有哪些用法?

(1)修飾類:表示該類不能被繼承;

(2)修飾方法:表示方法不能被重寫;

(3)修飾變量:表示變量只能一次賦值以後值不能被修改(常量)。

博主後記:

希望看到此篇博文的小夥伴,如果發現有什麼不對的地方,歡迎在下方留言指正!博主一定虛心接受並改正!大家一起共同進步。如果對你有所幫助,可以給博主一個贊👍。

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