前提

Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以直接通过IDE查看对应的源码和进行Debug。

本文主要介绍反射调用的底层实现,当然还没有能力分析JVM的实现,这里只分析到最终Native方法的调用点。底层会依赖到Unsafe类,可以的话可以看下笔者之前写的一篇文章《神奇的魔法类和双刃剑-Unsafe》。

反射调用的底层实现探究

主要考虑下面的情况:

  • 属性操作:java.lang.reflect.Field#set(Object obj, Object value)java.lang.reflect.Field#get(Object obj)
  • 构造器调用:java.lang.reflect.Constructor#newInstance(Object ... initargs)
  • 方法调用:java.lang.reflect.Method#invoke(Object obj, Object... args)

处理属性操作的底层实现

属性操作方法Field#set(Object obj, Object value)Field#get(Object obj)底层都是委托到jdk.internal.reflect.FieldAccessor实现:

  1. public interface FieldAccessor {
  2. /** Matches specification in {@link java.lang.reflect.Field} */
  3. public Object get(Object obj) throws IllegalArgumentException;
  4. /** Matches specification in {@link java.lang.reflect.Field} */
  5. public boolean getBoolean(Object obj) throws IllegalArgumentException;
  6. /** Matches specification in {@link java.lang.reflect.Field} */
  7. public byte getByte(Object obj) throws IllegalArgumentException;
  8. /** Matches specification in {@link java.lang.reflect.Field} */
  9. public char getChar(Object obj) throws IllegalArgumentException;
  10. /** Matches specification in {@link java.lang.reflect.Field} */
  11. public short getShort(Object obj) throws IllegalArgumentException;
  12. /** Matches specification in {@link java.lang.reflect.Field} */
  13. public int getInt(Object obj) throws IllegalArgumentException;
  14. /** Matches specification in {@link java.lang.reflect.Field} */
  15. public long getLong(Object obj) throws IllegalArgumentException;
  16. /** Matches specification in {@link java.lang.reflect.Field} */
  17. public float getFloat(Object obj) throws IllegalArgumentException;
  18. /** Matches specification in {@link java.lang.reflect.Field} */
  19. public double getDouble(Object obj) throws IllegalArgumentException;
  20. /** Matches specification in {@link java.lang.reflect.Field} */
  21. public void set(Object obj, Object value)
  22. throws IllegalArgumentException, IllegalAccessException;
  23. /** Matches specification in {@link java.lang.reflect.Field} */
  24. public void setBoolean(Object obj, boolean z)
  25. throws IllegalArgumentException, IllegalAccessException;
  26. /** Matches specification in {@link java.lang.reflect.Field} */
  27. public void setByte(Object obj, byte b)
  28. throws IllegalArgumentException, IllegalAccessException;
  29. /** Matches specification in {@link java.lang.reflect.Field} */
  30. public void setChar(Object obj, char c)
  31. throws IllegalArgumentException, IllegalAccessException;
  32. /** Matches specification in {@link java.lang.reflect.Field} */
  33. public void setShort(Object obj, short s)
  34. throws IllegalArgumentException, IllegalAccessException;
  35. /** Matches specification in {@link java.lang.reflect.Field} */
  36. public void setInt(Object obj, int i)
  37. throws IllegalArgumentException, IllegalAccessException;
  38. /** Matches specification in {@link java.lang.reflect.Field} */
  39. public void setLong(Object obj, long l)
  40. throws IllegalArgumentException, IllegalAccessException;
  41. /** Matches specification in {@link java.lang.reflect.Field} */
  42. public void setFloat(Object obj, float f)
  43. throws IllegalArgumentException, IllegalAccessException;
  44. /** Matches specification in {@link java.lang.reflect.Field} */
  45. public void setDouble(Object obj, double d)
  46. throws IllegalArgumentException, IllegalAccessException;
  47. }

