午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

2017年百度騰訊等 校招高頻面試題

 chenTUPI 2017-02-20
前言

參加了2017年校招,面試了阿里、百度、騰訊、滴滴、美團(tuán)、網(wǎng)易、去哪兒等公司,個(gè)人是客戶端 Android 方向,總結(jié)了面試過(guò)程中頻率出現(xiàn)較高的題目,希望對(duì)大家有所幫助。


Java


Object 有哪些方法


  • public 方法:

    getClass、equals、hashCode、toString、wait、notify

  • protected 方法:clone、finalize

  • private 方法:registerNatives,該方法作用是將不同平臺(tái)C/C++實(shí)現(xiàn)的方法映射到Java中的 native方法

public class Object{
    private static native void registerNatives();
    // 聲明后有緊接靜態(tài)代碼塊
    static {
       registerNatives();
   }
}


自動(dòng)裝箱

public static void main(String[] args) {
    int i = 0;
    Integer j = new Integer(0);
    System.out.println(j == i);
    System.out.println(j.equals(i));
}

上述代碼的輸出是

true
true


Java 虛擬機(jī) GC 根節(jié)點(diǎn)的選擇

        Java通過(guò)可達(dá)性分析來(lái)判斷對(duì)象是否存活?;舅枷胧峭ㄟ^(guò)一系列稱為”GC roots”的對(duì)象作為起始點(diǎn),可以作為根節(jié)點(diǎn)的是:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象

  • 本地方法棧中 JNI(即一般說(shuō)的 Native 方法)引用的對(duì)象

  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象

  • 方法區(qū)中常量引用的對(duì)象

        筆者這么理解,作為GC Roots的節(jié)點(diǎn)主要在全局性的引用(例如常量或類靜態(tài)屬性)與執(zhí)行上下文(例如棧幀中的本地變量表)中。

        虛擬機(jī)棧、本地方法棧這都是局部變量,某個(gè)方法執(zhí)行完,某些局部使用的對(duì)象可以被回收。


類加載機(jī)制

  • 啟動(dòng)類加載器( Bootstrap ClassLoader)啟動(dòng)類加載器無(wú)法被 java 程序員直接引用,這個(gè)類加載器負(fù)責(zé)把存放在 \lib 目錄中的,或者被 -Xbootclasspath 參數(shù)指定路徑中的,并且是被虛擬機(jī)識(shí)別的類庫(kù)加載到虛擬機(jī)內(nèi)存中。

  • 擴(kuò)展類加載器(Extension ClassLoader)負(fù)責(zé)加載在 \lib\ext 目錄中的,或者被 java.ext.dirs 系統(tǒng)變量所指定的路徑中的所有類庫(kù)。

  • 應(yīng)用程序類加載器( Application ClassLoader )這個(gè)類加載器是 ClassLoader 中的 getSystemClassLoader()方法的返回值,一般稱其為系統(tǒng)類加載器,它負(fù)責(zé)加載用戶類路徑( ClassPath )上所指定的類庫(kù)。

從 java 虛擬機(jī)的角度而降, 只存在兩種不同的類加載器:

  • 一個(gè)是啟動(dòng)類加載器( Bootstrap ClassLoader ),這個(gè)類加載使用 C++ 語(yǔ)言實(shí)現(xiàn),是虛擬機(jī)自身的一部分;

  • 另一種是其他所有的類加載器,他們由 java 語(yǔ)言實(shí)現(xiàn),獨(dú)立于虛擬機(jī)之外,并且全部繼承自 java.lang.ClassLoader

加載類的尋找范圍就是 JVM 默認(rèn)路徑加上Classpath, 類具體是使用哪個(gè)類加載器不確定。


類加載主要步驟

  • 加載 把 class 文件的二進(jìn)制字節(jié)流加載到 jvm 里面

  • 驗(yàn)證 確保 class 文件的字節(jié)流包含的信息符合當(dāng)前 jvm 的要求 有文件格式驗(yàn)證, 元數(shù)據(jù)驗(yàn)證, 字節(jié)碼驗(yàn)證, 符號(hào)引用驗(yàn)證等

  • 準(zhǔn)備 正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段, 初始化為各數(shù)據(jù)類型的零值

  • 解析 把常量值內(nèi)的符號(hào)引用替換為直接引用的過(guò)程

  • 初始化 執(zhí)行類構(gòu)造器 () 方法

  • 使用 根據(jù)相應(yīng)的業(yè)務(wù)邏輯代碼使用該類

  • 卸載 類從方法區(qū)移除


