最近找工作面的面試題目匯總(二)


引言

今天繼續的是去那幾家面試公司的一些面試題目,適合剛出來或者兩三年經驗的,大牛可以適量吐槽下,找工作的可以補補基礎。

這系列的第一篇文章請查看這里:最近找工作面的面試題目匯總(一)

1.請從中選擇引用類型或值類型

說起題,我們不由得會想到幾個名詞:棧和堆,值類型和引用類型,裝箱和拆箱。

這些概念可是C#的入門基礎呀,咱們還是要搞懂的,詳細可以查看參考文章。

這里要提下一個知識點:C#新手都有一個誤區:值類型的值都是保存在棧里,實際應該是:值類型的值是在它聲明的位置存儲的。即局部變量(參數)的值會在棧里,而當值類型作為引用類型的類型成員的話,會跟隨對象,即存儲在托管堆里。

順便提供幾張經典圖片便於讀者理解:

image

image

最后在這些概念里,我覺得比較重要的精華提要:

  1. 對於棧和堆的概念,我們聲明值類型和引用類型的時候,為什么會分配兩種內存而不是一種呢?只要我們仔細想一下,基本類型他們並不復雜,很多時候只包含簡單的值,比如 i=1,而對象類型則相對復雜,它們則會引用其他對象或基本類型。簡單來說,對象類型需要動態內存而基本類型則需要靜態內存。若需要分配動態內存,那么就分配到堆上;反之在棧上。
  2. 對於值類型和引用類型的概念,值類型,它們的內存值都分配在棧上,當我們把一個int值分配給另外一個int值時,需要創建一個完全不同的拷貝。換句話說,你可以改變其中任何一個而不會影響另外一個。這種數據類型被稱為值類型;引用類型,當我們創建一個對象,並把一個對象賦給另外一個對象時,它們的指針指向相同的內存(如下圖,當我們把obj賦給obj1時,它們指向相同的內存)。換句話說,我們改變其中一個,會影響到另外一個。

參考文章

  1. 圖解C#的值類型,引用類型,棧,堆,ref,out
  2. 6個重要的.NET概念:棧,堆,值類型,引用類型,裝箱,拆箱強烈推薦此篇文章
  3. .NET下的內存分配機制
  4. 從棧和堆中來看值傳遞和引用傳遞

2.判斷一個string變量是否為空

最普通的用法當然就是:

  • s.Length == 0
  • s == string.Empty
  • s == ""

效率上:s.Length == 0 > s == string.Empty > s == ""

不過 net 2.0后,可用String.IsNullOrEmpty(s) 來進行判斷

參考文章

String.IsNullOrWhiteSpace和String.IsNullOrEmpty的區別

3.Lock的作用

關於lock的介紹就到這里,有下面幾點需要注意的地方

  1. lock的是引用類型的對象,string類型除外。
  2. lock推薦的做法是使用靜態的、只讀的、私有的對象。
  3. 保證lock的對象在外部無法修改才有意義,如果lock的對象在外部改變了,對其他線程就會暢通無阻,失去了lock的意義。

還有摘自本篇評論的精彩回復:

this 表示的就是當前實例,當你再new一個的時候,鎖定的就不再是同一個對象了。 不能鎖定值類型的原因是,當這個值類型傳遞到另一個線程的時候,會創建一個副本,鎖定的也不再是同一個對象了。 鎖定字符串帶來的問題是,字符串在CLR中會暫存在 內存中,如果有兩個變量被分配了相同的字符串內容,那么這兩個引用會指向同一塊內存,實際鎖定也就是同一個對象,這就會導致整個應用程序的阻塞。所以鎖定字符串是非常危險的行為。

參考文章:

