全面總結(jié)Android面試知識要點:Java核心基礎(chǔ)相關(guān)(一)

請點贊,你的點贊對我意義重大,滿足下我的虛榮心。
??常在河邊走,哪有不濕鞋?;蛟S面試過程中你遇到的問題就在這呢?
??關(guān)注我,面試不迷路~

一、Java中提供了抽象類還有接口,開發(fā)中如何去選擇呢?

這道題想考察什么?

Java是面向?qū)ο缶幊痰模橄笫撬囊淮筇卣?,而體現(xiàn)這個特征的就是抽象類與接口。抽象類與接口某些情況下都能夠互相替代,但是如果真的都能夠互相替代,那Java為何會設(shè)計出抽象與接口的概念?這就需要面試者能夠掌握兩者的區(qū)別。

考察的知識點

OOP(面向?qū)ο螅┚幊趟枷?,抽象與接口的區(qū)別與應(yīng)用場景;

考生應(yīng)該如何回答

抽象類的設(shè)計目的,是代碼復(fù)用;接口的設(shè)計目的,是對類的行為進(jìn)行約束。

  • 當(dāng)需要表示is-a的關(guān)系,并且需要代碼復(fù)用時用抽象類
  • 當(dāng)需要表示has-a的關(guān)系,可以使用接口

比如狗具有睡覺和吃飯方法,我們可以使用接口定義:

public interface Dog {
    public void sleep();
    public void eat();
}

但是我們發(fā)現(xiàn)如果采用接口,就需要讓每個派生類都實現(xiàn)一次sleep方法。此時為了完成對sleep方法的復(fù)用,我們可以選擇采用抽象類來定義:

public abstract class Dog {
    public void sleep(){
        //......
    }
    public abstract void eat();
}

但是如果我們訓(xùn)練,讓狗擁有一項技能——握手,怎么添加這個行為? 將握手方法寫入抽象類中,但是這會導(dǎo)致所有的狗都能夠握手。

握手是訓(xùn)練出來的,是對狗的一種擴(kuò)展。所以這時候我們需要單獨定義握手這種行為。這種行為是否可以采用抽象類來定義呢?

public abstract Handshake{
    abstract void doHandshake();
}

如果采用抽象類定義握手,那我們現(xiàn)在需要創(chuàng)建一類能夠握手的狗怎么辦?

public class HandShakeDog extends Dog //,Handshake

大家都知道在Java中不能多繼承,這是因為多繼承存在二義性問題。

二義性問題:一個類如果能夠繼承多個父類,那么如果其中父類A與父類B具有相同的方法,當(dāng)調(diào)用這個方法時會調(diào)用哪個父類的方法呢?

所以此時,我們就需要使用接口來定義握手行為:

public interface Handshake{
    void doHandshake();
}
public class HandShakeDog extends Dog implements Handshake

不是所有的狗都會握手,也不止狗會握手。我們可以同樣訓(xùn)練貓,讓貓也具備握手的技能,那么貓Cat類,同樣能夠?qū)崿F(xiàn)此接口,這就是"has-a"的關(guān)系。

抽象類強(qiáng)調(diào)從屬關(guān)系,接口強(qiáng)調(diào)功能,除了使用場景的不同之外,在定義中的不同則是:

image.png

二、重載和重寫是什么意思,區(qū)別是什么?

這道題想考察什么?

Java基礎(chǔ)

考察的知識點

面向?qū)ο蠖鄳B(tài)的基礎(chǔ)概念

考生應(yīng)該如何回答

重寫(Override)

重寫就是重新寫的意思,當(dāng)父類中的方法對于子類來說不適用或者需要擴(kuò)展增強(qiáng)時,子類可以對從父類中繼承來的方法進(jìn)行重寫。

比如Activity是Android開發(fā)中四大組件之一。在Activity中存在各種聲明周期方法:onCreate、onStart .....等等。而我們應(yīng)用中需要使用Activity來展示UI,那么我們會需要編寫自己的類繼承自Activity。

public class MainActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

在上述代碼中,onCreate就是被我們重寫的Activity中定義方法。我們在onCreate增加了setContentView

的調(diào)用,完成了對超類Activity中對應(yīng)方法的修改與擴(kuò)展。

重載(Overload)

重載則是在同一個類中,允許存在多個同名方法,只要它們的參數(shù)列表不同即可。比如在Android開發(fā)中,我們會使用LayoutInflater的inflate方法加載布局,inflate方法存在多個定義,其中包括兩個參數(shù)的,與三個參數(shù)的:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    //......
}

可以看到在兩個參數(shù)的inflate方法中,會為我們調(diào)起三個參數(shù)的inflate方法,而定義第一個inflate方法的目的就是為了提供默認(rèn)的attachToRoot參數(shù)值。因為Java中無法定義方法參數(shù)默認(rèn)值,所以我們經(jīng)常使用重載達(dá)成此目的。

三、靜態(tài)內(nèi)部類是什么?和非靜態(tài)內(nèi)部類的區(qū)別是什么?

這道題想考察什么?

掌握static的作用與注意事項

考察的知識點

Java中關(guān)鍵字static

考生應(yīng)該如何回答

在定義內(nèi)部類時,如果內(nèi)部類被static聲明,則該內(nèi)部類為靜態(tài)內(nèi)部類。

public class OuterClass{
    static class InnerClass{
        
    }
}

當(dāng)內(nèi)部類被static聲明,那么在內(nèi)部類中就無法直接使用外部類的屬性。比如編寫普通內(nèi)部類:

public class OuterClass{
    int i;
    public class InnerClass{
        public InnerClass(){
            i = 10;
        }
    }
}