FieldAccessor接口有很多的实现,FieldAccessor接口实例是通过jdk.internal.reflect.ReflectionFactory这个工厂构造的:

  1. public FieldAccessor newFieldAccessor(Field field, boolean override) {
  2. checkInitted();
  3. Field root = langReflectAccess.getRoot(field);
  4. if (root != null) {
  5. // FieldAccessor will use the root unless the modifiers have
  6. // been overrridden
  7. if (root.getModifiers() == field.getModifiers() || !override) {
  8. field = root;
  9. }
  10. }
  11. return UnsafeFieldAccessorFactory.newFieldAccessor(field, override);
  12. }

最终委托到UnsafeFieldAccessorFactory#newFieldAccessor()

  1. class UnsafeFieldAccessorFactory {
  2. static FieldAccessor newFieldAccessor(Field field, boolean override) {
  3. Class<?> type = field.getType();
  4. boolean isStatic = Modifier.isStatic(field.getModifiers());
  5. boolean isFinal = Modifier.isFinal(field.getModifiers());
  6. boolean isVolatile = Modifier.isVolatile(field.getModifiers());
  7. boolean isQualified = isFinal || isVolatile;
  8. boolean isReadOnly = isFinal && (isStatic || !override);
  9. if (isStatic) {
  10. // This code path does not guarantee that the field's
  11. // declaring class has been initialized, but it must be
  12. // before performing reflective operations.
  13. UnsafeFieldAccessorImpl.unsafe.ensureClassInitialized(field.getDeclaringClass());
  14. if (!isQualified) {
  15. if (type == Boolean.TYPE) {
  16. return new UnsafeStaticBooleanFieldAccessorImpl(field);
  17. } else if (type == Byte.TYPE) {
  18. return new UnsafeStaticByteFieldAccessorImpl(field);
  19. } else if (type == Short.TYPE) {
  20. return new UnsafeStaticShortFieldAccessorImpl(field);
  21. } else if (type == Character.TYPE) {
  22. return new UnsafeStaticCharacterFieldAccessorImpl(field);
  23. } else if (type == Integer.TYPE) {
  24. return new UnsafeStaticIntegerFieldAccessorImpl(field);
  25. } else if (type == Long.TYPE) {
  26. return new UnsafeStaticLongFieldAccessorImpl(field);
  27. } else if (type == Float.TYPE) {
  28. return new UnsafeStaticFloatFieldAccessorImpl(field);
  29. } else if (type == Double.TYPE) {
  30. return new UnsafeStaticDoubleFieldAccessorImpl(field);
  31. } else {
  32. return new UnsafeStaticObjectFieldAccessorImpl(field);
  33. }
  34. } else {
  35. if (type == Boolean.TYPE) {
  36. return new UnsafeQualifiedStaticBooleanFieldAccessorImpl(field, isReadOnly);
  37. } else if (type == Byte.TYPE) {
  38. return new UnsafeQualifiedStaticByteFieldAccessorImpl(field, isReadOnly);
  39. } else if (type == Short.TYPE) {
  40. return new UnsafeQualifiedStaticShortFieldAccessorImpl(field, isReadOnly);
  41. } else if (type == Character.TYPE) {
  42. return new UnsafeQualifiedStaticCharacterFieldAccessorImpl(field, isReadOnly);
  43. } else if (type == Integer.TYPE) {
  44. return new UnsafeQualifiedStaticIntegerFieldAccessorImpl(field, isReadOnly);
  45. } else if (type == Long.TYPE) {
  46. return new UnsafeQualifiedStaticLongFieldAccessorImpl(field, isReadOnly);
  47. } else if (type == Float.TYPE) {
  48. return new UnsafeQualifiedStaticFloatFieldAccessorImpl(field, isReadOnly);
  49. } else if (type == Double.TYPE) {
  50. return new UnsafeQualifiedStaticDoubleFieldAccessorImpl(field, isReadOnly);
  51. } else {
  52. return new UnsafeQualifiedStaticObjectFieldAccessorImpl(field, isReadOnly);
  53. }
  54. }
  55. } else {
  56. if (!isQualified) {
  57. if (type == Boolean.TYPE) {
  58. return new UnsafeBooleanFieldAccessorImpl(field);
  59. } else if (type == Byte.TYPE) {
  60. return new UnsafeByteFieldAccessorImpl(field);
  61. } else if (type == Short.TYPE) {
  62. return new UnsafeShortFieldAccessorImpl(field);
  63. } else if (type == Character.TYPE) {
  64. return new UnsafeCharacterFieldAccessorImpl(field);
  65. } else if (type == Integer.TYPE) {
  66. return new UnsafeIntegerFieldAccessorImpl(field);
  67. } else if (type == Long.TYPE) {
  68. return new UnsafeLongFieldAccessorImpl(field);
  69. } else if (type == Float.TYPE) {
  70. return new UnsafeFloatFieldAccessorImpl(field);
  71. } else if (type == Double.TYPE) {
  72. return new UnsafeDoubleFieldAccessorImpl(field);
  73. } else {
  74. return new UnsafeObjectFieldAccessorImpl(field);
  75. }
  76. } else {
  77. if (type == Boolean.TYPE) {
  78. return new UnsafeQualifiedBooleanFieldAccessorImpl(field, isReadOnly);
  79. } else if (type == Byte.TYPE) {
  80. return new UnsafeQualifiedByteFieldAccessorImpl(field, isReadOnly);
  81. } else if (type == Short.TYPE) {
  82. return new UnsafeQualifiedShortFieldAccessorImpl(field, isReadOnly);
  83. } else if (type == Character.TYPE) {
  84. return new UnsafeQualifiedCharacterFieldAccessorImpl(field, isReadOnly);
  85. } else if (type == Integer.TYPE) {
  86. return new UnsafeQualifiedIntegerFieldAccessorImpl(field, isReadOnly);
  87. } else if (type == Long.TYPE) {
  88. return new UnsafeQualifiedLongFieldAccessorImpl(field, isReadOnly);
  89. } else if (type == Float.TYPE) {
  90. return new UnsafeQualifiedFloatFieldAccessorImpl(field, isReadOnly);
  91. } else if (type == Double.TYPE) {
  92. return new UnsafeQualifiedDoubleFieldAccessorImpl(field, isReadOnly);
  93. } else {
  94. return new UnsafeQualifiedObjectFieldAccessorImpl(field, isReadOnly);
  95. }
  96. }
  97. }
  98. }
  99. }

