JAVA反射浅析 怼烎@ 2022-05-20 07:20 146阅读 0赞 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 就是说在运行时,我们可以写一个程序,这个程序能够获取任意一个类的各种信息,对于对象,我们还可以调用它的方法,看起来有点牛逼,上帝之手,不同于通常我们new对象然后调用方法的地方就是这是动态的。 Java提供了一个反射库**java.lang.reflect** ![70][] 还有一个位于java.lang包中的**Class**类,下面解释一下这个类,这个类是反射中不可少的一环。 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。JVM利用运行时类型信息选择相应的方法执行。 而保存这些信息的类就是Class类。 一个Class对象就将表示一个特定类的属性。 那么我们要怎么在程序中**获得某各类的Class对象**呢?Java提供了三种手段。 **①所有类的父类Object类有个getClass()方法** ![70 1][] 源码注释如下 /** * Returns the runtime class of this {@code Object}. The returned * {@code Class} object is the object that is locked by {@code * static synchronized} methods of the represented class. * * <p><b>The actual result type is {@code Class<? extends |X|>} * where {@code |X|} is the erasure of the static type of the * expression on which {@code getClass} is called.</b> For * example, no cast is required in this code fragment:</p> * * <p> * {@code Number n = 0; }<br> * {@code Class<? extends Number> c = n.getClass(); } * </p> * * @return The {@code Class} object that represents the runtime * class of this object. * @jls 15.8.2 Class Literals */ public final native Class<?> getClass(); **②Class类有个重载的静态方法forName(),这里列出最简单的形式** ![70 2][] 也看下源码 /** * Returns the {@code Class} object associated with the class or * interface with the given string name. Invoking this method is * equivalent to: * * <blockquote> * {@code Class.forName(className, true, currentLoader)} * </blockquote> * * where {@code currentLoader} denotes the defining class loader of * the current class. * * <p> For example, the following code fragment returns the * runtime {@code Class} descriptor for the class named * {@code java.lang.Thread}: * * <blockquote> * {@code Class t = Class.forName("java.lang.Thread")} * </blockquote> * <p> * A call to {@code forName("X")} causes the class named * {@code X} to be initialized. * * @param className the fully qualified name of the desired class. * @return the {@code Class} object for the class with the * specified name. * @exception LinkageError if the linkage fails * @exception ExceptionInInitializerError if the initialization provoked * by this method fails * @exception ClassNotFoundException if the class cannot be located */ @CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); } 关键的还是forName0()这个方法 private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class<?> caller) throws ClassNotFoundException; /** * Creates a new instance of the class represented by this {@code Class} * object. The class is instantiated as if by a {@code new} * expression with an empty argument list. The class is initialized if it * has not already been initialized. * * <p>Note that this method propagates any exception thrown by the * nullary constructor, including a checked exception. Use of * this method effectively bypasses the compile-time exception * checking that would otherwise be performed by the compiler. * The {@link * java.lang.reflect.Constructor#newInstance(java.lang.Object...) * Constructor.newInstance} method avoids this problem by wrapping * any exception thrown by the constructor in a (checked) {@link * java.lang.reflect.InvocationTargetException}. * * @return a newly allocated instance of the class represented by this * object. * @throws IllegalAccessException if the class or its nullary * constructor is not accessible. * @throws InstantiationException * if this {@code Class} represents an abstract class, * an interface, an array class, a primitive type, or void; * or if the class has no nullary constructor; * or if the instantiation fails for some other reason. * @throws ExceptionInInitializerError if the initialization * provoked by this method fails. * @throws SecurityException * If a security manager, <i>s</i>, is present and * the caller's class loader is not the same as or an * ancestor of the class loader for the current class and * invocation of {@link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to the package * of this class. */ @CallerSensitive public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); } // NOTE: the following code may not be strictly correct under // the current Java memory model. // Constructor lookup if (cachedConstructor == null) { if (this == Class.class) { throw new IllegalAccessException( "Can not call newInstance() on the Class for java.lang.Class" ); } try { Class<?>[] empty = {}; final Constructor<T> c = getConstructor0(empty, Member.DECLARED); // Disable accessibility checks on the constructor // since we have to do the security check here anyway // (the stack depth is wrong for the Constructor's // security check to work) java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { c.setAccessible(true); return null; } }); cachedConstructor = c; } catch (NoSuchMethodException e) { throw (InstantiationException) new InstantiationException(getName()).initCause(e); } } Constructor<T> tmpConstructor = cachedConstructor; // Security check (same as in java.lang.reflect.Constructor) int modifiers = tmpConstructor.getModifiers(); if (!Reflection.quickCheckMemberAccess(this, modifiers)) { Class<?> caller = Reflection.getCallerClass(); if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; } } // Run constructor try { return tmpConstructor.newInstance((Object[])null); } catch (InvocationTargetException e) { Unsafe.getUnsafe().throwException(e.getTargetException()); // Not reached return null; } } **③如果T是 任意的Java类型(或者void关键字),那么T.class将代表匹配的类对象。** 上面三种方法我做下试验,我们写一个Student类和一个测试的main方法 package dailyprg0714; public class Student { private String name; public Student(String name) { super(); this.name = name; } public void say(){ System.out.println("Hello, I'm "+name+" !"); } } package dailyprg0714; public class Test { public static void main(String[] args) { Student student = new Student("Jenny"); Class class1 = student.getClass(); System.out.println(class1.toString()); try { Class class2 = Class.forName("dailyprg0714.Student"); System.out.println(class2.toString()); } catch (Exception e) { e.printStackTrace(); } Class class3 = Student.class; System.out.println(class3.toString()); } } 我们运行一下, ![70 3][] 三种方法都得到了Class对象。 JVM为每个类型管理一个Class对象,**也只有一个**,我们可以看一下上面获得的三个对象是不是同一个,我们添加两行代码 System.out.println(class1==class2); System.out.println(class1==class3); 结果都为true,也就是说这个对象是唯一的 ![70 4][] 获得了这个对象之后我们就能调用Class类提供的方法来**分析类**了, 在java.lang.reflect包中有三个类**Field**、**Method**和**Constructor**,从名字也能看出来它们分别用于描述类的域、方法和构造器。 而Class类中的getFields、getMethods和getConstructors方法将分别返回类的public域、方法和构造器数组,其中包括超类的公有成员。 另外Class类的getDeclaredFields、getDeclaredMethods和getDeclaredConstructors方法分别返回类中声明的全部域、方法和构造器,包括私有和受保护的,但不包括超类成员。 我们还是拿Student类试验一下,修改下main的代码 package dailyprg0714; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test { public static void main(String[] args) { Student student = new Student("Jenny"); Class class1 = student.getClass(); System.out.println(class1.toString()); try { Class class2 = Class.forName("dailyprg0714.Student"); System.out.println(class2.toString()); System.out.println(class1==class2); } catch (Exception e) { e.printStackTrace(); } Class class3 = Student.class; System.out.println(class3.toString()); System.out.println(class1==class3); System.out.println(); Field[] fields = class1.getDeclaredFields(); Method[] methods = class1.getDeclaredMethods(); Constructor[] constructors = class1.getConstructors(); for(Field field : fields){ System.out.println(field.getName()); } for(Method method : methods){ System.out.println(method.getName()); } for(Constructor constructor : constructors){ System.out.println(constructor.getName()); } } } 看下输出的结果 ![70 5][] 当然还能调用Field、Method和Constructor的其他方法,不止是getName来获得更多的信息,具体的还是看源码或者官方文档哈。只要访问权限允许,我们完全可以**获得一个Student对象的实例域的具体值,甚至可以修改它的值**。对于私有域需要用到 setAccessible方法来设置访问权限。 当然,**我们也可以调用任意一个方法**,这里的关键就是Method类提供的invoke()方法,它允许调用包装在当前Method对象中的方法。invoke的源码 @CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); } 我们也试一下调用student的say方法,在Method遍历的时候加入一段代码,用于执行student这个对象的say方法,如果say是Student类的静态方法那么就不需要传入这个参数了 for(Method method : methods){ System.out.println(method.getName()); try { method.invoke(student); } catch (Exception e) { e.printStackTrace(); } } 我们看下结果 ![70 6][] OK! 反射的更多功能就要去研究反射库了,看下有哪些方法! [70]: /images/20220520/60e9f0d5a8964a2798d0f3f7587b7717.png [70 1]: /images/20220520/c9551720a296412599e1431faa19b530.png [70 2]: /images/20220520/692007df221543c6908097f453c261c9.png [70 3]: /images/20220520/d4630bca82d949d9ac52871bd9b1538d.png [70 4]: /images/20220520/1184574720874faa942b7d42da8c6431.png [70 5]: /images/20220520/9d059ec59062480a9b0f4bdd17daa401.png [70 6]: /images/20220520/3b770b3d9c644e5d839e19afddd415b2.png
相关 Java反射机制浅析与实践案例 Java的反射机制是Java语言强大的特性之一,它允许程序在运行时动态地获取类的信息,并可以操作对象。 以下是反射机制的主要部分和实践案例: 1. 获取类信息: ```ja 约定不等于承诺〃/ 2024年09月16日 06:03/ 0 赞/ 13 阅读
相关 Java反射机制浅析与实例 Java的反射机制是一种强大的工具,它允许我们在运行时检查类、对象以及方法等信息。以下是对Java反射机制的浅析和一些实例: 1. **创建Reflection对象**: 快来打我*/ 2024年09月16日 06:03/ 0 赞/ 9 阅读
相关 Java反射机制浅析与应用示例 Java的反射机制是Java语言强大的特性之一,它允许我们在运行时检查类、接口、方法和字段等信息。 一、浅析 1. 类:通过Class对象可以获取类的所有信息,如构造器、方 你的名字/ 2024年09月15日 23:45/ 0 赞/ 11 阅读
相关 浅析:Java反射机制带来的常见问题 Java的反射机制,使得程序可以在运行时获取类的信息、对象信息以及方法信息等。这在一定程度上提高了代码的灵活性和可维护性。然而,反射机制也可能带来一些常见的问题: 1. 性能 旧城等待,/ 2024年09月10日 09:00/ 0 赞/ 17 阅读
相关 Java反射机制:浅析与常见问题 Java的反射机制是一种强大的工具,它允许我们在运行时检查类、对象、方法等信息。以下是反射机制的浅析和常见问题: 1. **浅析**: - **获取类型信息**:可以使 小灰灰/ 2024年09月05日 19:39/ 0 赞/ 22 阅读
相关 java的反射机制速度很慢_java反射机制Reflection浅析 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的 墨蓝/ 2022年11月07日 14:42/ 0 赞/ 128 阅读
相关 Java反射机制浅析 [Java反射机制浅析 ][Java_] 标签: [ java][java] 2017-08-08 13:16 136人阅读 [评论][Link 墨蓝/ 2022年06月10日 02:51/ 0 赞/ 140 阅读
相关 浅析Java反射 废话不多说,直切进入正题。先来一张反射机制的图--> ![1][] 认识反射 首先反射我们通过“反”来理解,既然有“反”就一定有“正”,在正常情况下,我们 爱被打了一巴掌/ 2022年05月28日 02:14/ 0 赞/ 126 阅读
相关 JAVA反射浅析 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 怼烎@/ 2022年05月20日 07:20/ 0 赞/ 147 阅读
还没有评论,来说两句吧...