雙親委派模型

        除了頂層的啟動(dòng)類加載器之外, 其余的類加載器都應(yīng)當(dāng)有自己的父類加載器, 父子關(guān)系這兒一般都是以組合來(lái)實(shí)現(xiàn)。

        工作過(guò)程:如果一個(gè)類加載器收到了類加載的請(qǐng)求, 它首先不會(huì)自己去嘗試加載這個(gè)類, 而是把這個(gè)請(qǐng)求委派給父類加載器去完成, 最終所有的加載請(qǐng)求都會(huì)傳送到頂層的啟動(dòng)類加載器中, 只有當(dāng)父類加載器反饋?zhàn)约簾o(wú)法完成這個(gè)請(qǐng)求時(shí)候, 才由子加載器來(lái)加載。

        例如類 Object,它放在 rt.jar 中,無(wú)論哪一個(gè)類加載器要加載這個(gè)類,最終都是委派給啟動(dòng)類加載器進(jìn)行加載,因此 Object 類在程序的各種類加載器環(huán)境中都是同一個(gè)類。

        對(duì)于任何一個(gè)類, 都需要由加載它的類加載器和這個(gè)類本身一同確定其在 java 虛擬機(jī)中的唯一性。

        ClassLoader.loadClass() 的代碼如下,先檢查是否已經(jīng)被加載過(guò),如果沒(méi)有則 parent.loadClass() 調(diào)用父加載器的 loadClass() 方法,如果父加載器為空則默認(rèn)使用啟動(dòng)類加載器作為父加載器。如果父類加載器加載失敗,拋出 ClassNotFoundException,再調(diào)用自己的 findClass() 方法進(jìn)行加載。

        另外,如果我們自己實(shí)現(xiàn)類加載器,一般是 Override 復(fù)寫 findClass 方法,而不是 loadClass 方法。

protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {

   synchronized (getClassLoadingLock(name)) {

       // First, check if the class has already been loaded

       Class c = findLoadedClass(name);

       if (c == null) {

           long t0 = System.nanoTime();

           try {

               if (parent != null) {

                   c = parent.loadClass(name, false);

               } else {

                   c = findBootstrapClassOrNull(name);

               }

           } catch (ClassNotFoundException e) {

               // ClassNotFoundException thrown if class not found

               // from the non-null parent class loader

           }

           if (c == null) {

               // If still not found, then invoke findClass in order

               // to find the class.

               long t1 = System.nanoTime();

               c = findClass(name); //可以O(shè)verride該方法

           }

       }

       if (resolve) {

           resolveClass(c);

       }

       return c;

   }
}


Java 后臺(tái)


JSP 與 Servlet 的關(guān)系

  • Tomcat 等 Web 容器最終會(huì)把 JSP轉(zhuǎn)化為 Servlet

  • Jsp更擅長(zhǎng)表現(xiàn)于頁(yè)面顯示, Servlet更擅長(zhǎng)于邏輯控制

  • Servlet是利用 System.out.println() 來(lái)輸出 html 代碼,由于包括大量的HTML標(biāo)簽、大量的靜態(tài)文本及格式等,導(dǎo)致Servlet的開發(fā)效率低下

  • JSP通過(guò)在標(biāo)準(zhǔn)的HTML頁(yè)面中嵌入Java代碼,其靜態(tài)的部分無(wú)須Java程序控制,Java 代碼只控制那些動(dòng)態(tài)生成的信息

  • 最終 JSP 被容器解釋為 Servlet,其中Html 代碼也是用 System.out.println() 等拼接輸出的

  • JSP 第一次訪問(wèn)的時(shí)候,要轉(zhuǎn)化為 java 文件,然后編譯為 class 文件,所以第一次訪問(wèn) JSP 速度會(huì)比較慢,后面會(huì)快很多


Servlet 生命周期

主要是 java.servlet.Servlet 接口中的init() 、service() 、和 destroy() 3個(gè)方法。

  • 初始化階段,web容器通過(guò)調(diào)用 init() 方法來(lái)初始化 Servlet 實(shí)例,在 Servlet 的整個(gè)生命周期類,init() 方法只被調(diào)用一次

  • 客戶請(qǐng)求到來(lái)時(shí),容器會(huì)開始一個(gè)新線程,并調(diào)用 servlet 的 service() 方法,service() 方法根據(jù)請(qǐng)求的http方法來(lái)調(diào)用 doget() 或 dopost()

  • 終止階段調(diào)用 destroy() 方法,銷毀一些資源