这里注意一下属性修饰符的判断:

  • isStatic:静态属性,也就是static关键字修饰的属性。
  • isFinal:final关键字修饰的属性。
  • isVolatile:valatile关键字修饰的属性。
  • isQualified:valatile关键字或者final关键字修饰的属性。
  • isReadOnly:是否只读属性,final关键字修饰的属性或者static关键字修饰并且不能覆盖(override = false)的属性。

通过上面修饰符做判断,得到最终的FieldAccessor实现。这里挑一个例子进行分析,例如一个普通非静态没有volatile和final关键字修饰属性最终就会得到UnsafeObjectFieldAccessorImpl的实例:

  1. class UnsafeObjectFieldAccessorImpl extends UnsafeFieldAccessorImpl {
  2. UnsafeObjectFieldAccessorImpl(Field field) {
  3. super(field);
  4. }
  5. public Object get(Object obj) throws IllegalArgumentException {
  6. ensureObj(obj);
  7. return unsafe.getObject(obj, fieldOffset);
  8. }
  9. public void set(Object obj, Object value)
  10. throws IllegalArgumentException, IllegalAccessException{
  11. ensureObj(obj);
  12. if (isFinal) {
  13. throwFinalFieldIllegalAccessException(value);
  14. }
  15. if (value != null) {
  16. if (!field.getType().isAssignableFrom(value.getClass())) {
  17. throwSetIllegalArgumentException(value);
  18. }
  19. }
  20. unsafe.putObject(obj, fieldOffset, value);
  21. }
  22. public boolean getBoolean(Object obj) throws IllegalArgumentException {
  23. throw newGetBooleanIllegalArgumentException();
  24. }
  25. public byte getByte(Object obj) throws IllegalArgumentException {
  26. throw newGetByteIllegalArgumentException();
  27. }
  28. // 省略其他直接抛出异常的方法
  29. }

