JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
在日常开发过程中,会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。比如JDBC链接:
1Class.forName("com.mysql.cj.jdbc.Driver");
反射机制的相关类
Class代表类的实例,表示正在运行的Java应用程序中的类和接口。Class没有公共构造函数。相反,Class对象由Java虚拟机在加载类时自动构造,并通过调用类加载器中的defineClass方法来构造。
类名
1
2
3
4
5public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement
在Class中有个静态代码块,此native方法表示向JVM注册本地方法。
1
2
3
4private static native void registerNatives(); static { registerNatives(); }
forName(String className)
1
2
3
4
5
6
7@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { //返回调用这个方法的类对象 Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
返回给定字符串名称的类或接口关联的类对象,@CallerSensitive为了防止通过构造双重反射来提升权限。
T newInstance()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54@CallerSensitive public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { //检查是否允许访问成员。如果拒绝访问,则抛出SecurityException checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); } // 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 = {}; //先获得Constructor数组,拿到所有的构造,包括非public的 final Constructor<T> c = getConstructor0(empty, Member.DECLARED); // 禁用构造函数的可访问性检查 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; int modifiers = tmpConstructor.getModifiers(); //检查是否是public,如果是public,返回true 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; } }
栗子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class Student implements Serializable { private static final long serialVersionUID = -1L; private String id; private String name; public Integer age; public Student(){} public Student(String id, String name) { this.id = id; this.name = name; } private int sum(int i, int j){ return i + j; } public Student getStudent(int id){ return this; } public Student getStudent(String name){ return new Student(); } public String getInfo(){ return id + " " + name; } }
1
2Student student = Student.class.newInstance();
但是在jdk9以上,这个方法被弃用了,而使用下面的方法:
1
2Student student = Student.class.getDeclaredConstructor().newInstance()
getMethods()
1
2
3
4
5
6@CallerSensitive public Method[] getMethods() throws SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyMethods(privateGetPublicMethods()); }
返回一个数组,该数组包含Method对象,这些对象包含该class对象表示的类或接口的所有公共方法,包括由该类或接口声明的方法以及从父类和父接口继承的方法。里面调用了privateGetPublicMethods方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53private Method[] privateGetPublicMethods() { checkInitted(); Method[] res; ReflectionData<T> rd = reflectionData(); if (rd != null) { res = rd.publicMethods; if (res != null) return res; } //没有可用的缓存值;递归计算值。从获取公共声明的方法开始 MethodArray methods = new MethodArray(); { Method[] tmp = privateGetDeclaredMethods(true); methods.addAll(tmp); } // 首先检查父接口,这样我们可以更容易地过滤掉最后从父类继承的具体实现。 MethodArray inheritedMethods = new MethodArray(); for (Class<?> i : getInterfaces()) { inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods()); } if (!isInterface()) { //如果不是接口 Class<?> c = getSuperclass();//得到父类 if (c != null) { MethodArray supers = new MethodArray(); //父类中的public方法 supers.addAll(c.privateGetPublicMethods()); // 过滤掉任何接口方法的具体实现 for (int i = 0; i < supers.length(); i++) { Method m = supers.get(i); if (m != null && !Modifier.isAbstract(m.getModifiers()) && !m.isDefault()) { inheritedMethods.removeByNameAndDescriptor(m); } } // 在父接口之前插入父类的继承方法以满足getMethod的搜索顺序 supers.addAll(inheritedMethods); inheritedMethods = supers; } } // 从继承的方法中筛选出所有本地方法 for (int i = 0; i < methods.length(); i++) { Method m = methods.get(i); inheritedMethods.removeByNameAndDescriptor(m); } methods.addAllIfNotPresent(inheritedMethods); methods.removeLessSpecifics(); methods.compactAndTrim(); res = methods.getArray(); if (rd != null) { rd.publicMethods = res; } return res; }
与getMethods()方法对应的还有一个getDeclaredMethods(),这个方法返回一个Method对象数组,其中包含该Class对象表示的类或接口的所有已声明方法,包括public、protected、default(package)访问和private方法,但不包括继承的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25@CallerSensitive public Method[] getDeclaredMethods() throws SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyMethods(privateGetDeclaredMethods(false)); } 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; } //getDeclaredMethods0底层方法获取本类方法 res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); if (rd != null) { if (publicOnly) { rd.declaredPublicMethods = res; } else { rd.declaredMethods = res; } } return res; }
getFields()
1
2
3
4
5@CallerSensitive public Field[] getFields() throws SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); return copyFields(privateGetPublicFields(null)); }
返回一个包含Field对象的数组,该数组包含Class对象表示的类或接口的所有可访问公共字段。包括父类和父接口的公共字段。调用的privateGetPublicFields方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) { checkInitted(); Field[] res; ReflectionData<T> rd = reflectionData(); if (rd != null) { res = rd.publicFields; if (res != null) return res; } List<Field> fields = new ArrayList<>(); if (traversedInterfaces == null) { traversedInterfaces = new HashSet<>(); } // 类本身的字段 Field[] tmp = privateGetDeclaredFields(true); addAll(fields, tmp); // 遍历父接口 for (Class<?> c : getInterfaces()) { if (!traversedInterfaces.contains(c)) { traversedInterfaces.add(c); addAll(fields, c.privateGetPublicFields(traversedInterfaces)); } } // 父类 if (!isInterface()) { Class<?> c = getSuperclass(); if (c != null) { addAll(fields, c.privateGetPublicFields(traversedInterfaces)); } } res = new Field[fields.size()]; fields.toArray(res); if (rd != null) { rd.publicFields = res; } return res; }
getFields()也有一个对应的方法getDeclaredFields(),这个方法返回Field对象的数组,该数组包含该Class对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承字段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25@CallerSensitive public Field[] getDeclaredFields() throws SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); return copyFields(privateGetDeclaredFields(false)); } private Field[] privateGetDeclaredFields(boolean publicOnly) { checkInitted(); Field[] res; ReflectionData<T> rd = reflectionData(); if (rd != null) { res = publicOnly ? rd.declaredPublicFields : rd.declaredFields; if (res != null) return res; } // 调用底层方法 res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); if (rd != null) { if (publicOnly) { rd.declaredPublicFields = res; } else { rd.declaredFields = res; } } return res; }
getResourceAsStream(String name)
1
2
3
4
5
6
7
8
9
10public InputStream getResourceAsStream(String name) { //如果名称不是绝对的,则添加包名称前缀如果名称是绝对的,则删除前导“/” name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResourceAsStream(name); } return cl.getResourceAsStream(name); }
此方法查找具有给定名称的资源。搜索与给定类关联的资源的规则是通过定义类的ClassLoader来实现的。此方法委托给此对象的类加载器。如果此对象是由引导类加载器加载的,则方法将委托给getSystemResourceAsStream。如果name以'/'开头,则资源的绝对名称是'/'后面的部分。如果名称不是绝对的,则添加包名称前缀,如果名称是绝对的,则删除前导“/”。
1
2
3InputStream resourceAsStream = Student.class.getResourceAsStream("application.xml");
更多精彩内容请关注微信公众号:
最后
以上就是魁梧银耳汤最近收集整理的关于JDK源码(十四):Class的全部内容,更多相关JDK源码(十四)内容请搜索靠谱客的其他文章。
发表评论 取消回复