此時對OuterClass.java 進(jìn)行編譯,會生成:OuterClass.class 與 OuterClass$InnerClass.class 兩個文件。對后者反編譯我們將看到:

public class OuterClass$InnerClass {
    public OuterClass$InnerClass(OuterClass var1) {
        this.this$0 = var1;
        var1.i = 10;
    }
}

可以看到,普通內(nèi)部類構(gòu)造方法中實際上會隱式的傳遞外部類實例對象給內(nèi)部類。在內(nèi)部類中使用外部類的屬性:i。實際上是通過外部類的實例對象:var1獲取的。同時如果我們需要構(gòu)建出InnerClass的實例對象,非靜態(tài)內(nèi)部類也無法脫離外部類實體被創(chuàng)建。

下面我們將InnerClass定義為static靜態(tài)內(nèi)部類:

public class OuterClass{
    int i;
    public static class InnerClass{
        public InnerClass(){
            //i = 10; 
        }
    }
}

此時無法使用外部類的普通成員屬性:i。其對應(yīng)字節(jié)碼為:

public class OuterClass$InnerClass {
    public OuterClass$InnerClass() {
       
    }
}

靜態(tài)內(nèi)部類中不再隱式的持有外部類的實例對象。但是如果我們將屬性i定義為static,那么在靜態(tài)內(nèi)部類中也是可以直接使用外部類的靜態(tài)成員屬性的,此時字節(jié)碼為:

public class OuterClass$InnerClass {
    public OuterClass$InnerClass() {
        OuterClass.i = 10;
    }
}

內(nèi)部靜態(tài)類不需要有指向外部類的引用。但非靜態(tài)內(nèi)部類需要持有對外部類的引用。但是靜態(tài)內(nèi)部類能夠直接利用new OuterClass.InnerClass() 實例化。

因此靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類的區(qū)別有:

  1. 非靜態(tài)內(nèi)部類能夠訪問外部類的靜態(tài)和非靜態(tài)成員,靜態(tài)類只能訪問外部類的靜態(tài)成員。
  2. 非靜態(tài)內(nèi)部類不能脫離外部類被創(chuàng)建,靜態(tài)內(nèi)部類可以。

四、Java中在傳參數(shù)時是將值進(jìn)行傳遞,還是傳遞引用?

這道題想考察什么?

是否了解什么是值傳遞和引用傳遞與真實場景使用,是否熟悉什么是值傳遞和引用傳遞在工作中的表現(xiàn)是什么?

考察的知識點

什么是值傳遞和引用傳遞的概念,兩者對開發(fā)中編寫的代碼的影響

考生應(yīng)該如何回答

值傳遞:在方法調(diào)用時,傳遞的參數(shù)是這個參數(shù)指向值的拷貝;

引用傳遞:在方法調(diào)用時,傳遞引用的地址

在Java中對于參數(shù)的傳遞可以分為兩種情況:

1.基本數(shù)據(jù)類型的參數(shù)

 1 public class TransferTest {
 2     public static void main(String[] args) {
 3         int num = 1;
 4         System.out.println("changeNum()方法調(diào)用之前:num = " + num);
 5         changeNum(num);
 6         System.out.println("changeNum()方法調(diào)用之后:num = " + num);
 7     }
 8 
 9     public static void changeNum(int x) {
10         x = 2;
11     }
12 }

運行結(jié)果:

image.png

傳遞過程的示意圖如下:

image.png

分析:num作為參數(shù)傳遞給changeNum()方法時,是將內(nèi)存空間中num所指向的那個存儲單元中存放的值1復(fù)制了一份傳遞給了changeNum()方法中的x變量,而這個x變量也在內(nèi)存空間中分配的一個存儲單元。這時就把num對的值1傳遞給了x變量所指向的存儲單元中。此后在changeNum()方法中對x變量的一切操作都是針對于x所指向的這個存儲單元,與num所指向的存儲單元無關(guān)。

所以,在changeNum()方法被調(diào)用后,num所指向的存儲單元的值還是沒有發(fā)生變化,這就是所謂的“值傳遞”。

值傳遞的精髓是:傳遞的是存儲單元中的內(nèi)容,而不是存儲單元的引用。

2.引用類型的參數(shù)

 1  public class TransferTest2 {
 2     public static void main(String[] args) {
 3         Person person = new Person();
 4         System.out.println(person);
 5         change(person);
 6         System.out.println(person);
 7     }
 8 
 9     public static void change(Person p) {
10         p = new Person();
11     }
12 }
13 
14 /**
15  * Person類
16  */
17 class Person {
18 
19 }

運行結(jié)果:

image.png

可以看出兩次打印結(jié)果一致。即調(diào)用change()方法后,person變量并沒發(fā)生改變。

傳遞過程的示意圖如下:

image.png

分析:

01.當(dāng)程序執(zhí)行到第3行 Person person = new Person()時,程序在堆內(nèi)存(heap)中開辟了一塊內(nèi)存空間用來存儲Person類實例對象,同時在棧內(nèi)存(stack)中開辟了一個存儲單元來存儲該實例對象的引用,即上圖中person指向的存儲單元。

02.當(dāng)程序執(zhí)行到第5行 change(person)時,person作為參數(shù)(實參)傳遞給了change()方法。這里是person將自己的存儲單元的內(nèi)容傳遞給了change()方法的p變量。 此后在change()方法中對p變量的一切操作都是針對于p變量所指向的存儲單元,與perosn所指向的存儲單元就沒有關(guān)系了。

因此Java的參數(shù)傳遞,不管是基本數(shù)據(jù)類型還是引用類型的參數(shù),都是按值傳遞!

今天的面試分享到此結(jié)束拉~下期在見

?著作權(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)容

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