可见UnsafeObjectFieldAccessorImpl中除了get(Object obj)set(Object obj, Object value)方法,其他方法都是直接抛出IllegalArgumentException。而get(Object obj)set(Object obj, Object value)底层分别依赖于jdk.internal.misc.UnsafeputObject(obj, fieldOffset, value)getObject(obj, fieldOffset)方法。而属性的内存偏移地址是在UnsafeObjectFieldAccessorImpl的父类UnsafeFieldAccessorImpl的构造函数中计算出来的:

  1. abstract class UnsafeFieldAccessorImpl extends FieldAccessorImpl {
  2. static final Unsafe unsafe = Unsafe.getUnsafe();
  3. protected final Field field;
  4. protected final long fieldOffset;
  5. protected final boolean isFinal;
  6. UnsafeFieldAccessorImpl(Field field) {
  7. this.field = field;
  8. if (Modifier.isStatic(field.getModifiers()))
  9. fieldOffset = unsafe.staticFieldOffset(field);
  10. else
  11. fieldOffset = unsafe.objectFieldOffset(field);
  12. isFinal = Modifier.isFinal(field.getModifiers());
  13. }
  14. // 省略其他方法
  15. }

这里可以做个小结,属性反射操作FieldsetXXgetXX方法最终委托到jdk.internal.misc.UnsafeputXXgetXX方法,而属性的内存偏移地址是通过jdk.internal.misc.UnsafestaticFieldBase()staticFieldOffsetobjectFieldOffset几个方法计算的。

处理构造器调用的底层实现

Constructor#newInstance()方法调用依赖到ConstructorAccessor

  1. public T newInstance(Object ... initargs)
  2. throws InstantiationException, IllegalAccessException,
  3. IllegalArgumentException, InvocationTargetException
  4. {
  5. if (!override) {
  6. Class<?> caller = Reflection.getCallerClass();
  7. checkAccess(caller, clazz, clazz, modifiers);
  8. }
  9. if ((clazz.getModifiers() & Modifier.ENUM) != 0)
  10. throw new IllegalArgumentException("Cannot reflectively create enum objects");
  11. ConstructorAccessor ca = constructorAccessor; // read volatile
  12. if (ca == null) {
  13. ca = acquireConstructorAccessor();
  14. }
  15. @SuppressWarnings("unchecked")
  16. T inst = (T) ca.newInstance(initargs);
  17. return inst;
  18. }
  19. // ConstructorAccessor接口
  20. public interface ConstructorAccessor {
  21. /** Matches specification in {@link java.lang.reflect.Constructor} */
  22. public Object newInstance(Object[] args)
  23. throws InstantiationException,
  24. IllegalArgumentException,
  25. InvocationTargetException;
  26. }

