(一) java基礎知識點


   java中==和equals和hashCode的區別 ?

1、基本數據類型,也稱原始數據類型。byte,short,char,int,long,float,double,boolean 
他們之間的比較,應用雙等號(==),比較的是他們的值。

2、引用數據類型(類) 
當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,所以,除非是同一個new出來的對象,他們的比較後的結果爲true,否則比較後結果爲false。 JAVA當中所有的類都是繼承於Object這個基類的,在Object中的基類中定義了一個equals的方法,這個方法的初始行爲是比較對象的內存地 址,但在一些類庫當中這個方法被覆蓋掉了,如String,Integer,Date在這些類當中equals有其自身的實現,而不再是比較類在堆內存中的存放地址了。

3、hashCode():計算出對象實例的哈希碼,並返回哈希碼,又稱爲散列函數。根類Object的hashCode()方法的計算依賴於對象實例的D(內存地址),故每個Object對象的hashCode都是唯一的;當然,當對象所對應的類重寫了hashCode()方法時,結果就截然不同了。 
兩個obj,如果equals()相等,hashCode()一定相等。 
兩個obj,如果hashCode()相等,equals()不一定相等(Hash散列值有衝突的情況,雖然概率很低)。 
所以: 
  可以考慮在集合中,判斷兩個對象是否相等的規則是: 
    第一步,如果hashCode()相等,則查看第二步,否則不相等; 
    第二步,查看equals()是否相等,如果相等,則兩obj相等,否則還是不相等。 
1. new Object(),JVM根據這個對象的Hashcode值,放入到對應的Hash表對應的Key上,如果不同的對象確產生了相同的hash值,也就是發生了Hash key相同導致衝突的情況,那麼就在這個Hash key的地方產生一個鏈表,將所有產生相同hashcode的對象放到這個單鏈表上去,串在一起。>2. 比較兩個對象的時候,首先根據他們的hashcode去hash表中找他的對象,當兩個對象的hashcode相同,那麼就是說他們這兩個對象放在Hash表中的同一個key上,那麼他們一定在這個key上的鏈表上。那麼此時就只能根據Object的equal方法來比較這個對象是否equal。當兩個對象的hashcode不同的話,肯定他們不能equal.

int、char、long各佔多少字節數 ?

1字節: byte , boolean 
2字節: short , char 
4字節: int , float 
8字節: long , double 
注:1字節(byte)=8位(bits)

int與integer的區別

1、Integer是int的包裝類,int則是java的一種基本數據類型 
2、Integer變量必須實例化後才能使用,而int變量不需要 
3、Integer實際是對象的引用,當new一個Integer時,實際上是生成一個指針指向此對象;而int則是直接存儲數據值 
4、Integer的默認值是null,int的默認值是0

延伸: 
關於Integer和int的比較 
1、由於Integer變量實際上是對一個Integer對象的引用,所以兩個通過new生成的Integer變量永遠是不相等的(因爲new生成的是兩個對象,其內存地址不同)。

Integer i = new Integer(100); 
Integer j = new Integer(100); 
System.out.print(i == j); //false

2、Integer變量和int變量比較時,只要兩個變量的值是向等的,則結果爲true(因爲包裝類Integer和基本數據類型int比較時,java會自動拆包裝爲int,然後進行比較,實際上就變爲兩個int變量的比較)

Integer i = new Integer(100); 
int j = 100; 
System.out.print(i == j); //true

3、非new生成的Integer變量和new Integer()生成的變量比較時,結果爲false。(因爲非new生成的Integer變量指向的是java常量池中的對象,而new Integer()生成的變量指向堆中新建的對象,兩者在內存中的地址不同)

Integer i = new Integer(100); 
Integer j = 100; 
System.out.print(i == j); //false

4、對於兩個非new生成的Integer對象,進行比較時,如果兩個變量的值在區間-128到127之間,則比較結果爲true,如果兩個變量的值不在此區間,則比較結果爲false

Integer i = 100; 
Integer j = 100; 
System.out.print(i == j); //true

Integer i = 128; 
Integer j = 128; 
System.out.print(i == j); //false

