Just Go Ahead

問題來源如下鏈接,根據(jù)自己理解以及查找資料寫的答案,有的地方自己也不是很清楚,歡迎多多指正。

http://www.itdecent.cn/p/e6702d61eec9

1. Java中 == 、equals 和 hashCode 的區(qū)別

  • == 如果是基本類型比較的是真實值,如果是引用類型比較的是內(nèi)存中的地址
  • Object類的equals方法內(nèi)部也是調用==
public boolean equals(Object obj){
     return (this==obj);
}

所以說如果子類不覆蓋equals方法,== 和 equals是一樣。
那為什么還有equals方法呢,我開發(fā)中的需求不同,比如:

String s1 = "hello";
String s2 = new String("hello");

由于s1在字符串常量池而s2在堆內(nèi)存中,所以s1==s2肯定是false。
但是我們期望的是內(nèi)容如果相同,我們就希望返回true,所以String類中重寫了equals方法。
此時equals方法不再等同于==,而是根據(jù)我們自己的邏輯,進行判斷。

  • hashCode是Object類中的一個方法,它返回一個整形數(shù),它怎樣計算返回這個整數(shù)我不清楚,但是它不是對象的內(nèi)存地址值。

那這個hashCode到底是做什么用的呢?

先來說幾條java的通用約定:

  • 重寫equals方法的類,也必須重寫hashCode方法
  • 一個應用程序,一次運行中,在沒有修改equals方法中的比較操作,多次調用一個對象hashCode方法,一定返回相同的值;多次運行,hashCode值則不一定相同
  • 如果倆個對象x.equals(y) 返回true,則xy的hashCode值一定相等
  • 如果倆個對象x.equals(y)返回false,則xy的hashCode值不一定不相等

這個得說一種數(shù)據(jù)結構散列,比如HashMap,HashSet,Hashtable都是基于散列的集合,其實這種技術的核心就是:

// index 元素存儲位置也就是散列地址
// key 關鍵字
// fun 是一個函數(shù),理想狀態(tài)下不同的key返回的值不一樣

index = fun(key)

其實這個fun就是hashCode函數(shù),比如我們有下面的元素要存儲,計算后的散列地址,以及在內(nèi)存中的簡單分配?;谏⒘械募隙家蕾噃ashCode這個方法。


image.png

image.png

2. int ,char,long各占多少字節(jié)

byte(1) ,short(2),int(4), long(8), float(4) ,double(8),char (2),boolean(1)

3.int 和Integer的區(qū)別

  • int 是基本數(shù)據(jù)類型,而Integer是int的包裝類
  • Integer必須實例化后才能使用,而int型變量不需要
  • Integer的默認值是null,int是0
  • Integer實際是對象的引用,當new一個Integer時,實際生成一個指針指向該對象,而int是直接存儲數(shù)據(jù)值

延伸:

  • 兩個new出來的Integer,用==比較,永遠為false,對象地址不同
  • int和Integer比較時,只要值相等即相等,因為比較時會拆箱,將Integer轉為int
    Integer i = new Integer(100)
    int j = 100
    i==j 返回true,自動拆箱
  • 一個new的Integer和一個非new的Integer比較,返回false,因為一個是堆的地址,一個指向常量池
    Integer i = new Integer(100)
    Integer j = 100
    i==j 返回false
  • 在-128~127之間的倆個相同Integer比較時,會返回true,如果超出范圍就會返回false

4. 談談java多態(tài)

多態(tài)就是同一個行為具有不同的表現(xiàn)形式,就是一個接口的方法,在不同的實例中執(zhí)行操作不同

5.String,StringBuffer,StringBuilder區(qū)別

  • String 字符串常量,不能修改
  • StringBuffer字符串變量,可以修改,線程安全
  • StringBuilder字符串變量,可以修改,線程不安全

6. 什么是內(nèi)部類,內(nèi)部類的作用

在一個類內(nèi)部創(chuàng)建的類就叫內(nèi)部類,內(nèi)部類可以寫在方法里,叫局部內(nèi)部類。內(nèi)部可以用static修飾,就是靜態(tài)內(nèi)部類。靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類的區(qū)別在于,非靜態(tài)內(nèi)部類持有對外部類的引用,而靜態(tài)內(nèi)部類沒有。

非靜態(tài)內(nèi)部類里面不允許有靜態(tài)變量、方法、或者另一個靜態(tài)內(nèi)部類,而靜態(tài)內(nèi)部類里面可以有這一切

內(nèi)部類的作用:

  • 內(nèi)部類可以很好的實現(xiàn)隱藏,體現(xiàn)了java的封裝性
  • 可以不用修改接口,實現(xiàn)同一個類中存在倆個同名同參數(shù)方法
  • 可以實現(xiàn)多繼承
  • 內(nèi)部類擁有外部類的所有元素的訪問權限

重點說下作用3,可以實現(xiàn)多繼承,這也是內(nèi)部類存在的最直接因素。如果沒有內(nèi)部類,我們用實現(xiàn)接口的方式達到多繼承效果。但是實現(xiàn)接口,就必須實現(xiàn)所有的方法,而內(nèi)部類就可以有選擇。

比如有類A,B, 類C中有兩個內(nèi)部類,D繼承A,E繼承B,這樣我們實例化
C c = new C();
然后我們就可以調用D E中的方法了,也就會間接調到A B中的方法。

7. 接口和抽象類的區(qū)別

