RTIT(Run-Time Type Identification)运行时类型识别。在《Thinking in Java》一书第十四章中有提到,其作用是在运行时识别一个对象的类型和类的信息。主要有两种方式:一种是“传统的”RTTI,它假定我们在编译时已经知道了所有的类型;另一种是“反射”机制,它允许我们在运行时发现和使用类的信息。
Class类,Class类也是一个实实在在的类,存在于JDK的java.lang包中。Class类的实例表示java应用运行时的类(class ans enum)或接口(interface and annotation)(每个java类运行时都在JVM里表现为一个class对象,可通过类名.class、类型.getClass()、Class.forName(“类名”)等方法获取class对象)。数组同样也被映射为class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本类型boolean,byte,char,short,int,long,float,double和关键字void同样表现为 class 对象。
/* * Private constructor. Only the Java Virtual Machine creates Class objects. //私有构造器,只有JVM才能调用创建Class对象 * This constructor is not used and prevents the default constructor being * generated. */ privateClass(ClassLoader loader) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader; }
return var5; } else { thrownewClassNotFoundException(var1); } } else { returnsuper.loadClass(var1, var2); } } // java.lang.ClassLoader protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 先获取锁 synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded // 如果已经加载了的话,就不用再加载了 Class<?> c = findLoadedClass(name); if (c == null) { longt0= System.nanoTime(); try { // 双亲委托加载 if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader }
// 父类没有加载到时,再自己加载 if (c == null) { // If still not found, then invoke findClass in order // to find the class. longt1= System.nanoTime(); c = findClass(name);
// this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
// 获取当前类所有的构造方法,通过jvm或者缓存 // Returns an array of "root" constructors. These Constructor // objects must NOT be propagated to the outside world, but must // instead be copied via ReflectionFactory.copyConstructor. private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); Constructor<T>[] res; // 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收 ReflectionData<T> rd = reflectionData(); if (rd != null) { res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; // 存在缓存,则直接返回 if (res != null) return res; } // No cached value available; request value from VM if (isInterface()) { @SuppressWarnings("unchecked") Constructor<T>[] temporaryRes = (Constructor<T>[]) newConstructor<?>[0]; res = temporaryRes; } else { // 使用native方法从jvm获取构造器 res = getDeclaredConstructors0(publicOnly); } if (rd != null) { // 最后,将从jvm中读取的内容,存入缓存 if (publicOnly) { rd.publicConstructors = res; } else { rd.declaredConstructors = res; } } return res; }
// Lazily create and cache ReflectionData private ReflectionData<T> reflectionData() { SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; intclassRedefinedCount=this.classRedefinedCount; ReflectionData<T> rd; if (useCaches && reflectionData != null && (rd = reflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } // else no SoftReference or cleared SoftReference or stale ReflectionData // -> create and replace new instance return newReflectionData(reflectionData, classRedefinedCount); }
// 新创建缓存,保存反射信息 private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) { if (!useCaches) returnnull;
// 使用cas保证更新的线程安全性,所以反射是保证线程安全的 while (true) { ReflectionData<T> rd = newReflectionData<>(classRedefinedCount); // try to CAS it... if (Atomic.casReflectionData(this, oldReflectionData, newSoftReference<>(rd))) { return rd; } // 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了 oldReflectionData = this.reflectionData; classRedefinedCount = this.classRedefinedCount; if (oldReflectionData != null && (rd = oldReflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } } }
for (inti=0; i < a1.length; i++) { if (a1[i] != a2[i]) { returnfalse; } }
returntrue; } // sun.reflect.ReflectionFactory /** Makes a copy of the passed constructor. The returned constructor is a "child" of the passed one; see the comments in Constructor.java for details. */ public <T> Constructor<T> copyConstructor(Constructor<T> arg) { return langReflectAccess().copyConstructor(arg); }
// java.lang.reflect.Constructor, copy 其实就是新new一个 Constructor 出来 Constructor<T> copy() { // This routine enables sharing of ConstructorAccessor objects // among Constructor objects which refer to the same underlying // method in the VM. (All of this contortion is only necessary // because of the "accessibility" bit in AccessibleObject, // which implicitly requires that new java.lang.reflect // objects be fabricated for each reflective call on Class // objects.) if (this.root != null) thrownewIllegalArgumentException("Can not copy a non-root Constructor");
Constructor<T> res = newConstructor<>(clazz, parameterTypes, exceptionTypes, modifiers, slot, signature, annotations, parameterAnnotations); // root 指向当前 constructor res.root = this; // Might as well eagerly propagate this if already present res.constructorAccessor = constructorAccessor; return res; }
// return tmpConstructor.newInstance((Object[])null); // java.lang.reflect.Constructor @CallerSensitive public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } } if ((clazz.getModifiers() & Modifier.ENUM) != 0) thrownewIllegalArgumentException("Cannot reflectively create enum objects"); ConstructorAccessorca= constructorAccessor; // read volatile if (ca == null) { ca = acquireConstructorAccessor(); } @SuppressWarnings("unchecked") Tinst= (T) ca.newInstance(initargs); return inst; } // sun.reflect.DelegatingConstructorAccessorImpl public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException { return delegate.newInstance(args); } // sun.reflect.NativeConstructorAccessorImpl public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException { // We can't inflate a constructor belonging to a vm-anonymous class // because that kind of class can't be referred to by name, hence can't // be found from the generated bytecode. if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) { ConstructorAccessorImplacc= (ConstructorAccessorImpl) newMethodAccessorGenerator(). generateConstructor(c.getDeclaringClass(), c.getParameterTypes(), c.getExceptionTypes(), c.getModifiers()); parent.setDelegate(acc); }
// Returns an array of "root" methods. These Method objects must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyMethod. private Method[] privateGetDeclaredMethods(boolean publicOnly) { checkInitted(); Method[] res; ReflectionData<T> rd = reflectionData(); if (rd != null) { res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; if (res != null) return res; } // No cached value available; request value from VM res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); if (rd != null) { if (publicOnly) { rd.declaredPublicMethods = res; } else { rd.declaredMethods = res; } } return res; }
// probably make the implementation more scalable. private MethodAccessor acquireMethodAccessor() { // First check to see if one has been created yet, and take it // if so MethodAccessortmp=null; if (root != null) tmp = root.getMethodAccessor(); if (tmp != null) { // 存在缓存时,存入 methodAccessor,否则调用 ReflectionFactory 创建新的 MethodAccessor methodAccessor = tmp; } else { // Otherwise fabricate one and propagate it up to the root tmp = reflectionFactory.newMethodAccessor(this); setMethodAccessor(tmp); }
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { // We can't inflate methods belonging to vm-anonymous classes because // that kind of class can't be referred to by name, hence can't be // found from the generated bytecode. if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImplacc= (MethodAccessorImpl) newMethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); }
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { // We can't inflate methods belonging to vm-anonymous classes because // that kind of class can't be referred to by name, hence can't be // found from the generated bytecode. if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImplacc= (MethodAccessorImpl) newMethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); }
// Constant pool entries: // ( * = Boxing information: optional) // (+ = Shared entries provided by AccessorGenerator) // (^ = Only present if generating SerializationConstructorAccessor) // [UTF-8] [This class's name] // [CONSTANT_Class_info] for above // [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}" // [CONSTANT_Class_info] for above // [UTF-8] [Target class's name] // [CONSTANT_Class_info] for above // ^ [UTF-8] [Serialization: Class's name in which to invoke constructor] // ^ [CONSTANT_Class_info] for above // [UTF-8] target method or constructor name // [UTF-8] target method or constructor signature // [CONSTANT_NameAndType_info] for above // [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method // [UTF-8] "invoke" or "newInstance" // [UTF-8] invoke or newInstance descriptor // [UTF-8] descriptor for type of non-primitive parameter 1 // [CONSTANT_Class_info] for type of non-primitive parameter 1 // ... // [UTF-8] descriptor for type of non-primitive parameter n // [CONSTANT_Class_info] for type of non-primitive parameter n // + [UTF-8] "java/lang/Exception" // + [CONSTANT_Class_info] for above // + [UTF-8] "java/lang/ClassCastException" // + [CONSTANT_Class_info] for above // + [UTF-8] "java/lang/NullPointerException" // + [CONSTANT_Class_info] for above // + [UTF-8] "java/lang/IllegalArgumentException" // + [CONSTANT_Class_info] for above // + [UTF-8] "java/lang/InvocationTargetException" // + [CONSTANT_Class_info] for above // + [UTF-8] "<init>" // + [UTF-8] "()V" // + [CONSTANT_NameAndType_info] for above // + [CONSTANT_Methodref_info] for NullPointerException's constructor // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor // + [UTF-8] "(Ljava/lang/String;)V" // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V" // + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String // + [UTF-8] "(Ljava/lang/Throwable;)V" // + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V" // + [CONSTANT_Methodref_info] for InvocationTargetException's constructor // + [CONSTANT_Methodref_info] for "super()" // + [UTF-8] "java/lang/Object" // + [CONSTANT_Class_info] for above // + [UTF-8] "toString" // + [UTF-8] "()Ljava/lang/String;" // + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;" // + [CONSTANT_Methodref_info] for Object's toString method // + [UTF-8] "Code" // + [UTF-8] "Exceptions" // * [UTF-8] "java/lang/Boolean" // * [CONSTANT_Class_info] for above // * [UTF-8] "(Z)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "booleanValue" // * [UTF-8] "()Z" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Byte" // * [CONSTANT_Class_info] for above // * [UTF-8] "(B)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "byteValue" // * [UTF-8] "()B" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Character" // * [CONSTANT_Class_info] for above // * [UTF-8] "(C)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "charValue" // * [UTF-8] "()C" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Double" // * [CONSTANT_Class_info] for above // * [UTF-8] "(D)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "doubleValue" // * [UTF-8] "()D" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Float" // * [CONSTANT_Class_info] for above // * [UTF-8] "(F)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "floatValue" // * [UTF-8] "()F" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Integer" // * [CONSTANT_Class_info] for above // * [UTF-8] "(I)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "intValue" // * [UTF-8] "()I" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Long" // * [CONSTANT_Class_info] for above // * [UTF-8] "(J)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "longValue" // * [UTF-8] "()J" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "java/lang/Short" // * [CONSTANT_Class_info] for above // * [UTF-8] "(S)V" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above // * [UTF-8] "shortValue" // * [UTF-8] "()S" // * [CONSTANT_NameAndType_info] for above // * [CONSTANT_Methodref_info] for above
shortnumCPEntries= NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES; booleanusesPrimitives= usesPrimitiveTypes(); if (usesPrimitives) { numCPEntries += NUM_BOXING_CPOOL_ENTRIES; } if (forSerialization) { numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES; }
// Add in variable-length number of entries to be able to describe // non-primitive parameter types and checked exceptions. numCPEntries += (short) (2 * numNonPrimitiveParameterTypes());
// Output class information for non-primitive parameter types nonPrimitiveParametersBaseIdx = add(asm.cpi(), S2); for (inti=0; i < parameterTypes.length; i++) { Class<?> c = parameterTypes[i]; if (!isPrimitive(c)) { asm.emitConstantPoolUTF8(getClassName(c, false)); asm.emitConstantPoolClass(asm.cpi()); } }
// Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor emitCommonConstantPoolEntries();
// Boxing entries if (usesPrimitives) { emitBoxingContantPoolEntries(); }
// Load class vec.trim(); finalbyte[] bytes = vec.getData(); // Note: the class loader is the only thing that really matters // here -- it's important to get the generated code into the // same namespace as the target class. Since the generated code // is privileged anyway, the protection domain probably doesn't // matter. return AccessController.doPrivileged( newPrivilegedAction<MagicAccessorImpl>() { public MagicAccessorImpl run() { try { return (MagicAccessorImpl) ClassDefiner.defineClass (generatedName, bytes, 0, bytes.length, declaringClass.getClassLoader()).newInstance(); } catch (InstantiationException | IllegalAccessException e) { thrownewInternalError(e); } } }); }