對於第4條的原因: 
java在編譯Integer i = 100 ;時,會翻譯成爲Integer i = Integer.valueOf(100);,而java API中對Integer類型的valueOf的定義如下:

public static Integer valueOf(int i){ 
assert IntegerCache.high >= 127; 
if (i >= IntegerCache.low && i <= IntegerCache.high){ 
return IntegerCache.cache[i + (-IntegerCache.low)]; 

return new Integer(i); 
}

java對於-128到127之間的數,會進行緩存,Integer i = 127時,會將127進行緩存,下次再寫Integer j = 127時,就會直接從緩存中取,就不會new了

談談對java多態的理解

父類的引用指向子類的對象 
同一消息可以根據發送對象的不同而採用多種不同的行爲方式

void doSomething(Shape shape){
        shape.draw();
         .
         .
         shape.erase();
}

Circle circle = new Cricle();

Traingle traingle = new Traingle();

Line line = new Line();

doSonething(circle);

doSonething(traingle);

doSonething(line);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

String、StringBuffer、StringBuilder區別

String 字符串常量 
StringBuffer 字符串變量(線程安全) 
StringBuilder 字符串變量(非線程安全) 
1.三者在執行速度方面的比較:StringBuilder > StringBuffer > String 
2.String <(StringBuffer,StringBuilder)的原因 
    String:字符串常量 
    StringBuffer:字符創變量 
    StringBuilder:字符創變量 
從上面的名字可以看到,String是“字符創常量”,也就是不可改變的對象。對於這句話的理解你可能會產生這樣一個疑問 ,比如這段代碼:

1 String s = "abcd";
2 s = s+1;
3 System.out.print(s);// result : abcd1
  • 1
  • 2
  • 3

我們明明就是改變了String型的變量s的,爲什麼說是沒有改變呢? 其實這是一種欺騙,JVM是這樣解析這段代碼的:首先創建對象s,賦予一個abcd,然後再創建一個新的對象s用來執行第二行代碼,也就是說我們之前對象s並沒有變化,所以我們說String類型是不可改變的對象了,由於這種機制,每當用String操作字符串時,實際上是在不斷的創建新的對象,而原來的對象就會變爲垃圾被GC回收掉,可想而知這樣執行效率會有多低。 
  而StringBuffer與StringBuilder就不一樣了,他們是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,實際上是在一個對象上操作的,這樣就不會像String一樣創建一些而外的對象進行操作了,當然速度就快了。

3.一個特殊的例子:

String str = “This is only a” + “ simple” + “ test”;
StringBuffer builder = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
  • 1
  • 2

你會很驚訝的發現,生成str對象的速度簡直太快了,而這個時候StringBuffer居然速度上根本一點都不佔優勢。其實這是JVM的一個把戲,實際上:

    String str = “This is only a” + “ simple” + “test”;

  其實就是:

    String str = “This is only a simple test”;

  所以不需要太多的時間了。但大家這裏要注意的是,如果你的字符串是來自另外的String對象的話,速度就沒那麼快了,譬如:

    String str2 = “This is only a”;

    String str3 = “ simple”;

    String str4 = “ test”;

    String str1 = str2 +str3 + str4;

    這時候JVM會規規矩矩的按照原來的方式去做。

什麼是內部類?內部類的作用

內部類( Inner Class )就是定義在另外一個類裏面的類。與之對應,包含內部類的類被稱爲外部類。 
內部類的主要作用如下:

  1. 內部類提供了更好的封裝,可以把內部類隱藏在外部類之內,不允許同一個包中的其他類訪問該類

  2. 內部類的方法可以直接訪問外部類的所有數據,包括私有的數據

  3. 內部類所實現的功能使用外部類同樣可以實現,只是有時使用內部類更方便

內部類有幾種呢?

 成員內部類

 靜態內部類

 方法內部類

 匿名內部類
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

抽象類和接口區別

接口類描述的是行爲 抽象類描述的是根源; 
接口是對動作的抽象,抽象類是對根源的抽象。 
抽象類

抽象類是用來捕捉子類的通用特性的 。它不能被實例化,只能被用作子類的超類。抽象類是被用來創建繼承層級裏子類的模板。
  • 1
  • 2

接口

接口是抽象方法的集合。如果一個類實現了某個接口,那麼它就繼承了這個接口的抽象方法。這就像契約模式,如果實現了這個接口,那麼就必須確保使用這些方法。接口只是一種形式,接口自身不能做任何事情。
  • 1
  • 2

1.抽象類可以不包含靜態方法,接口也不能包含靜態方法; 
2.抽象類和接口都可以包含靜態成員變量,抽象類中靜態成員變量訪問類型可以任意,但接口中定義的變量只能是public static final 類型,並且默認爲public static final 類型; 
3.抽象類中可以包含普通成員變量,接口中沒有普通成員變量。 
4.抽象類中的方法method不能同時是靜態的;

抽象類的意義

1,爲子類提供一個公共的類型;

2,封裝子類中重複內容(成員變量和方法);

3,定義有抽象方法,子類雖然有不同的實現,但該方法的定義是一致的。

抽象類與接口的應用場景

  1. 定義了一組接口,但又不想強迫每個實現類都必須實現所有的接口。可以用abstract class定義一組方法體,甚至可以是空方法體,然後由子類選擇自己所感興趣的方法來覆蓋。
  2. 某些場合下,只靠純粹的接口不能滿足類與類之間的協調,還必需類中表示狀態的變量來區別不同的關係。abstract的中介作用可以很好地滿足這一點。
  3. 規範了一組相互協調的方法,其中一些方法是共同的,與狀態無關的,可以共享的,無需子類分別實現;而另一些方法卻需要各個子類根據自己特定的狀態來實現特定的功能

抽象類是否可以沒有方法和屬性?

可以

接口的意義

接口的最主要的作用是達到統一訪問,就是在創建對象的時候用接口創建,【接口名】 【對象名】=new 【實現接口的類】,這樣你像用哪個類的對象就可以new哪個對象了,不需要改原來的代碼,就和你的USB接口一樣,插什麼讀什麼,就是這個原理

解耦,可擴展這是設計接口的主要原因之一

泛型中extends和super的區別

<? extends T>限定參數類型的上界:參數類型必須是T或T的子類型 
<? super T> 限定參數類型的下界:參數類型必須是T或T的超類型 
總結爲: 
<? extends T> 只能用於方法返回,告訴編譯器此返參的類型的最小繼承邊界爲T,T和T的父類都能接收,但是入參類型無法確定,只能接受null的傳入 
<? super T>只能用於限定方法入參,告訴編譯器入參只能是T或其子類型,而返參只能用Object類接收? 既不能用於入參也不能用於返參

父類的靜態方法能否被子類重寫

java中靜態屬性和和靜態方法可以被繼承,但是沒有被重寫(overwrite)而是被隱藏。

進程和線程的區別

進程:具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位.

線程:進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.

1 簡而言之,一個程序至少有一個進程,一個進程至少有一個線程.

2 線程的劃分尺度小於進程,使得多線程程序的併發性高。

3 另外,進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,從而極大地提高了程序的運行效率。 
4 線程在執行過程中與進程還是有區別的。每個獨立的線程有一個程序運行的入口、順序執行序列和程序的出口。但是線程 不能夠獨立執行,必須依存在應用程序中,由應用程序提供多個線程執行控制。 
5 從邏輯角度來看,多線程的意義在於一個應用程序中,有多個執行部分可以同時執行。但操作系統並沒有將多個線程看做多個獨立的應用,來實現進程的調度和管理以及資源分配。這就是進程和線程的重要區別。

final,finally,finalize的區別

Final用於修飾類、成員變量和成員方法。final修飾的類,不能被繼承(String、StringBuilder、StringBuffer、Math,不可變類),其中所有的方法都不能被重寫,所以不能同時用abstract和final修飾類(abstract修飾的類是抽象類,抽象類是用於被子類繼承的,和final起相反的作用);Final修飾的方法不能被重寫,但是子類可以用父類中final修飾的方法;Final修飾的成員變量是不可變的,如果成員變量是基本數據類型,初始化之後成員變量的值不能被改變,如果成員變量是引用類型,那麼它只能指向初始化時指向的那個對象,不能再指向別的對象,但是對象當中的內容是允許改變的。 
Finally通常和try catch搭配使用,保證不管有沒有發生異常,資源都能夠被釋放(釋放連接、關閉IO流)。

Finalize是object類中的一個方法,子類可以重寫finalize()方法實現對資源的回收。垃圾回收只負責回收內存,並不負責資源的回收,資源回收要由程序員完成,Java虛擬機在垃圾回收之前會先調用垃圾對象的finalize方法用於使對象釋放資源(如關閉連接、關閉文件),之後才進行垃圾回收,這個方法一般不會顯示的調用,在垃圾回收時垃圾回收器會主動調用。

序列化的方式

什麼是序列化?

把Java對象轉換爲字節序列,並存儲至一個儲存媒介的過程。

什麼是反序列化?

把字節序列恢復爲Java對象的過程。 
Android開發中的序列化有兩種方法。 
第一種是實現Serializable接口(是JavaSE本身就支持的),第二種是實現Parcelable接口(是Android特有功能,效率比實現Serializable接口高效,可用於Intent數據傳遞,也可以用於進程間通信(IPC))。實現Serializable接口非常簡單,聲明一下就可以了,而實現Parcelable接口稍微複雜一些,但效率更高,推薦用這種方法提高性能。

Serializable 和Parcelable 的區別

1)在使用內存的時候,Parcelable比Serializable性能高,所以推薦使用Parcelable。