而获取ConstructorAccessor实例也是通过反射工厂类ReflectionFactory,具体是ReflectionFactory#newConstructorAccessor

  1. public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {
  2. checkInitted();
  3. Class<?> declaringClass = c.getDeclaringClass();
  4. // 抽象方法会进入此if分支
  5. if (Modifier.isAbstract(declaringClass.getModifiers())) {
  6. return new InstantiationExceptionConstructorAccessorImpl(null);
  7. }
  8. // 宿主类直接是Class类型,则无法实例化
  9. if (declaringClass == Class.class) {
  10. return new InstantiationExceptionConstructorAccessorImpl
  11. ("Can not instantiate java.lang.Class");
  12. }
  13. // use the root Constructor that will not cache caller class
  14. Constructor<?> root = langReflectAccess.getRoot(c);
  15. if (root != null) {
  16. c = root;
  17. }
  18. // 当前声明构造的宿主类是ConstructorAccessorImpl的子类
  19. if (Reflection.isSubclassOf(declaringClass,
  20. ConstructorAccessorImpl.class)) {
  21. return new BootstrapConstructorAccessorImpl(c);
  22. }
  23. //
  24. if (noInflation && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
  25. return new MethodAccessorGenerator().
  26. generateConstructor(c.getDeclaringClass(),
  27. c.getParameterTypes(),
  28. c.getExceptionTypes(),
  29. c.getModifiers());
  30. } else {
  31. NativeConstructorAccessorImpl acc =
  32. new NativeConstructorAccessorImpl(c);
  33. DelegatingConstructorAccessorImpl res =
  34. new DelegatingConstructorAccessorImpl(acc);
  35. acc.setParent(res);
  36. return res;
  37. }
  38. }

可见最终得到的ConstructorAccessor实例为DelegatingConstructorAccessorImpl,而DelegatingConstructorAccessorImpl只是一个委托实现,底层是调用NativeConstructorAccessorImpl

  1. class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
  2. private final Constructor<?> c;
  3. private DelegatingConstructorAccessorImpl parent;
  4. private int numInvocations;
  5. NativeConstructorAccessorImpl(Constructor<?> c) {
  6. this.c = c;
  7. }
  8. public Object newInstance(Object[] args)
  9. throws InstantiationException,
  10. IllegalArgumentException,
  11. InvocationTargetException
  12. {
  13. // We can't inflate a constructor belonging to a vm-anonymous class
  14. // because that kind of class can't be referred to by name, hence can't
  15. // be found from the generated bytecode.
  16. if (++numInvocations > ReflectionFactory.inflationThreshold()
  17. && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
  18. ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
  19. new MethodAccessorGenerator().
  20. generateConstructor(c.getDeclaringClass(),
  21. c.getParameterTypes(),
  22. c.getExceptionTypes(),
  23. c.getModifiers());
  24. parent.setDelegate(acc);
  25. }
  26. return newInstance0(c, args);
  27. }
  28. void setParent(DelegatingConstructorAccessorImpl parent) {
  29. this.parent = parent;
  30. }
  31. // 这个就是最终构造实例化对象的native方法
  32. private static native Object newInstance0(Constructor<?> c, Object[] args)
  33. throws InstantiationException,
  34. IllegalArgumentException,
  35. InvocationTargetException;
  36. }

NativeConstructorAccessorImpl#newInstance0()就是最终构造实例化对象的Native方法。当然有例外的情况,例如非正常调用下,如果构造器的宿主类是一个抽象类,那么最终会返回一个InstantiationExceptionConstructorAccessorImpl实例,里面直接抛出InstantiationException异常。

处理方法调用的底层实现

Method#invoke()调用依赖于MethodAccessor

  1. // MethodAccessor接口
  2. public interface MethodAccessor {
  3. /** Matches specification in {@link java.lang.reflect.Method} */
  4. public Object invoke(Object obj, Object[] args)
  5. throws IllegalArgumentException, InvocationTargetException;
  6. }
  7. public Object invoke(Object obj, Object... args)
  8. throws IllegalAccessException, IllegalArgumentException,
  9. InvocationTargetException{
  10. if (!override) {
  11. Class<?> caller = Reflection.getCallerClass();
  12. checkAccess(caller, clazz,
  13. Modifier.isStatic(modifiers) ? null : obj.getClass(),
  14. modifiers);
  15. }
  16. MethodAccessor ma = methodAccessor; // read volatile
  17. if (ma == null) {
  18. ma = acquireMethodAccessor();
  19. }
  20. return ma.invoke(obj, args);
  21. }

获取MethodAccessor实例的逻辑和前两节类似,是通过ReflectionFactory#newMethodAccessor()

  1. public MethodAccessor newMethodAccessor(Method method) {
  2. checkInitted();
  3. if (Reflection.isCallerSensitive(method)) {
  4. Method altMethod = findMethodForReflection(method);
  5. if (altMethod != null) {
  6. method = altMethod;
  7. }
  8. }
  9. // use the root Method that will not cache caller class
  10. Method root = langReflectAccess.getRoot(method);
  11. if (root != null) {
  12. method = root;
  13. }
  14. if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
  15. return new MethodAccessorGenerator().
  16. generateMethod(method.getDeclaringClass(),
  17. method.getName(),
  18. method.getParameterTypes(),
  19. method.getReturnType(),
  20. method.getExceptionTypes(),
  21. method.getModifiers());
  22. } else {
  23. NativeMethodAccessorImpl acc =
  24. new NativeMethodAccessorImpl(method);
  25. DelegatingMethodAccessorImpl res =
  26. new DelegatingMethodAccessorImpl(acc);
  27. acc.setParent(res);
  28. return res;
  29. }
  30. }

最终会委托到NativeMethodAccessorImpl#invoke(Object obj, Object[] args)

  1. class NativeMethodAccessorImpl extends MethodAccessorImpl {
  2. private final Method method;
  3. private DelegatingMethodAccessorImpl parent;
  4. private int numInvocations;
  5. NativeMethodAccessorImpl(Method method) {
  6. this.method = method;
  7. }
  8. public Object invoke(Object obj, Object[] args)
  9. throws IllegalArgumentException, InvocationTargetException
  10. {
  11. // We can't inflate methods belonging to vm-anonymous classes because
  12. // that kind of class can't be referred to by name, hence can't be
  13. // found from the generated bytecode.
  14. if (++numInvocations > ReflectionFactory.inflationThreshold()
  15. && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
  16. MethodAccessorImpl acc = (MethodAccessorImpl)
  17. new MethodAccessorGenerator().
  18. generateMethod(method.getDeclaringClass(),
  19. method.getName(),
  20. method.getParameterTypes(),
  21. method.getReturnType(),
  22. method.getExceptionTypes(),
  23. method.getModifiers());
  24. parent.setDelegate(acc);
  25. }
  26. return invoke0(method, obj, args);
  27. }
  28. void setParent(DelegatingMethodAccessorImpl parent) {
  29. this.parent = parent;
  30. }
  31. private static native Object invoke0(Method m, Object obj, Object[] args);
  32. }

NativeMethodAccessorImpl#invoke0()就是方法调用的最终调用的Native方法。

小结

学习知识过程总是阶梯式上升的,JDK中的类库设计也类似这样,如果提前熟悉Unsafe类的相关方法,其实反射调用的底层实现也能够相对轻易地理解。属性、构造和方法反射调用底层的实现(只考虑正常调用的情况下)如下:

  • 对于属性(Field):Field#setXX()Field#getXX()分别对应UnsafeputXX()getXX()方法,也就是说完全依赖Unsafe中的Native方法。
  • 对于构造(Constructor):Constructor#newInstance()底层调用NativeConstructorAccessorImpl#newInstance0()
  • 对于方法(Method):Method#invoke()底层调用NativeMethodAccessorImpl#invoke0()

个人博客

(本文完 e-a-20181216 c-1-d)