1.[C#基礎]說說lock到底鎖誰?](http://www.cnblogs.com/wolf-sun/p/4209521.html)

4.abstract class 和 interface 有什么區別

這篇已經有提過了:請參閱:最近找工作面的面試題目匯總(一)

5.關鍵字params是什么

參考文章:

為了將方法聲明為可以接受可變數量參數的方法,我們可以使用params關鍵字來聲明數組

要求:

  1. 在方法聲明中的 params 關鍵字之后不允許任何其他參數,並且在方法聲明中只允許一個 params 關鍵字
  2. 該參數必須標識一個一維數組,但類型不限,對該參數傳遞null或者0個數目的數組的引用都是合法的

參考文章:

  1. C# 參數關鍵字params
  2. C#中的params關鍵字的用法

6.怎么獲取用戶請求的Url地址

  1. 獲取 完整url:
string url=Request.Url.ToString(); 

參考文章:

  1. asp.net獲取當前網址url

寫出三元運算符實例

這個我就不說了。 ?:

7.說明Stack和Queue的區別

1.Queue的定義

Queue是先進先出(first in first-out)數據結構,表示放進queue的第一個數據,會是第一個拿出來使用

示例:

//建立Queue的對象
            var myqueue = new Queue<string>();
            //新增數據進入queue
            myqueue.Enqueue("第1個");
            myqueue.Enqueue("第2個");
            myqueue.Enqueue("第3個");
            //查看queue的所有資料
            foreach (string queue in myqueue)
            {
                Console.WriteLine(queue);
            }
            //使用Peek()方法查看queue里的第一條數據
            Console.WriteLine("");
            Console.WriteLine("使用peek方法的輸出值:" + myqueue.Peek());
            //使用Dequeue()方法從queue中拿出值
            //記得是先進先出的獲取方法
            Console.WriteLine("第一個被我拿走了:" + myqueue.Dequeue());
            //查看剩下的值
            Console.WriteLine("查看myqueue剩下的值");
            foreach (string queue in myqueue)
            {
                Console.WriteLine(queue.ToString());
            }
            //查看某位置的值
            Console.WriteLine("查看特定位置的值");
            Console.WriteLine(myqueue.ElementAt(1));

運行結果

第1個
第2個
第3個

使用peek方法的輸出值:第1個
第一個被我拿走了:第1個
查看myqueue剩下的值
第2個
第3個
查看特定位置的值
第3個
第3個
第2個
第1個

Peek看到的數據:第3個
被拿走了:第3個
查看剩下的數據
第2個
第1個

2.Stack的定義

Stack為后進先出(first-in last-out)的數據結構,表示第一個進去的數據,反而是最后一個出來。

示例代碼

 //建立Stack對象
            var mystack = new Stack<string>();
            //插入數據
            mystack.Push("第1個");
            mystack.Push("第2個");
            mystack.Push("第3個");
            //查看數據
            foreach(string stack in mystack)
            {
                Console.WriteLine(stack.ToString());
            }
            //Stack與Queue一樣有Peek方法查看第一條數據
            Console.WriteLine("");
            Console.WriteLine("Peek看到的數據:"+mystack.Peek());

            //使用Pop方法取出數據
            Console.WriteLine("被拿走了:"+mystack.Pop());
            Console.WriteLine("查看剩下的數據");
            foreach (string stack in mystack)
            {
                Console.WriteLine(stack.ToString());
            }

運行結果

第3個
第2個
第1個

Peek看到的數據:第3個
被拿走了:第3個
查看剩下的數據
第2個
第1個

參考文章:

1..NET源碼Stack 和Queue 的實現

2.C#資料群集系列菜單-『Queue與Stack』

8.Overload和Override的區別

1.Overload的定義

重載應該叫overload,重載某個方法是在同一個類或父子關系類中發生的!重載(overload)是提供了一種機制, 相同函數名通過不同的返回值類型以及參數來表來區分的機制

overload:  同一類中或父子關系類中皆可.
                   public string ToString(){return "a";}
                   public string ToString(int id){return id.ToString();}

2.Override的定義

重寫叫override,重寫是在子類中重寫父類中的方法。重寫(override)是用於重寫基類的虛方法,這樣在派生類中提供一個新的方法

override:   父類:public virtual string ToString(){return "a";}
                   子類:public override string ToString(){return "b";}

3.兩者間的區別

很本質的區別就是看函數特征:覆寫(Override)的兩個函數的函數特征相同,重載(Overload)的兩個函數的函數名雖然相同,但函數特征不同。

  1. override 是在繼承的時候,如果你寫的函數與要繼承的函數函數特征相同,那么,加上這個關鍵字,在使用這個子類的這個函數的時候就看不見父類(或超類)的函數了,它被覆蓋掉了。
    比如:Derived繼承了Base,Base里面有void A(int a) ,那么如果你Derived里面覺得A寫得不好或不適合這個類,你想重新再寫一遍A里的代碼,那么就寫override void A(int a)這樣,原來的那個函數就被你新寫的這個覆蓋掉了。
    overload 是重載,就是說函數名相同,函數特征不同,系統會根據你提供的參數來調相應的函數。比如:void A(int a)和void A(int a,int b) ,如果你用的是A(1)那么調的是第一個,如果是A(1,1)那么調的是第二個。

參考文章:

  1. C#中override和overload的區別

9. using的意義

簡述:

提供能確保正確使用 IDisposable 對象的方便語法。它的用途就是清理非托管資源,不受GC控制的資源。Using結束后會隱式的調用Disposable方法

  1. 有許多其他類別的非托管資源和封裝這些資源的類庫類型,所有這些類型都必須實現IDisposable接口,而using語句確保即使在調用對象上的方法時發生異常Dispose方法也會被調用。
  2. 實際上,將對象放入 try 塊中並在finally塊中調用Dispose一樣可以達到同樣的效果,而這功能就是編譯器轉換using語句的方式。

以下兩段代碼的作用是一致的

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}
 {
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

參考文章:

  1. using 語句(C# 參考)
  2. 三種C# using的用法

10.List是什么

因為ArrayList存在不安全類型與裝箱拆箱的缺點,所以出現了泛型的概念。List類是ArrayList類的泛型等效類,它的大部分用法都與ArrayList相似,因為List類也繼承了IList接口。最關鍵的區別在於,在聲明List集合時,我們同時需要為其聲明List集合內數據的對象類型。

優點

  1. 類型安全
  2. 性能增強
  3. 代碼服用

參考文章:

  1. 數組排序方法的性能比較(3):LINQ排序實現分析
  2. C# 泛型List的定義、作用、用法
  3. C#中數組、ArrayList和List三者的區別


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM