泛型,即“參數(shù)化類型”。一提到參數(shù),最熟悉的就是定義方法時有形參,然后調(diào)用此方法時傳遞實參。那么參數(shù)化類型怎么理解呢?顧名思義,就是將類型由原來的具體的類型參數(shù)化,類似于方法中的變量參數(shù),此時類型也定義成參數(shù)形式(可以稱之為類型形參),然后在使用/調(diào)用時傳入具體的類型。——來自百度
自我理解:泛型函數(shù)就是,你定義函數(shù)時候,是萬能類型。在調(diào)用的時候,只要你把具體的類型傳進(jìn)去就好。好處呢,就是代碼的復(fù)用,減少代碼量。
在面向?qū)ο蟮恼Z言中都是有泛型的這個概念和實現(xiàn)的。比如說:JAVA、C#、C++、TypeScript等等。但是我們在看書或者學(xué)習(xí)的時候呢,一般只是看到了這樣的概念,或者說例子很簡單,就是一個Int 和 string 參數(shù)的泛型使用。
其實泛型是用的很廣泛的,特別是在寫底層框架的時候。當(dāng)大家去看源碼的時候,會看到很多泛型。最近的工作中也用到了泛型,算是寫底層吧,因為給別人調(diào)用。
工作需求是這樣的 ,使用TCP/IP協(xié)議,從客戶端發(fā)送 “結(jié)構(gòu)體”到服務(wù)端。一般都是會將數(shù)據(jù)轉(zhuǎn)化成byte[],再進(jìn)行數(shù)據(jù)的傳送。查資料和用泛型改造后:
C#代碼
// 結(jié)構(gòu)體轉(zhuǎn)byte數(shù)組
public byte[] StructToBytes<T>(T structParams)
{
var size = Marshal.SizeOf(structParams);
var buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structParams, buffer, false);
var bytes = new byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
// 結(jié)構(gòu)體轉(zhuǎn)byte數(shù)組
public static T BytesToStruct<T>(byte[] arr) where T : new()
{
// where后面的泛型約束:參數(shù)需要有一個無參的構(gòu)造函數(shù)
T structType = new T();
var size = Marshal.SizeOf(structType);
var ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(arr, 0, ptr, size);
structType = (T)Marshal.PtrToStructure(ptr, structType.GetType());
Marshal.FreeHGlobal(ptr);
return structType;
}
public struct TestStruct0
{
public int count;
public string key;
}
public struct TestStruct1
{
public int count1;
public string key1;
}
// testStruct0 為實例
StructToBytes<TestStruct0>(testStruct0)
// testStruct1 為實例
StructToBytes<TestStruct1>(testStruct1)
在方法寫成泛型以后,無論結(jié)構(gòu)體是什么,函數(shù)只需要寫一遍。調(diào)用方只需要寫結(jié)構(gòu)體的類型,和傳入相應(yīng)的實例就可以,而不需要寫多個函數(shù)。對于參數(shù)不一樣的而實現(xiàn)是一樣的函數(shù),大家可以考慮寫成泛型方法或者用接口。
因為泛型在多種面向?qū)ο笳Z言中均有實現(xiàn),為了廣大水友能更好的理解,或者說消除語言方面的區(qū)別。接下來寫一個C#、JAVA、typescript的簡單泛型函數(shù)版本。
C#的泛型函數(shù):
public void Test<T>(T params)
{
// TODO
}
// 調(diào)用實例1: Student為類型,student為傳入?yún)?shù)
Test<Student>(student);
// 調(diào)用實例2: String為類型
Test<String>("我是參數(shù)")
// 調(diào)用實例3:Int為類型
Test<Int>(100)
Java中沒有Struct,我們將用簡單的例子:
// 返回值為T類型的實例
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
// 調(diào)用
test1 obj1 = genericMethod(Class.forName("com.test.test1"));
test2 obj2 = genericMethod(Class.forName("com.test.test2"));
TypeScript 泛型函數(shù)代碼
function identity<T>(arg: T): T {
return arg;
}
// 調(diào)用
let output0 Identity(3);
let output1 = identity("myString");
自我理解用法:泛型函數(shù)一般用在基礎(chǔ)類型的函數(shù)較多,像Int、String、struct,這種不能用接口限定的,用泛型去寫方法。如果是Object類型的話,可以用接口是去限定參數(shù)。記得有一句話叫對接口編程,而不是對實現(xiàn)編程。