GET 請(qǐng)求 vs POST 請(qǐng)求

  • GET 用于信息獲取,是安全的和冪等的,GET 一般是對(duì)后臺(tái)數(shù)據(jù)庫(kù)的信息進(jìn)行查詢

  • POST 表示可能修改變服務(wù)器上的資源的請(qǐng)求,一般是對(duì)后臺(tái)數(shù)據(jù)庫(kù)進(jìn)行增、刪、改的操作

  • GET 請(qǐng)求的參數(shù)會(huì)跟在URL后進(jìn)行傳遞,請(qǐng)求的數(shù)據(jù)會(huì)附在URL之后,以 ? 分割URL和傳輸數(shù)據(jù),參數(shù)之間以 & 相連,一般瀏覽器對(duì) URL 的長(zhǎng)度會(huì)有限制

  • POST 請(qǐng)求,提交的數(shù)據(jù)則放置在是 HTTP 包的包體中,用類似 Key-Value 的格式發(fā)送一些數(shù)據(jù),相對(duì)來(lái)說(shuō),GET 請(qǐng)求會(huì)把請(qǐng)求的參數(shù)暴露在 URL 中,安全性比 POST 差一些


HTTP 請(qǐng)求的基本格式

  •  請(qǐng)求行

  •  請(qǐng)求頭(參數(shù)頭)

  •  空白行

  • [] 請(qǐng)求實(shí)體(GET沒(méi)有, POST有


數(shù)據(jù)庫(kù)


索引的分類

主要分為聚集索引和非聚集索引:

  • 聚集索引存儲(chǔ)記錄物理上連續(xù),而非聚集索引是邏輯上的連續(xù),物理存儲(chǔ)并不連續(xù)

  • 聚集索引一個(gè)表只能有一個(gè),而非聚集索引一個(gè)表可以存在多個(gè)


ResultSet 統(tǒng)計(jì)記錄數(shù)目

Java 中使用 JDBC 連接數(shù)據(jù)庫(kù),最后都會(huì)得到一個(gè) ResultSet,比如如下的代碼

Connection con = DriverManager.getConnection(url, username, password);

Statement sta = con.createStatement();

String sql = 'select * from student';

ResultSet resultSet = sta.executeQuery(sql);

那么如何根據(jù)得到的 ResultSet 統(tǒng)計(jì)一共有多少條記錄呢?注意:ResultSet 沒(méi)有提供類似 size()length 的 API 來(lái)直接獲取總記錄數(shù)。

方法1:利用循環(huán)

int sum = 0;      
while(resultSet.next()){      
   sum++;      
}

方法2:利用ResultSet的getRow方法來(lái)獲得ResultSet的總行數(shù)

resultSet.last(); //移到最后一行     

int rowCount = resultSet.getRow(); //得到當(dāng)前行號(hào),也就是記錄數(shù)


設(shè)計(jì)模式


單例模式

        單例模式中必須保證只有一個(gè)實(shí)例存在。有時(shí)候單例是為了避免重復(fù)創(chuàng)建多個(gè)實(shí)例造成資源浪費(fèi),有時(shí)候也是為了避免多個(gè)不同的實(shí)例導(dǎo)致系統(tǒng)不一致的行為。

        Android 中,App啟動(dòng)時(shí)系統(tǒng)會(huì)創(chuàng)建一個(gè) Application 對(duì)象,用來(lái)存儲(chǔ)系統(tǒng)的一些信息,這兒的 Application 就是是單例模式的應(yīng)用??梢酝ㄟ^(guò) Context.getApplicationContext() 獲取唯一的 Application 實(shí)例。

class Singleton {  
   private volatile static Singleton instance;  

   private Singleton() { }  

   public static Singleton getInstance() {  
       //第一重判斷  
       if (instance == null) {  
           //鎖定代碼塊  
           synchronized (Singleton.class) {  
               //第二重判斷  
               if (instance == null) {  
                   instance = new Singleton(); //創(chuàng)建單例實(shí)例  
               }  
           }  
       }  
       return instance;  
   }  
}

為什么 synchronized 里面需要加一次判斷 if (instance == null),是考慮這樣的特殊情形:比如線程A、B都到達(dá)第一個(gè) if (instance == null),線程A進(jìn)入 synchronized 代碼中創(chuàng)建實(shí)例,線程B排隊(duì)等待。但當(dāng)A執(zhí)行完畢時(shí),線程B進(jìn)入 synchronized 鎖定代碼,它并不知道實(shí)例已經(jīng)創(chuàng)建,將繼續(xù)創(chuàng)建新的實(shí)例,導(dǎo)致產(chǎn)生多個(gè)單例對(duì)象。


也可以用內(nèi)部類的方式創(chuàng)建,

public class Singleton(){

   private static class Inner {

       private static Singleton instance = new Singleton();

   }

   private Singleton() {

   }

   public static Singleton getInstance(){

       return Inner.instance;

   }
}


模板方法模式

        在父類中實(shí)現(xiàn)一個(gè)算法不變的部分,并將可變的行為留給子類來(lái)實(shí)現(xiàn)。

        比如 AsyncTask 里面的四個(gè)方法 onPreExecute、doInBackground、onProgressUpdateonPostExecute

        還有 Activity 也應(yīng)用了模板方法模式
        onCreate、onStart、onResume、onPause、onStoponDestroy、onRestart


適配器模式

分為兩種:類的適配器模式、對(duì)象的適配器模式

Android 里的 ListView 和 RecyclerViewsetAdapter() 方法就是使用了適配器模式。


觀察者模式

在 GUI 中,不管是 Windows 桌面應(yīng)用、或者 Android、IOS,都會(huì)給某個(gè)按鈕 Button 設(shè)置監(jiān)聽事件,這兒就是使用了觀察者模式。Android 中設(shè)置 Button 的監(jiān)聽事件代碼如下:

final Button button = (Button) findViewById(R.id.button_id);

button.setOnClickListener(new View.OnClickListener() {

   public void onClick(View v) {

       // Perform action on click

   }
});


筆試編程題


線程 VS 進(jìn)程

關(guān)于線程和進(jìn)程,不正確的描述是__。(選 D 棧是線程私有, 保存其運(yùn)行狀態(tài)和局部變量 )

  1. 進(jìn)程的隔離性要好于線程

  2. 線程在資源消耗上通常要比進(jìn)程輕量

  3. 不同進(jìn)程間不會(huì)共享邏輯地址空間

  4. 同一個(gè)進(jìn)程的線程之間共享內(nèi)存,包括堆和棧

  5. 進(jìn)程間有途徑共享大量?jī)?nèi)存中的數(shù)據(jù)

  6. 線程間通訊可以通過(guò)直接訪問(wèn)全局變量,或者使用進(jìn)程間通訊的機(jī)制(IPC)