深入分析Java反射(七)-简述反射调用的底层实现的更多相关文章

  1. 深入分析Java反射(八)-优化反射调用性能

    Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以直接通过IDE查看对应的源码和进行Deb ...

  2. 深入分析Java反射(六)-反射调用异常处理

    前提 Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以直接通过IDE查看对应的源码和进行 ...

  3. Java反射机制demo(七)—反射机制与工厂模式

    Java反射机制demo(七)—反射机制与工厂模式 工厂模式 简介 工厂模式是最常用的实例化对象模式. 工厂模式的主要作用就是使用工厂方法代替new操作. 为什么要使用工厂模式?直接new不好吗? 直 ...

  4. 深入分析Java反射(五)-类实例化和类加载

    前提 其实在前面写过的<深入分析Java反射(一)-核心类库和方法>已经介绍过通过类名或者java.lang.Class实例去实例化一个对象,在<浅析Java中的资源加载>中也 ...

  5. 深入分析Java反射(四)-动态代理

    动态代理的简介 Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分 ...

  6. 反射工具类.提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,被AOP过的真实类等工具函数.java

    import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.ap ...

  7. Java基础:(七)反射

    一.什么是反射 理解反射之前,先要搞懂一件事情,类加载到底是怎么一回事? 类加载相当于Class对象的加载.每个类都有一个Class对象,包含了与类有关的信息.当编译一个新类时,会产生一个同名的.cl ...

  8. Java反射学习-4 - 反射调用方法

    反射调用方法: package cn.tx.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Method ...

  9. 深入分析Java反射(一)-核心类库和方法

    前提 Java反射的API在JavaSE1.7的时候已经基本完善,但是本文编写的时候使用的是Oracle JDK11,因为JDK11对于sun包下的源码也上传了,可以直接通过IDE查看对应的源码和进行 ...

随机推荐

  1. Vulkan Device Memory

    1.通过下面的接口,可以获得显卡支持的所有内存类型: MemoryType的类型如下: 2.引用索引3对内存的描述 我们可以通过调用vkGetPhysicalDeviceMemoryPropertie ...

  2. sqlserver插入图片数据

    -- 插入 insert into [CHOLPOR].[dbo].[t_image](id, name) select '1', BulkColumn from openrowset(bulk N' ...

  3. 026-PHP常用字符串函数(三)

    <?php //颠倒字串 print("abcdefg 颠倒 "); print(strrev("abcdefg")."<hr>&q ...

  4. 黑马oracle_day01:02.oracle的基本操作

    01.oracle体系结构 02.oracle的基本操作 03.oracle的查询 04.oracle对象 05.oracle编程 02.oracle的基本操作 PLSQL中文乱码问题解决1.查看服务 ...

  5. h5页面列表滚动加载数据

    h5列表滚动加载数据很常见,以下分享下今天做的案例: 前言 这个效果实现需要知道三个参数 1. scrollTop -- 滚动条距离顶部的高度 2. scrollHeight -- 当前页面的总高度( ...

  6. IT日常技能:VMware网络配置

    1.0 基本概念 集线器:把一流量为M的端口分为N个端口,每个端口流量为M/N 交换机:把一流量为M的端口分为N个端口,每个端口流量仍为M 路由器:相当于两块网卡,一块连接外网并负责NAT, 另一块负 ...

  7. UVA - 1151 Buy or Build (买还是建)(并查集+二进制枚举子集)

    题意:平面上有n个点(1<=n<=1000),你的任务是让所有n个点连通.可以新建边,费用等于两端点欧几里德距离的平方.也可以购买套餐(套餐中的点全部连通).问最小费用. 分析: 1.先将 ...

  8. UVA - 12716 GCD XOR(GCD等于XOR)(数论)

    题意:输入整数n(1<=n<=30000000),有多少对整数(a, b)满足:1<=b<=a<=n,且gcd(a,b)=a XOR b. 分析:因为c是a的约数,所以枚 ...

  9. Vulkan SDK之 CommandBuff

    Basic Command Buffer Operation 调用指定的api, 驱动将命令放入指定的buff当中. 在其他图形API(dx,or opengl) ,glsetlinewidth驱动会 ...

  10. C语言-字符类型

    C语言-字符类型 char不仅是一种整数,也是一种特殊的类型:字符(character). 常用单引号表示字符的字面量,如'a', '1'. 单引号''也是一个字符,printf和scanf里用的%c ...