//今天京東通知面試了,一面面完,我以爲我玩完了。。唉。。。不過記錄一下本身的面試經驗仍是很重要的(雖然只是一個實習面試),爲下次的面試作準備吧。html
先是問了一下總成績,數據結構,算法的成績,而後問了以前有沒有作過相關的安卓工程,問了簡歷上的實習經歷和項目經歷。由於本身面的是安卓開發,因此重點問的是安卓的項目和獲獎項目。前端
以後是一些專業性的問題:java
1.字母組合的代碼:abc三個字母組合能夠組合成6種,abc,acb,bac,bca,cab,cba,而aac的組合只有3種,aac,caa,aca,輸出用戶輸入字符串的全部排列組合結果。(算法題)面試
2.JAVA的面向對象編程三大特徵:封裝,繼承,多態,解釋這三個概念並用代碼解釋;java的繼承題目,A extends B,new A(),輸出結果算法
3.死鎖的定義,用代碼寫死鎖;編程
4.onNewInent數據結構
5.安卓開發時,前端和後臺傳遞數據的方法;多線程
解:1.參考全排列ide
2.內容來源:Java面向對象的三大特徵post
封裝和繼承幾乎都是爲多態而準備的
1)修改屬性的可見性來限制對屬性的訪問
2)爲每一個屬性建立一隊賦值和取值方法,用於對這些屬性的訪問
3)在賦值和取值方法中,加入對屬性的存取限制
爲了實現良好的封裝,咱們一般將類的成員變量聲明爲private,在經過public方法來對這個變量來訪問。對一個變量的操做,通常有讀取和賦值2個操做,,咱們分別定義2個方法來實現這2個操做,一個是getXX(XX表示要訪問的成員變量的名字)用來讀取這個成員變量,另外一個是setXX()用來對這個變量賦值。
例子:
public class Husband { /* * 對屬性的封裝一我的的姓名、性別、年齡、妻子都是這我的的私有屬性 */ private String name; private String sex; private int age; private Wife wife; /* * setter()、getter()是該對象對外開發的接口 */ public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setWife(Wife wife) { this.wife = wife; } }
繼承所表達的就是一種對象類之間的相交關係,它使得某類對象能夠繼承另一類對象的數據成員和成員方法。若類B繼承類A,則屬於B的對象便具備類A的所有或部分性質(數據屬性)和功能(操做),咱們稱被繼承的類A爲基類、父類或超類,而稱繼承類B爲A的派生類或子類。
繼承避免了對通常類和特殊類之間共同特徵進行的重複描述。同時,經過繼承能夠清晰地表達每一項共同特徵所適應的概念範圍——在通常類中定義的屬性和操做適應於這個類自己以及它如下的每一層特殊類的所有對象。運用繼承原則使得系統模型比較簡練也比較清晰。
繼承的實例
class Person1 { public String name = "xiaomiao"; public int age = 20; } class Student extends Person1 { void study() { System.out.println("I can study!"); } } public class JiCheng { public static void main(String args[]) { Student stu = new Student(); // stu.name = "zhangsan"; // stu.age = 20; System.out.println("name=" + stu.name + ",,," + "age=" + stu.age); } }
方法的重寫、重載與動態鏈接構成多態性;
Java之因此引入多態的概念,緣由之一是它在類的繼承問題上和C++不一樣,後者容許多繼承,這確實給其帶來的很是強大的功能,可是複雜的繼承關係也給C++開發者帶來了更大的麻煩,爲了規避風險,Java只容許單繼承,派生類與基類間有IS-A的關係(即「貓」is a 「動物」)。這樣作雖然保證了繼承關係的簡單明瞭,可是勢必在功能上有很大的限制,因此,Java引入了多態性的概念以彌補這點的不足,此外,抽象類和接口也是解決單繼承規定限制的重要手段。同時,多態也是面向對象編程的精髓所在。
要理解多態性,首先要知道什麼是「向上轉型」。
我定義了一個子類Cat,它繼承了Animal類,那麼後者就是前者的父類。我能夠經過
Cat c = new Cat(); 例化一個Cat的對象,這個不難理解。
但當我這樣定義時: Animal a = new Cat();
這表明什麼意思呢?
很簡單,它表示我定義了一個Animal類型的引用,指向新建的Cat類型的對象。因爲Cat是繼承自它的父類Animal,因此Animal類型的引用是能夠指向Cat類型的對象的。那麼這樣作有什麼意義呢?由於子類是對父類的一個改進和擴充,因此通常子類在功能上較父類更強大,屬性較父類更獨特,定義一個父類類型的引用指向一個子類的對象既可使用子類強大的功能,又能夠抽取父類的共性。因此, 父類引用只能調用父類中存在的方法和屬性,不能調用子類的擴展部分;由於父類引用指向的是堆中子類對象繼承的父類;(可是若是強制把超類轉換成子類的話,就能夠調用子類中新添加而超類沒有的方法了。)
同時,父類中的一個方法只有在父類中定義而在子類中沒有重寫的狀況下,才能夠被父類類型的引用調用;
對於父類中定義的方法,若是子類中重寫了該方法,那麼父類類型的引用將會調用子類中的這個方法,這就是動態鏈接。
3.內容來源:多線程死鎖的產生以及如何避免死鎖
死鎖是指多個線程因競爭資源而形成的一種僵局(互相等待),若無外力做用,這些進程都將沒法向前推動。
產生死鎖必須同時知足如下四個條件,只要其中任一條件不成立,死鎖就不會發生。
/** * 一個簡單的死鎖類 * 當DeadLock類的對象flag==1時(td1),先鎖定o1,睡眠500毫秒 * 而td1在睡眠的時候另外一個flag==0的對象(td2)線程啓動,先鎖定o2,睡眠500毫秒 * td1睡眠結束後須要鎖定o2才能繼續執行,而此時o2已被td2鎖定; * td2睡眠結束後須要鎖定o1才能繼續執行,而此時o1已被td1鎖定; * td一、td2相互等待,都須要獲得對方鎖定的資源才能繼續執行,從而死鎖。 */ public class DeadLock implements Runnable { public int flag = 1; //靜態對象是類的全部對象共享的 private static Object o1 = new Object(), o2 = new Object(); @Override public void run() { System.out.println("flag=" + flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { System.out.println("0"); } } } } public static void main(String[] args) { DeadLock td1 = new DeadLock(); DeadLock td2 = new DeadLock(); td1.flag = 1; td2.flag = 0; //td1,td2都處於可執行狀態,但JVM線程調度先執行哪一個線程是不肯定的。 //td2的run()可能在td1的run()以前運行 new Thread(td1).start(); new Thread(td2).start(); } }
4.內容來源:Activity生命週期與onNewIntent
Activity第一次啓動時:onCreate -> onStart -> onResume
Activity再次啓動時:onPause(原來的實例) -> onCreate(新的實例) -> onStart(新的實例) -> onResume(新的實例) -> onStop(原來的實例)
因此,標準模式下,activity被屢次啓動,不會回調onNewIntent方法。
Activity第一次啓動時:onCreate -> onStart -> onResume
Activity再次啓動時:onPause -> onNewInent -> onResume
Activity第三次啓動時:onPause -> onNewInent -> onResume
因此,非標準模式下,activity第一次被啓動,會正常回調生命週期方法,不會回調onNewIntent方法。屢次啓動該activity後,均會調用 onNewInent方法。
注意:當調用到onNewIntent(intent)時,該參數的intent是最新的intent,可在onNewIntent中使用setIntent(intent),這樣後續使用getIntent()時將得到最新的intent.不然,後續getIntent()獲得的是舊的intent。
A畫面singleTask模式下:
畫面以下跳轉:
A-B-A
A的生命週期以下,開發者模式中,保留活動:
1. A啓動:onCreate: null == savedInstanceState -> onStart -> onResume
2. 跳轉到B:onStop
3. 跳轉到A:onNewIntent -> onRestart -> onStart -> onResume
A的生命週期以下,開發者模式中,不保留活動:
1. A啓動:onCreate: null == savedInstanceState -> onStart -> onResume
2. 跳轉到B:onStop -> onDestroy
3. 跳轉到A:onCreate: null == savedInstanceState -> onStart -> onResume
也就是說,不會走onNewIntent
主畫面設置成singleTask模式,那麼在退出登陸後,從新statActivity主畫面,而且intent傳入一個標誌位:
1.主畫面未被異常關閉時,此時會走onNewIntent()方法,而且主畫面之上的畫面會被推出棧,在該方法中根據intent傳入的標誌位,啓動從新登陸畫面,關閉主畫面;
2.主畫面被異常關閉時,此時不會走onNewIntent()方法,而且主畫面之上的畫面會被推出棧,在onCreate方法中根據intent傳入的標誌位,啓動從新登陸畫面,關閉主畫面。
注意:
activity異常退出的時候,好比屏幕橫豎切換、內存不足低優先級的activity被殺死,ondestroy仍然會被調用,除非直接退出整個進程System.exit(0)不會調用ondestroy。