抽象類,被abstract修飾的類為抽象類,抽象類不能被實例化,只能被子類繼承。抽象類中可以沒有抽象方法,抽象類中可以有默認實現(xiàn)的方法。非抽象子類繼承抽象類,必須要重寫父類的抽象方法。
接口,內(nèi)的方法不能有默認實現(xiàn),必須為抽象方法,接口不能被繼承只能被實現(xiàn),實現(xiàn)類必須實現(xiàn)接口的所有方法。抽象類可以實現(xiàn)接口,非抽象子類中要實現(xiàn)費抽象和接口中的抽象方法。
很多時候他們甚至可以互換使用,為什么要有兩個類似的東東呢,最重要的點在于類只能單繼承,而可以多實現(xiàn)。實際開發(fā)中如果某個類繼承了一個抽象類,就不能再繼承其他類,有一定局限性,所以一般多用接口。

8.泛型中extends和super的區(qū)別

先說下泛型的常用倆種方法<T> 和 <? extends T> or <? super T>
<T>是將數(shù)據(jù)類型參數(shù)化,舉個簡單例子,定義一個帶泛型的盤子類和不帶泛型蘋果類,盤子可以盛各種水果。

public class Plate<T> {
    private T something;

    public Palte(T t){
        this.something = t;
    }

    private void setSomething(T t){
      this.something = t;
    }

    private T getSomething(){
      return something;
    }
}
publci static void main(String[] args){
    //盛蘋果的盤子
    Plate<Apple> plate = new Palte<>(new Apple());
}

在來舉個例子,何種情況下使用 <?extends T> (上邊界限定通配符) 和 <? super T> (下邊界限定通配符)

//確定上邊界
List<? extends Number> list;
// 不確定List存儲哪種類型,但是肯定是Number的子類
list = new ArrayList<Integer>();
list = new ArrayList<Long>();

//確定下邊界
List<? super Integer> list;
list = new ArrayList<Interge>();
list = new ArrayList<Number>();

9.父類的靜態(tài)屬性和方法能否繼承?能否被重寫?為什么?

子類可以繼承父類的靜態(tài)屬性和靜態(tài)方法,不能被重寫
因為靜態(tài)屬性和靜態(tài)方法初始化類的同時就會在內(nèi)存中為其開辟了一塊空間,并且是不能修改的,子類中可以有同名同參的靜態(tài)或非靜態(tài)方法,也可以有同名靜態(tài)屬性,但那不是從父類繼承來的,而是自己屬性或方法,也有自己的內(nèi)存空間。

10.進程和線程的區(qū)別

幾乎任何的操作系統(tǒng)都支持操作多個任務,通常一個任務就是一個程序,而一個程序就是一個進程。當一個進程運行時,內(nèi)部可以包含多個順序執(zhí)行流,每個流就是一個線程。
進程是指運行過程中的程序,并且具有一定的獨立功能,進程是系統(tǒng)進行資源分配和調度的一個單位。
進程擁有以下特點:

  • 獨立行:進程是系統(tǒng)中獨立存在的實體,它可以獨立擁有資源,每一個進程都有自己獨立的內(nèi)存空間地址
  • 動態(tài)性:進程和程序的區(qū)別在于進程是動態(tài)的,進程有時間概念,進程有自己的生命周期
  • 并發(fā)性:多個進程可以在單個處理并發(fā)執(zhí)行,互不影響

線程是進程的組成部分,一個進程可以擁有多個線程,但是一個線程只能擁有一個父進程。線程可以擁有自己的堆棧,程序計數(shù)器,局部變量,但不能獨立擁有系統(tǒng)資源,它與父進程的其他線程共享父進程的資源。

11.final ,fianlly ,和finalize的區(qū)別

  • final 修飾屬性,方法,和類,修飾屬性不能被修改,修飾的方法不能被重寫,修飾的類不能被繼承
  • finally 通常是用來在常處理中
try{
    //正常
}catch(Exception e){
    //異常
}finally{
    //總會執(zhí)行
}
  • finalize 是Object類中的一個方法,是垃圾回收器工作時,會調用將要被清理的對象finalize方法,以確保此對象沒有其他任何引用指向它。

12. 簡述java序列化和反序列化,并說明Serializable和Parcelable的區(qū)別

java序列化,簡單的說就是將對象以一連串字節(jié)描述的過程,反序列化就是將這些字節(jié)重建成相同對象的過程。
再通俗一點:

image.png

image.png

為什么會有序列化這種技術呢,因為這種機制允許你將對象轉化成字節(jié)流后在網(wǎng)絡上傳播,并可以隨時把對象持久化到數(shù)據(jù)庫,文件等一系列讀寫操作。
雖然Serializable和Parcelable都能實現(xiàn)對象序列化,但是Serializable的作用是保存對象的屬性到本地文件,數(shù)據(jù)庫,網(wǎng)絡流以方便數(shù)據(jù)傳輸,這種傳輸可以是程序內(nèi)的,也可以是倆個程序之間的。而Parcelable的設計初衷是因為Serializable效率過慢,為了在程序內(nèi)不同組件間以及不同Android程序間高效的傳輸數(shù)據(jù)而設計,這些數(shù)據(jù)僅在內(nèi)存中存在,Parcelable是通過IBinder通信的消息的載體。
Parcelable的性能比Serializable好,在內(nèi)存開銷方面較小,所以在內(nèi)存間數(shù)據(jù)傳輸時推薦使用Parcelable,如activity間傳輸數(shù)據(jù),而Serializable可將數(shù)據(jù)持久化方便保存,所以在需要保存或網(wǎng)絡傳輸數(shù)據(jù)時選擇Serializable。

13.靜態(tài)內(nèi)部類的設計意圖

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

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