找出未打卡的員工

題目:輸入兩行數(shù)據(jù),第一行為全部員工的 id,第二行為某一天打卡的員工 id,已知只有一個(gè)員工沒(méi)有打卡,求出未打卡員工的 id。(員工 id 不重復(fù),每行輸入的 id 未排序)

輸入:
1001 1003 1002 1005 1004
1002 1003 1001 1004
輸出:
1005


分析:可以用兩個(gè) List,第一個(gè) List 保存所有員工的 id,第二個(gè) List 保存打卡員工的 id,從第一個(gè)List 中把第二個(gè) List 的數(shù)據(jù)都刪除,最終剩下的就是未打卡員工的 id。


更好的方法:異或,兩行數(shù)據(jù)中未打卡員工的 id 出現(xiàn)了一次,其余員工的 id 都出現(xiàn)了2次,兩個(gè)相同的數(shù)異或?yàn)?。

public static void main(String[] args) {

   Scanner scan = new Scanner(System.in);

   while (scan.hasNext()) {


       String[] ids = scan.nextLine().split(' ');

       String[] marks = scan.nextLine().split(' ');

       int result = 0;

       for (int i = 0; i < ids.length;="" i++)="">

           result ^= Integer.parseInt(ids[i]);
       }        for (int i = 0; i < marks.length;="" i++)="">
           result ^= Integer.parseInt(marks[i]);
       }
       System.out.println(result);
   }
}


手寫代碼題


快速排序

排序是經(jīng)典面試題,公司也希望通過(guò)手寫快排來(lái)考察面試者的編程習(xí)慣和基本功。

// 排序范圍 [start, end], 包含 end

public void sort(int[] arr, int start, int end) {

   if (start < end)="">

       int p = partition(arr, start, end);

       quickSort(arr, start, p - 1);

       quickSort(arr, p + 1, end);

   }

}

// 一次劃分代碼,返回被劃分后的基準(zhǔn)位置

