都說c#和java差不多即硼,會了java逃片,c#基本都會了。我對java還是很熟的只酥,對oc也比較熟褥实,但是c#感覺還是過一遍比較好。最近看到了c#的反射裂允,這里呢就對反射在各個語言中的體現(xiàn)橫向比較一下损离。
反射,讓程序員能夠根據(jù)一個字符串去:
- 實例化對象
- 調(diào)用想要的方法
- 遍歷類中或者對象中的屬性或者屬性值绝编。
意思就是能夠動態(tài)調(diào)用草冈。這樣會有非常非常大的好處,以及便捷性瓮增。反射這一套東西在開發(fā)業(yè)務(wù)中不是必須的怎棱,但是如果你想讓你的代碼有:
- 更好的組織性
- 更松的耦合性
- 更強的復(fù)用性
反射必須掌握。而且語言之間都是相通的绷跑。如果你是一個想偷懶的程序員拳恋,一定要掌握反射。
1.如何從一個字符串實例化一個類
c#
Type type = Type.GetType("Person",true);
Person p = (Person)System.Activator.CreateInstance(type);
java
Object o = Class.forName("com.company.Main").newInstance();
oc
Class class = NSClassFromString(@"YXTestObject");
YXTestObject *obj= [[class alloc] init];
或者
Class class = objc_getClass("YXTestObject");
YXTestObject *obj= [[class alloc] init];
js
//js就比較靈活一點
//第一種方式:這種方式有一定的不安全性砸捏,特別是當(dāng)類名從用戶那邊獲取的時候
var myStr = "Product"
var p = eval("new " + myStr + "()");
//第二種:將類定義在一個域中
var mynamespace = {};
mynamespace.Person = function Person() {..}
var p = new mynamespace["Person"]();
//如果直接定義在全局域可以這樣:
var p = new window["Person"]();
2.如何通過一個字符串調(diào)用某個對象的某個方法
c#
Person p = new Person();
//有參公有
var methodInfo = p.GetType().GetMethod("set_Name");
methodInfo.Invoke(p, new string[] {"aaa"});
//無參公有
var methodInfo2 = p.GetType().GetMethod("get_Name");
var name = methodInfo2.Invoke(p, null);
//靜態(tài)函數(shù)公有
p.GetType().GetMethod("getaaa").Invoke(null,null)
//非靜態(tài)私有
var methodInfo2 = p.GetType().GetMethod("getaaa",BindingFlags.NonPublic | BindingFlags.Instance);
var result = methodInfo2.Invoke(p, null);
//靜態(tài)私有
var methodInfo2 = p.GetType().GetMethod("getaaa",BindingFlags.NonPublic | BindingFlags.Static);
var name = methodInfo2.Invoke(p, null);
java
//公有
Person p =(Person) Class.forName("com.company.Person").newInstance();
String number = (String)Person.class.getMethod("getNumber", null).invoke(p,null);
//私有
Person p =(Person) Class.forName("com.company.Person").newInstance();
Method method = Person.class.getDeclaredMethod("getNumber", null);
method.setAccessible(true);
String number=(String)method .invoke(p,null);
//Java中反射靜態(tài)方法和調(diào)用普通的公有私有方法無太大區(qū)別
//只是忽略了invoke中的對象參數(shù)
//getDeclaredMethod方法可以獲取當(dāng)前類的所有方法
//但是不包含繼承的方法谬运,如果想獲取繼承的方法,可以通過getSuperclass向上尋找垦藏。
//getMethod方法只會獲取public類型的
oc
//方式1:這種方式梆暖,最多支持2個參數(shù)
NSString *number = [obj performSelector:NSSelectorFromString(@"getNumber") withObject:nil withObject:nil];
//方式2
//支持多參
//導(dǎo)入#import <objc/message.h>
//Build Setting--> Apple LLVM 6.0 - Preprocessing--> Enable Strict Checking of objc_msgSend Calls 改為 NO
//否則會報Too many arguments to function call ,expected 0,have3
NSString *number2 = objc_msgSend(obj,NSSelectorFromString(@"getNumber"),nil);
//類方法
NSString *number2 = objc_msgSend(class,NSSelectorFromString(@"getNumber"),nil);
//NSSelectorFromString(@"getNumber")等價于sel_registerName("getNumber")
//上面的幾種方式不管在h文件中有沒有聲明都能被調(diào)用到
js
//js就非常簡單了
var p = new Person();
var number = p["getNumber"]();
3.通過屬性名稱字符串獲取某個對象的字段值
c#
//公有
p.GetType().GetField("number").SetValue(p,"123456");
//私有
p.GetType().GetField("number",BindingFlags.NonPublic|BindingFlags.Instance).SetValue(p,"123456");
//私有靜態(tài)
p.GetType().GetField("number",BindingFlags.NonPublic|BindingFlags.Static).SetValue(p,"123456");
Java
Field field = Person.class.getDeclaredField("name");
field.setAccessible(true); //是否設(shè)置強制訪問私有
field.set(p, "aaaa"); //設(shè)置字段值
String name = (String)field.get(p); //獲取字段值
oc
//可以通過kvc的方式,成員變量不管被聲明在m文件還是h文件
//不管是私有還是公有都能通過這種方式被訪問到
YXTestObject *obj= [[class alloc] init];
[obj setValue:@"男" forKey:@"sex"];
NSLog(@"%@",[obj valueForKey:@"sex"]);
js
js依然是最簡單的
var p = new Person();
p["number"]="123456";
var number= p["number"];
4.遍歷某個對象的字段以及字段值
c#
public class Test {
public static void reflect(Object o){
PropertyInfo[] propertys = o.GetType().GetProperties();
foreach (PropertyInfo pinfo in propertys)
{
Console.WriteLine(pinfo.Name+","+pinfo.GetValue(o,null));
}
}
static void Main(string[] args){
Person p = new Person();
reflect(p);
}
}
java
public class Test {
public static void reflect(Object o) throws Exception{
Class cls = o.getClass();
Field[] fields = cls.getDeclaredFields();
for(int i=0; i<fields.length; i++){
Field f = fields[i];
f.setAccessible(true);
System.out.println("屬性名:" + f.getName() + " 屬性值:" + f.get(o));
}
}
public static void main(String[] args) throws Exception{
Person p = new Person();
reflect(p);
}
}
oc
+(NSString*)reflectWithObj:(id)obj
{
NSString *name = nil;
NSString *value =nil;
uint32_t ivarCount;
Ivar *ivars = class_copyIvarList([obj class], &ivarCount);
if(ivars)
{
for(uint32_t i=0; i<ivarCount; i++)
{
Ivar ivar = ivars[i];
name = [NSString stringWithUTF8String:ivar_getName(ivar)];
value=[obj valueForKey:name];
NSLog(@"name=%@,value=%@",name,value==nil?@"nil":value);
}
free(ivars);
}
return name;
}
Js
function allPrpos ( obj ) {
var props = "" ;
for ( var p in obj ){
if ( typeof ( obj [ p ]) == " function " ){
obj [p]() ;
} else {
props += p + " = " + obj [ p ] + " \t " ;
}
}
console.log( props ) ;
}
c#中類似的還有
獲取某個類的
ConstructorInfo
(構(gòu)造器信息): 通過GetConstructors
或者GetConstructor
方法掂骏。獲取某個類的
EventInfo
(類中的事件信息):通過GetEvents
或者GetEvent
方法轰驳。獲取某個類的
PropertyInfo
(類中的屬性信息):通過GetProperties
或者GetProperty
方法。-
如何加載程序集
Assembly.Load("相對路徑");
Assembly.LoadFrom("完整路徑"); -
如何取得程序集中所有的Type
Type[] types = Assembly.Load("aaa").GetTypes();
Java中也有類似的反射方法弟灼,以獲取構(gòu)造器级解,等類中的一些定義屬性。
OC 是動態(tài)語言就反射來說效率會高于靜態(tài)語言java和c#田绑。
Javascript總的來說是最靈活的勤哗。
反射還有很多,這里就不一一贅述掩驱,總的來說使用率比較高的就是我介紹的這幾個芒划。當(dāng)然實際肯定還有各種各樣的需求,慢慢查api吧欧穴,總結(jié)是總結(jié)不完的民逼,這里只是把常用的列出來。
PS:寫代碼這么久了苔可,還沒有像樣的博客缴挖,之前建了三次,忘了三次都被阿里云最后回收了焚辅。這次換社區(qū)試試映屋,希望能堅持下去。會把以前的筆記同蜻,經(jīng)驗棚点,還有工作中的一些問題,總結(jié)一下湾蔓,慢慢的放到博客上瘫析。