目录
什么是反射(Reflection)
reflection这个英语单词是反射、反省的意思, 在编程语言中
reflection是指在程序执行时取出程序的信息或者改变程序信息
Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime,
without knowing the names of the classes, methods etc. at compile time.
It is also possible to instantiate new objects, invoke methods and get/set field values using reflection.
Objective-C的反射
iOS开发中反射很常用, 以至于很多人都没有感觉到它的存在
reflection & class
获取class信息
NSLog(@"[self class] = %@", [self class]);
BOOL ret = [self isKindOfClass:[ViewController class]];
NSLog(@"ret = %@", ret ? @"YES" : @"NO");
ret = [ViewController isSubclassOfClass:[UIViewController class]];
NSLog(@"ret = %@", ret ? @"YES" : @"NO");
ret = [self isMemberOfClass:[ViewController class]];
NSLog(@"ret = %@", ret ? @"YES" : @"NO");
从className来创建Object
Class viewClass = NSClassFromString(@"UIView");
UIView *subView = [[viewClass alloc] init];
subView.backgroundColor = [UIColor redColor];
subView.frame = CGRectMake(20, 20, 100, 100);
[self.view addSubview:subView];
reflection & property
self.property = @"propertyValue";
unsigned int propertyListCount = 0;
objc_property_t *propertyList = class_copyPropertyList([ViewController class], &propertyListCount);
NSMutableArray *results = [NSMutableArray arrayWithCapacity:propertyListCount];
for (int i = 0; i < propertyListCount; i++) {
const char *property_name = property_getName(propertyList[i]);
NSString *propertyName = [NSString stringWithCString:property_name encoding:NSASCIIStringEncoding];
if (propertyName) {
id propertyValue = [self valueForKey:propertyName];
[results addObject:@{ @"name": propertyName, @"value": propertyValue }];
}
}
NSLog(@"results = %@", results);
reflection & method/protocol
BOOL ret = [self conformsToProtocol:@protocol(UITableViewDelegate)];
NSLog(@"ret = %@", ret ? @"YES" : @"NO");
ret = [self respondsToSelector:@selector(viewDidAppear:)];
NSLog(@"ret = %@", ret ? @"YES" : @"NO");
Objective-C的反射进阶
Java的反射
reflection & class
Class mainActivityClass = MainActivity.class;
Log.d(TAG, "className = " + mainActivityClass.getName());
Log.d(TAG, "className = " + mainActivityClass.getSimpleName());
Log.d(TAG, "modifiers = " + mainActivityClass.getModifiers());
Log.d(TAG, "modifiers = " + Modifier.isPublic(mainActivityClass.getModifiers()));
Log.d(TAG, "package = " + mainActivityClass.getPackage());
Log.d(TAG, "superclass = " + mainActivityClass.getSuperclass().getName());
reflection & property
Class aClass = MyObject.class;
try {
Field field = aClass.getField("someField");
Log.d(TAG, "field = " + field.getName());
MyObject objectInstance = new MyObject();
objectInstance.someField = "321";
Object value = field.get(objectInstance);
Log.d(TAG, "value = " + value);
field.set(objectInstance, "222");
Log.d(TAG, "someField = " + objectInstance.someField);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
reflection & method
Class aClass = MyObject.class;
try {
Method method = aClass.getMethod("doSomething", new Class[]{String.class});
Log.d(TAG, "method = " + method.toString());
MyObject objectInstance = new MyObject();
objectInstance.someField = "123";
method.invoke(objectInstance, "333");
} catch (Exception e) {
Log.d(TAG, e.toString());
}
reflection & annotation
相比Objective-C, Java特有的annotation, 也可以通过reflection来获取
Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
Log.d(TAG, "name = " + myAnnotation.name());
Log.d(TAG, "value = " + myAnnotation.value());
}
}
Java的反射进阶
reflection & proxy
使用反射可以在interface不变的情况下, 在runtime动态地替换interface的实现
而实现这一强大功能的手段就是proxy, proxy模式的定义如下
为其他对象提供一种代理以控制对这个对象的访问
而这种在runtime动态替换interface的实现的proxy就叫做dynamic proxies
dynamic proxies常见的应用场景有
-
Database Connection and Transaction Management
-
Dynamic Mock Objects for Unit Testing
-
Adaptation of DI Container to Custom Factory Interfaces
-
AOP-like Method Interception
reflection & JNI
JNI(Java Native Interface), 它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)
从以下这些常用的API可以看到, JNI是完全依赖于runtime的反射的
jint GetVersion()
jint GetEnv(void** env, jint version)
jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
jint DetachCurrentThread()
jclass (*FindClass)(JNIEnv*, const char*);
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
void (*DeleteLocalRef)(JNIEnv*, jobject);
一些问题
反射的优缺点
反射大大提高了程序的灵活性和扩展性, 降低耦合性, 提高自适应能力, 难道它就没有什么缺点么?
-
性能问题 - 使用反射基本上是一种解释操作, 会有一些性能的降低, 但是现在硬件和优化能力的提高让人逐渐忽略了这点
-
增加复杂性 - 反射的逻辑依赖于runtime, 这一定程度上增加了源代码交流和维护的成本
元编程与反射的关系
什么是元编程(Meta-Programming), Wiki的解释如下
Metaprogramming is the writing of computer programs with the ability to treat programs as their data. It means that a program could be designed to read, generate, analyse or transform other programs, and even modify itself while running.
Reflection is a valuable language feature to facilitate metaprogramming.
对此我的理解和解释是
元编程是目标, 而反射是实现这一目标的重要手段