2)Serializable在序列化的時候會產生大量的臨時變量,從而引起頻繁的GC。

3)Parcelable不能使用在要將數據存儲在磁盤上的情況,因爲Parcelable不能很好的保證數據的持續性在外界有變化的情況下。儘管Serializable效率低點,但此時還是建議使用Serializable。

4)Serializable的實現,只需要implements Serializable 即可。這只是給對象打了一個標記,系統會自動將其序列化。

5)Parcelabel的實現,不僅需要implements Parcelabel,還需要在類中添加一個靜態成員變量CREATOR,這個變量需要實現 Parcelable.Creator 接口。

6) Parcelable的性能比Serializable好,在內存開銷方面較小,所以在內存間數據傳輸時推薦使用Parcelable,如activity間傳輸數據,而Serializable可將數據持久化方便保存,所以在需要保存或網絡傳輸數據時選擇Serializable,因爲android不同版本Parcelable可能不同,所以不推薦使用Parcelable進行數據持久化

靜態屬性和靜態方法是否可以被繼承?是否可以被重寫?以及原因?

java中靜態屬性和和靜態方法可以被繼承,但是沒有被重寫(overwrite)而是被隱藏。 
靜態方法和屬性是屬於類的,調用的時候直接通過類名.方法名完成的,不需繼承機制就可以調用如果子類裏面定義了靜態方法和屬性,那麼這時候父類的靜態方法 或屬性稱之爲“隱藏”,你如果想要調用父類的靜態方法和屬性,直接通過父類名.方法名或變量名完成,至於是否繼承一說,子類是有繼承靜態方法和屬性,但是 跟實例方法和屬性不太一樣,存在“隱藏”的這種情況。