public static int partition(int[] arr, int left, int right) {

   int pivot = arr[left];

   while (left <>{

       while (left < right="" &&="" arr[right]="">= pivot)

           right--;

       if (left <>

           arr[left++] = arr[right];

       while (left < right="" &&="" arr[left]=""><=>

           left++;

       if (left <>

           arr[right--] = arr[left];
   }

   arr[left] = pivot;

   return left;

}

Note:快排是不穩(wěn)定的,常見的穩(wěn)定排序是:冒泡、插入、歸并


括號(hào)字符串是否合法

        某個(gè)字符串只包括 ( ,判斷其中的括號(hào)是否匹配正確,比如 (()()) 正確,((())() 錯(cuò)誤,不允許使用棧

        這種類似題的常見思路是棧,對(duì)于左括號(hào)入棧,如果遇到右括號(hào),判斷此時(shí)棧頂是不是左括號(hào),是則將其出棧,不是則該括號(hào)序列不合法。

        面試官要求不能使用棧,可以使用計(jì)數(shù)器,利用 int count 字段。

public static boolean checkBrackets(String str) {

   char[] cs = str.toCharArray();

   int count = 0;

   for (int i = 0; i < cs.length;="" i++)="">

       if (cs[i] == '(')

           count++;

       else {

           count--;

           if (count < 0)="">

               return false;

           }
       }

   }

   return count == 0;

}


撲克牌隨機(jī)發(fā)牌

        對(duì)于52張牌,實(shí)現(xiàn)一個(gè)隨機(jī)打算撲克牌順序的程序。52張牌使用 int 數(shù)組模擬。

        該算法的難點(diǎn)是如何保證隨機(jī)性?有個(gè)經(jīng)典算法 shuffle,思路就是遍歷數(shù)組,在剩下的元素里再隨機(jī)取一個(gè)元素,然后再在剩下的元素里再隨機(jī)取一個(gè)元素。每次取完元素后,我們就不會(huì)讓這個(gè)元素參與下一次的選取。

To shuffle an array a of n elements (indices 0..n-1):

 for i from n ? 1 downto 1 do

      j ← random integer with 0 ≤ j ≤ i
      exchange a[j] and a[i]

注意這兒是 0 ≤ j ≤ i,包括 j=i 的情況,因?yàn)榭赡芟磁坪竽硞€(gè)牌未發(fā)生交換,比如第51張牌還是原來(lái)的第51張牌。

public void randomCards() {

   int[] data = new int[52];

   Random random= new Random();

   for (int i = 0; i < data.length;="">

       data[i] = i;

   for (int i = data.length - 1; i > 0; i--) {

       int temp = random.nextInt(i+1); //產(chǎn)生 [0,i] 之間的隨機(jī)數(shù)

       swap(data,i,temp);
   }
}


智力題


金條付費(fèi)

        你讓工人為你工作7天,回報(bào)是一根金條,這個(gè)金條平分成相連的7段,你必須在每天結(jié)束的時(shí)候給他們一段金條,如果只允許你兩次把金條弄斷,你如何給你的工人付費(fèi)?

答案:切成一段,兩段,和四段。

第1天:給出1
第2天:給出2,還回1
第3天:給出1
第4天:給出4,還回1+2
第5天:給出1
第6天:給出2,還回1
第7天:給出1


賽馬

        25匹馬,速度都不同,但每匹馬的速度都是定值?,F(xiàn)在只有5條賽道,無(wú)法計(jì)時(shí),即每賽一場(chǎng)最多只能知道5匹馬的相對(duì)快慢。問(wèn)最少賽幾場(chǎng)可以找出25匹馬中速度最快的前3名?

答案:

  • 25匹馬分成5組,先進(jìn)行5場(chǎng)比賽

  • 再將剛才5場(chǎng)的冠軍進(jìn)行第6場(chǎng)比賽,得到第一名。按照第6場(chǎng)比賽的名詞把前面5場(chǎng)比賽所在的組命名為 A、B、C、D、E 組,即 A 組的冠軍是第6場(chǎng)第一名,B 組的冠軍是第二名 …

  • 分析第2名和第3名的可能性,如果確定有多于3匹馬比某匹馬快,那它可以被淘汰了。因?yàn)?D 組是第6場(chǎng)的第四名,整個(gè)D 組被淘汰了,同意整個(gè) E 組被淘汰。剩下可能是整體的第2、3名的就是C組的第1名、B組的1、2名、A組的第2、3名。取這5匹馬進(jìn)行第7場(chǎng)比賽

  • 所以,一共需要7場(chǎng)比賽


本文鏈接:http://www./article/it-interview-question-2017.html
本文作者:碼農(nóng)網(wǎng) – 陳小波


IT技術(shù)群,期待你的加入
后臺(tái)回復(fù)“入群”審核受邀

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多