都说c#和java差不多,会了java,c#基本都会了。我对java还是很熟的,对oc也比较熟,但是c#感觉还是过一遍比较好。最近看到了c#的反射,这里呢就对反射在各个语言中的体现横向比较一下。
反射,让程序员能够根据一个字符串去:
- 实例化对象
- 调用想要的方法
- 遍历类中或者对象中的属性或者属性值。
意思就是能够动态调用。这样会有非常非常大的好处,以及便捷性。反射这一套东西在开发业务中不是必须的,但是如果你想让你的代码有:
- 更好的组织性
- 更松的耦合性
- 更强的复用性
反射必须掌握。而且语言之间都是相通的。如果你是一个想偷懒的程序员,一定要掌握反射。
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就比较灵活一点
//第一种方式:这种方式有一定的不安全性,特别是当类名从用户那边获取的时候
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.如何通过一个字符串调用某个对象的某个方法
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);
//静态函数公有
p.GetType().GetMethod("getaaa").Invoke(null,null)
//非静态私有
var methodInfo2 = p.GetType().GetMethod("getaaa",BindingFlags.NonPublic | BindingFlags.Instance);
var result = methodInfo2.Invoke(p, null);
//静态私有
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中反射静态方法和调用普通的公有私有方法无太大区别
//只是忽略了invoke中的对象参数
//getDeclaredMethod方法可以获取当前类的所有方法
//但是不包含继承的方法,如果想获取继承的方法,可以通过getSuperclass向上寻找。
//getMethod方法只会获取public类型的
oc
//方式1:这种方式,最多支持2个参数
NSString *number = [obj performSelector:NSSelectorFromString(@"getNumber") withObject:nil withObject:nil];
//方式2
//支持多参
//导入#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文件中有没有声明都能被调用到
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");
//私有静态
p.GetType().GetField("number",BindingFlags.NonPublic|BindingFlags.Static).SetValue(p,"123456");
Java
Field field = Person.class.getDeclaredField("name");
field.setAccessible(true); //是否设置强制访问私有
field.set(p, "aaaa"); //设置字段值
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
(构造器信息): 通过GetConstructors
或者GetConstructor
方法。 -
获取某个类的
EventInfo
(类中的事件信息):通过GetEvents
或者GetEvent
方法。 -
获取某个类的
PropertyInfo
(类中的属性信息):通过GetProperties
或者GetProperty
方法。 -
如何加载程序集
Assembly.Load("相对路径");
Assembly.LoadFrom("完整路径"); -
如何取得程序集中所有的Type
Type[] types = Assembly.Load("aaa").GetTypes();
Java中也有类似的反射方法,以获取构造器,等类中的一些定义属性。
OC 是动态语言就反射来说效率会高于静态语言java和c#。
Javascript总的来说是最灵活的。
反射还有很多,这里就不一一赘述,总的来说使用率比较高的就是我介绍的这几个。当然实际肯定还有各种各样的需求,慢慢查api吧,总结是总结不完的,这里只是把常用的列出来。
PS:写代码这么久了,还没有像样的博客,之前建了三次,忘了三次都被阿里云最后回收了。这次换社区试试,希望能坚持下去。会把以前的笔记,经验,还有工作中的一些问题,总结一下,慢慢的放到博客上。
网友评论