例證如下:
package com.etc;
public  class A//父類
{
    public static String str = "靜態屬性";
    public String name = "非靜態屬性";
    public static void sing()
    {
        System.out.println("靜態方法");
    }

    public void run()
    {
        System.out.println("非靜態方法");
    }
}
package com.etc;
public class B extends A //子類B
{
    public static String str = "B該改寫後的靜態屬性";
    public String name ="B改寫後的非靜態屬性";
    public static void sing()
    {
        System.out.println("B改寫後的靜態方法");
    }
}
package com.etc;
public class C extends A //子類C繼承A中的所有屬性和方法
{
}
package com.etc;
public class Test//測試類
{
    public static void main(String[] args)
    {
        C c = new C();
        System.out.println(c.name);
        System.out.println(c.str);
        c.sing();//輸出的結果都是父類中的非靜態屬性、靜態屬性和靜態方法,推出靜態屬性和靜態方法可以被繼承

        A c1 = new C();
        System.out.println(c1.name);
        System.out.println(c1.str);
        c1.sing();//結果同上,輸出的結果都是父類中的非靜態屬性、靜態屬性和靜態方法,推出靜態屬性和靜態方法可以被繼承

        B b = new B();
        System.out.println(b.name);
        System.out.println(b.str);
        b.sing();//結果都是子類的非靜態屬性,靜態屬性和靜態方法,這裏和非靜態屬性和非靜態類的繼承相同


        A b1 = new B();
        System.out.println(b1.str);//結果是父類的靜態屬性,說明靜態屬性不可以被重寫,不能實現多態
        System.out.println(b1.name);//結果是父類的非靜態屬性,說明非靜態屬性不可以被重寫,不能實現多態
        b1.sing();//結果都是父類的靜態方法,說明靜態方法不可以被重寫,不能實現多態
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

靜態內部類的設計意圖

說靜態內部類之前,先了解下成員內部類(非靜態的內部類)。

成員內部類

成員內部類也是最普通的內部類,它是外圍類的一個成員,所以它可以無限制的訪問外圍類的所有成員屬性和方法,儘管是private的,但是外圍類要訪問內部類的成員屬性和方法則需要通過內部類實例來訪問。

在成員內部類中要注意兩點:

成員內部類中不能存在任何static的變量和方法;

成員內部類是依附於外圍類的,所以只有先創建了外圍類才能夠創建內部類。

靜態內部類

靜態內部類與非靜態內部類之間存在一個最大的區別:非靜態內部類在編譯完成之後會隱含地保存着一個引用,該引用是指向創建它的外圍類,但是靜態內部類卻沒有。

沒有這個引用就意味着:

它的創建是不需要依賴於外圍類的。

它不能使用任何外圍類的非static成員變量和方法。

成員內部類、靜態內部類、局部內部類和匿名內部類的理解,以及項目中的應用

廣泛意義上的內部類一般來說包括這四種:成員內部類、局部內部類、匿名內部類和靜態內部類

成員內部類 
可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員),不過要注意的是,當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問: 
外部類.this.成員變量 
外部類.this.成員方法 
雖然成員內部類可以無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼隨心所欲了。在外部類中如果要訪問成員內部類的成員,必須先創建一個成員內部類的對象,再通過指向這個對象的引用來訪問 
成員內部類是依附外部類而存在的,也就是說,如果要創建成員內部類的對象,前提是必須存在一個外部類的對象。 
局部內部類 
局部內部類是定義在一個方法或者一個作用域裏面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該作用域內,注意,局部內部類就像是方法裏面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。 
匿名內部類 
匿名內部類應該是平時我們編寫代碼時用得最多的,在編寫事件監聽的代碼時使用匿名內部類不但方便,而且使代碼更加容易維護。 
匿名內部類是唯一一種沒有構造器的類。正因爲其沒有構造器,所以匿名內部類的使用範圍非常有限,大部分匿名內部類用於接口回調。匿名內部類在編譯的時候由系統自動起名爲Outter$1.class。一般來說,匿名內部類用於繼承其他類或是實現接口,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。 
.靜態內部類 
靜態內部類也是定義在另一個類裏面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變量或者方法,這點很好理解,因爲在沒有外部類的對象的情況下,可以創建靜態內部類的對象,如果允許訪問外部類的非static成員就會產生矛盾,因爲外部類的非static成員必須依附於具體的對象。

談談對kotlin的理解

1,空類型安全 
2,Lambda 表達式 
3,擴展方法 
4,類型推導 
5,勝任Java能做的所有事,並且比Java更簡單 
6,沒有分號 ..

閉包和局部內部類的區別

閉包就是把函數以及變量包起來,使得變量的生存週期延長。閉包跟面向對象是一棵樹上的兩條枝,實現的功能是等價的。

string 轉換成 integer的方式及原理

public static Integer valueOf(String s) throws NumberFormatException{
        return new Integer(parseInt(s, 10));
} 
發佈了29 篇原創文章 · 獲贊 21 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章