正常new对象的方式,是由类到对象的形式,类加载-链接-初始化后,对象根据类的模板进行创建。而反射是由对象到模板类的形式,通过对象反向获取Class类信息,然后通过Class模板类获取类中的信息(属性,方法,父类等等Class类信息)。
1.获取String中的Byte数组
String str = "abcdefg";
Class aclass = str.getClass(); //获取类信息
Field value = aclass.getDeclaredField("value"); //获取私有
value.setAccessible(true);
char[] arr = (char[]) value.get(str);
for(char item:arr){
System.out.print(item);
}
获取到String的类信息后,由于内部的value数组是由private修饰的私有属性,所有调用getDeclaredField方法能将类中的所有属性拿到。
获取到Field字段后,这里要对私有属性进行读取(get)或修改(set),需要先调用setAccessible方法传入true表明可访问私有属性。
根据类中字段的名字和修饰符调用Class中相应的方法可获取到类中所有的信息!
2. 浅看下源码
到JVM中继续看:
JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
JVMWrapper("JVM_GetClassDeclaredFields");
JvmtiVMObjectAllocEventCollector oam;
// Exclude primitive types and array types
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(ofClass)) ||
java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass))->oop_is_array()) {
// Return empty array..从class模板中读取Field类返回
oop res = oopFactory::new_objArray(SystemDictionary::reflect_Field_klass(), 0, CHECK_NULL);
return (jobjectArray) JNIHandles::make_local(env, res);
}
再探SystemDictionary::reflect_Field_klass():
do_klass(reflect_Field_klass, java_lang_reflect_Field, Pre )
大致流程为:根据JavaClass对象读取SystemDictionary系统字典中Field的Klass对象,再转为Java的Class对象返回即可。
3.后言
反射的核心-Class对象,作为对象的模版定义存在的对象,编译器限定语法规则:不允许在类外进行变量函数的声明 一切皆类。jvm虚拟机手册提出字节码文件的格式,再由类加载机制通过system Dictionary执行parseClassFile读取字节码文件返回Klass对象,再将其转换为Java的Class对象进行返回,经过初始化后一个Class对象就创建完了,运行时以Class对象为模版new对象,这就是java的一切皆对象 连java的lambda表达式走的都是内部类。