引言
今天繼續的是去那幾家面試公司的一些面試題目,適合剛出來或者兩三年經驗的,大牛可以適量吐槽下,找工作的可以補補基礎。
這系列的第一篇文章請查看這里:最近找工作面的面試題目匯總(一)
1.請從中選擇引用類型或值類型
說起題,我們不由得會想到幾個名詞:棧和堆,值類型和引用類型,裝箱和拆箱。
這些概念可是C#的入門基礎呀,咱們還是要搞懂的,詳細可以查看參考文章。
這里要提下一個知識點:C#新手都有一個誤區:值類型的值都是保存在棧里,實際應該是:值類型的值是在它聲明的位置存儲的。即局部變量(參數)的值會在棧里,而當值類型作為引用類型的類型成員的話,會跟隨對象,即存儲在托管堆里。
順便提供幾張經典圖片便於讀者理解:
最后在這些概念里,我覺得比較重要的精華提要:
- 對於棧和堆的概念,我們聲明值類型和引用類型的時候,為什么會分配兩種內存而不是一種呢?只要我們仔細想一下,基本類型他們並不復雜,很多時候只包含簡單的值,比如 i=1,而對象類型則相對復雜,它們則會引用其他對象或基本類型。簡單來說,對象類型需要動態內存而基本類型則需要靜態內存。若需要分配動態內存,那么就分配到堆上;反之在棧上。
- 對於值類型和引用類型的概念,值類型,它們的內存值都分配在棧上,當我們把一個int值分配給另外一個int值時,需要創建一個完全不同的拷貝。換句話說,你可以改變其中任何一個而不會影響另外一個。這種數據類型被稱為值類型;引用類型,當我們創建一個對象,並把一個對象賦給另外一個對象時,它們的指針指向相同的內存(如下圖,當我們把obj賦給obj1時,它們指向相同的內存)。換句話說,我們改變其中一個,會影響到另外一個。
參考文章:
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的介紹就到這里,有下面幾點需要注意的地方
- lock的是引用類型的對象,string類型除外。
- lock推薦的做法是使用靜態的、只讀的、私有的對象。
- 保證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關鍵字來聲明數組
要求:
- 在方法聲明中的 params 關鍵字之后不允許任何其他參數,並且在方法聲明中只允許一個 params 關鍵字。
- 該參數必須標識一個一維數組,但類型不限,對該參數傳遞null或者0個數目的數組的引用都是合法的
參考文章:
6.怎么獲取用戶請求的Url地址
- 獲取 完整url:
string url=Request.Url.ToString();
參考文章:
寫出三元運算符實例
這個我就不說了。 ?:
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個
參考文章:
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)的兩個函數的函數名雖然相同,但函數特征不同。
- 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)那么調的是第二個。
參考文章:
9. using的意義
簡述:
提供能確保正確使用 IDisposable 對象的方便語法。它的用途就是清理非托管資源,不受GC控制的資源。Using結束后會隱式的調用Disposable方法
- 有許多其他類別的非托管資源和封裝這些資源的類庫類型,所有這些類型都必須實現IDisposable接口,而using語句確保即使在調用對象上的方法時發生異常Dispose方法也會被調用。
- 實際上,將對象放入 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();
}
}
參考文章:
10.List是什么
因為ArrayList存在不安全類型與裝箱拆箱的缺點,所以出現了泛型的概念。List類是ArrayList類的泛型等效類,它的大部分用法都與ArrayList相似,因為List類也繼承了IList接口。最關鍵的區別在於,在聲明List集合時,我們同時需要為其聲明List集合內數據的對象類型。
優點
- 類型安全
- 性能增強
- 代碼服用
參考文章: