Golang Reflect反射
Go是靜態型別語言。每個變數都擁有一個靜態型別,這意味著每個變數的型別在編譯時都是確定的:int,float32, *AutoType, []byte, chan []int 諸如此類。
動靜型別
編譯時就知道變數型別的是靜態型別;執行時才知道一個變數型別的叫做動態型別。
1. 靜態型別
靜態型別就是變數宣告時的賦予的型別。比如:
type MyInt int // int 就是靜態型別
type A struct{
Name string // string就是靜態
}
var i *int // *int就是靜態型別
2. 動態型別
動態型別:執行時給這個變數複製時,這個值的型別(如果值為nil的時候沒有動態型別)。一個變數的動態型別在執行時可能改變,這主要依賴於它的賦值(前提是這個變數時介面型別)。
var A interface{} // 靜態型別interface{}
A = 10 // 靜態型別為interface{} 動態為int
A = "String" // 靜態型別為interface{} 動態為string
var M *int
A = M // 猜猜這個呢?
來看看這個例子:
//定義一個介面
type Abc interface {
String() string
}
// 型別
type Efg struct{
data string
}
// 型別Efg實現Abc介面
func (e *Efg)String()string{
return e.data
}
// 獲取一個*Efg例項
func GetEfg() *Efg{
return nil
}
// 比較
func CheckAE(a Abc) bool{
return a == nil
}
func main() {
efg := GetEfg()
b := CheckAE(efg)
fmt.Println(b)
os.Exit(1)
}
關於動靜態型別就到這裡,詳細請自行Google,百度吧。
反射
那麼什麼時候下使用反射呢?
有時候你想在執行時使用變數來處理變數,這些變數使用編寫程式時不存在的資訊。也許你正試圖將來自檔案或網路請求的資料對映到變數中。也許建立一個適用於不同型別的tool。在這些情況下,你需要使用反射。反射使您能夠在執行時檢查型別。它還允許您在執行時檢查,修改和建立變數,函式和結構。
型別
你可以使用反射來獲取變數的型別: var t := reflect.Typeof(v)。返回值是一個reflect.Type型別。該值有很多定義好的方法可以使用。
Name()
返回型別的名稱。 但是像切片或指標是沒有型別名稱的,只能返回空字串。
Kind()
Kind有slice, map , pointer指標,struct, interface, string , Array, Function, int或其他基本型別組成。Kind和Type之前要做好區分。如果你定義一個 type Foo struct {}, 那麼Kind就是struct, Type就是Foo。
*小知識點:反射變數對應的Kind方法的返回值是基型別,並不是靜態型別。下面的例子中:
type MyInt int
var x MyInt = 7
v := reflect.ValueOf(x)
變數v的Kind依舊是reflect.Int,而不是MyInt這個靜態型別。Type可以表示靜態型別,而Kind不可以。
*注意點: 在使用refelct包時, reflect包會假定你已經知道所做的是什麼,否則引發panic。 例如你呼叫了與當前reflect.Type 不同的型別上的方法,那麼就會引發panic。
Elem()
如果你的變數是一個指標、map、slice、channel、Array。那麼你可以使用reflect.Typeof(v).Elem()來確定包含的型別。
案例程式碼
type Foo struct {
A int `tag1:"Tag1" tag2:"Second Tag"`
B string
}
func main(){
// Struct
f := Foo{A: 10, B: "Salutations"}
// Struct型別的指標
fPtr := &f
// Map
m := map[string]int{"A": 1 , "B":2}
// channel
ch := make(chan int)
// slice
sl:= []int{1,32,34}
//string
str := "string var"
// string 指標
strPtr := &str
tMap := examiner(reflect.TypeOf(f), 0)
tMapPtr := examiner(reflect.TypeOf(fPtr), 0)
tMapM := examiner(reflect.TypeOf(m), 0)
tMapCh := examiner(reflect.TypeOf(ch), 0)
tMapSl := examiner(reflect.TypeOf(sl), 0)
tMapStr := examiner(reflect.TypeOf(str), 0)
tMapStrPtr := examiner(reflect.TypeOf(strPtr), 0)
fmt.Println("tMap :", tMap)
fmt.Println("tMapPtr: ",tMapPtr)
fmt.Println("tMapM: ",tMapM)
fmt.Println("tMapCh: ",tMapCh)
fmt.Println("tMapSl: ",tMapSl)
fmt.Println("tMapStr: ",tMapStr)
fmt.Println("tMapStrPtr: ",tMapStrPtr)
}
// 型別以及元素的型別判斷
func examiner(t reflect.Type, depth int) map[int]map[string]string{
outType := make(map[int]map[string]string)
// 如果是一下型別,重新驗證
switch t.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
fmt.Println("這幾種型別Name是空字串:",t.Name(), ", Kind是:", t.Kind())
// 遞迴查詢元素型別
tMap := examiner(t.Elem(), depth)
for k, v := range tMap{
outType[k] = v
}
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
f := t.Field(i) // reflect欄位
outType[i] = map[string]string{
"Name":f.Name,
"Kind":f.Type.String(),
}
}
default:
// 直接驗證型別
outType = map[int] map[string]string{depth:{"Name":t.Name(), "Kind":t.Kind().String()}}
}
return outType
}
執行結果:
其中t.Field(index) 必須使用在Struct上 , 所以,細讀文件才行
利用反射讀取,設定,建立
看完了上面關於reflect檢測變數型別外,我們使用反射讀取、設定和建立。
要想讀取一個變數的值,首先需要一個reflect.Valueof( var ) 例項(reflectVal := reflect.Valueof(var)), 同時也可以獲取變數的型別了。
要想修改一個變數的值,那麼必須通過該變數的指標地址 , 取消指標的引用 。通過refPtrVal := reflect.Valueof( &var )的方式獲取指標型別,你使用refPtrVal.elem( ).set(一個新的reflect.Value)來進行更改,傳遞給set()的值也必須是一個reflect.value。
要想建立一個值,那麼使用NewPtrVal := reflect.New( vartype ) 傳遞一個reflect.Type型別。 返回的指標型別就可以使用以上修改的方式寫入值。
最後,你可以通過呼叫interface()方法返回一個正常的變數。因為Golang沒有泛型,變數的原始型別丟失;該方法返回一個型別為interface{} 的值。如果建立了一個指標以便可以修改該值,則需要使用elem().interface()來反引用reflect的指標。在這兩種情況下,您都需要將空介面轉換為實際型別才能使用它。
例項程式碼:
type Foo struct {
A int `tag1:"Tag1" tag2:"Second Tag"`
B string
}
func main(){
// 反射的使用
s := "String字串"
fo := Foo{A: 10, B: "欄位String字串"}
sVal := reflect.ValueOf(s)
// 在沒有獲取指標的前提下,我們只能讀取變數的值。
fmt.Println(sVal.Interface())
sPtr := reflect.ValueOf(&s)
sPtr.Elem().Set(reflect.ValueOf("修改值1"))
sPtr.Elem().SetString("修改值2")
// 修改指標指向的值,原變數改變
fmt.Println(s)
fmt.Println(sPtr) // 要注意這是一個指標變數,其值是一個指標地址
foType := reflect.TypeOf(fo)
foVal := reflect.New(foType)
// foVal.Elem().Field(0).SetString("A") // 引發panic
foVal.Elem().Field(0).SetInt(1)
foVal.Elem().Field(1).SetString("B")
f2 := foVal.Elem().Interface().(Foo)
fmt.Printf("%+v, %d, %s\n", f2, f2.A, f2.B)
}
執行結果:
記憶10秒。
建立slice, map, chan
除了建立內建和使用者定義型別的例項之外,還可以使用反射來建立通常需要make功能的例項。使用reflect.Makeslice,reflect.Makemap和reflect.Makechan函式來製作slice,map或channel。
// 反射建立map slice channel
intSlice := make([]int, 0)
mapStringInt := make(map[string]int)
sliceType := reflect.TypeOf(intSlice)
mapType := reflect.TypeOf(mapStringInt)
// 建立新值
intSliceReflect := reflect.MakeSlice(sliceType, 0, 0)
mapReflect := reflect.MakeMap(mapType)
// 使用新建立的變數
v := 10
rv := reflect.ValueOf(v)
intSliceReflect = reflect.Append(intSliceReflect, rv)
intSlice2 := intSliceReflect.Interface().([]int)
fmt.Println(intSlice2)
k := "hello"
rk := reflect.ValueOf(k)
mapReflect.SetMapIndex(rk, rv)
mapStringInt2 := mapReflect.Interface().(map[string]int)
fmt.Println(mapStringInt2)
執行結果:
建立函式
使用reflect.Makefunc()建立,這個函式需要我們想要做的函式的reflect.type和一個輸入引數是[] reflect.value型別的slice,其輸出引數也是型別[] reflect.value的閉包。下面是一個簡單的例子,檢測任意給定函式的執行時長:
package main
import (
"reflect"
"time"
"fmt"
"runtime"
)
/*
將建立Func封裝, 非reflect.Func型別會panic
當然makeFunc的閉包函式表示式型別是固定的,可以查閱一下文件。
細讀文件的reflect.Value.Call()方法。
*/
func MakeTimedFunction(f interface{}) interface{} {
rf := reflect.TypeOf(f)
if rf.Kind() != reflect.Func {
panic("非Reflect.Func")
}
vf := reflect.ValueOf(f)
wrapperF := reflect.MakeFunc(rf, func(in []reflect.Value) []reflect.Value {
start := time.Now()
out := vf.Call(in)
end := time.Now()
fmt.Printf("calling %s took %v\n", runtime.FuncForPC(vf.Pointer()).Name(), end.Sub(start))
return out
})
return wrapperF.Interface()
}
func time1() {
fmt.Println("time1Func===starting")
time.Sleep(1 * time.Second)
fmt.Println("time1Func===ending")
}
func time2(a int) int {
fmt.Println("time2Func===starting")
time.Sleep(time.Duration(a) * time.Second)
result := a * 2
fmt.Println("time2Func===ending")
return result
}
func main(
相關推薦
Golang Reflect反射
Go是靜態型別語言。每個變數都擁有一個靜態型別,這意味著每個變數的型別在編譯時都是確定的:int,float32, *AutoType, []byte, chan []int 諸如此類。
動靜型別
編譯時就知道變數型別的是靜態型別;執行時才知道一個變數型
golang-利用反射給結構體賦值
cnblogs logs val valueof blog eof 成員 str byname 由於想給一個結構體的部分成員賦值,但是有不知道具體名字,故將tag的json名字作為索引,按照json名字來一一賦值
//將結構體裏的成員按照json名字來賦值
func
GO語言使用之Reflect(反射)
一、從案列場景引入反射
定義了兩個函式test1和test2,定義一個介面卡函式用作統一處理介面: (1) 定義了兩個函式
test1 := func(v1 int, v2 int) {
t.Log(v1, v2)
}
test2 := func(v1 int, v2
Java- Reflect 反射 學習 總結
目錄
Class 類的使用
動態載入類
獲取方法資訊
獲取成員資訊
獲取構造方法
方法的反射
泛型的本質
學習總結
1、Class 類的使用
 
Java原始碼分析——java.lang.reflect反射包解析(三) 動態代理、Proxy類、WeakCache類
代理模式是一個經常被各種框架使用的模式,比如Spring AOP、Mybatis中就經常用到,當一個類訪問另外一個類困難時,可通過一個代理類來間接訪問,在Java中,為了保證程式的簡單性,代理類與目標類需要實現相同的介面。也就是說代理模式起
Java原始碼分析——java.lang.reflect反射包解析(二) Array類,陣列的建立
在Java中,引用型別中有那麼幾個特殊的類,Object類是所有類的起源、Class類定義所有類的抽象與行為、ClassLoader類實現了類從.class檔案中載入進jvm,而Array陣列類,則實現了陣列手動的建立。
&
Java原始碼分析——java.lang.reflect反射包解析(一) AccessibleObject、ReflectionFactory、Filed、Method、Constructor類
Java的反射機制一直是被人稱讚的,它的定義是:程式在執行中時,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性。簡單的來說就是可以通過Java的反射機制知道自己想知道的類的一切資訊。
golang reflect
在計算機中,反射表示程式能夠檢查自身結構的一種能力,尤其是型別。通過反射,可以獲取物件型別的詳細資訊,並可動態操作物件。
實現 包手冊地址:https://studygolang.com/static/pkgdoc/pkg/reflect.htm
Import ("reflect")
常用的主
[golang]golang reflect詳細用法整理
本部落格原創博文版權所有 @[email protected]
僅供交流學習使用用於商業用途請聯絡原作者
轉載請註明出處:http://blog.sina.com.cn/ally2014
java Introspector內省和Reflect反射學習、聯絡和區別
java Introspector內省和Reflect反射學習、聯絡和區別
一、反射和內省
1、反射: 將
java reflect反射獲取方法變數引數
類的成員包含變數(Field),方法(Method),構造器(Constructor)
類定義
package Reflect;
public class MyTest {
public int a;
public static int b;
public static f
golang通過反射動態呼叫方法
package main
import (
"fmt"
"reflect"
"errors"
)
func Call(m map[string]interface{}, name string, params ...interface{}) ([]reflect.Value, er
golang利用反射設定結構體變數的值
如果需要動態設定struct變數field的情況下, 可以利用reflect來完成.
程式碼如下:
package main
import (
"fmt"
"reflect"
)
// 定義結構
SpringMVC原始碼學習之request處理流程 springMVC原始碼學習地址 springMVC原始碼學習之addFlashAttribute原始碼分析 java reflect反射呼叫方法invoke
目的:為看原始碼提供呼叫地圖,最長呼叫邏輯深度為8層,反正我是springMVC原始碼學習地址看了兩週才理出來的。
1.處理流程(版本為4.3.18)
入口為spring-webmvc-4.3.18.RELEASE.jar中org.springframework.web.servlet.Dispatche
java-reflect反射
概述
JAVA反射機制是在執行狀態中;對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
獲取Class的三種方法
/**
* 獲取Clas
Java reflect 反射學習筆記
clas parameter 告訴 關鍵字 對象 報錯 getclass exc ==
class 類的使用
萬事萬物皆對象 (基本數據類型, 靜態成員不是面向對象), 所以我們創建的每一個類都是對象, 即類本身是java.lang.Class類的實例對象, 但是這些
[Golang語言社群]--提高 golang 的反射效能
golang 的反射很慢。這個和它的 api 設計有關。在 java 裡面,我們一般使用反射都是這樣來弄的。
Field field = clazz.getField("hello");
field.get(obj1);
field.get(obj2);
這個取得的
JAVA 構造器,extends[繼承],implements[實現],Interface[介面],reflect[反射],clone[克隆],final,static,abstract[抽象]
構造器[建構函式]:
在java中如果使用者編寫類的時候沒有提供建構函式,那麼編譯器會自動提供一個預設建構函式.它會把所有的例項欄位設定為預設值:所有的數字變數初始化為0;所有的布林變數設定為false;所有物件變數設定為null;
PS:
只有在類中沒有其它構造器的時
Golang的反射機制(The Laws of Reflection)
Introduction(簡介)
反射機制能夠在陳故鄉執行過程中檢查自身元素的結構,型別;屬於元程式程式設計。但同時也帶來了不少迷惑。
本文我們嘗試通過解釋Go中的反射機制來解釋一些使用細節。每種語言的反射機制都是不同的(有很多語言甚至沒有反射),此文針
Go reflect反射
UNC i++ php get import 返回 field rdquo 通過
reflect包實現了運行時反射,允許程序操作任意類型的對象。典型用法是用靜態類型interface{}保存一個值,通過調用TypeOf獲取其動態類型信息,該函數返回一個Type類型值