我是靠谱客的博主 魁梧银耳汤,最近开发中收集的这篇文章主要介绍JDK源码(十四):Class,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

在日常开发过程中,会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。比如JDBC链接:

Class.forName("com.mysql.cj.jdbc.Driver");

反射机制的相关类

Class代表类的实例,表示正在运行的Java应用程序中的类和接口。Class没有公共构造函数。相反,Class对象由Java虚拟机在加载类时自动构造,并通过调用类加载器中的defineClass方法来构造。

类名

public final class Class<T>
implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement

在Class中有个静态代码块,此native方法表示向JVM注册本地方法。

private static native void registerNatives();
static {
registerNatives();
}

forName(String className)

@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
//返回调用这个方法的类对象
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

返回给定字符串名称的类或接口关联的类对象,@CallerSensitive为了防止通过构造双重反射来提升权限

T newInstance()


@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;
}
}

栗子:

public 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;
}
}

Student student = Student.class.newInstance();

但是在jdk9以上,这个方法被弃用了,而使用下面的方法:

Student student =
Student.class.getDeclaredConstructor().newInstance()

getMethods()


@CallerSensitive
public Method[] getMethods() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyMethods(privateGetPublicMethods());
}

返回一个数组,该数组包含Method对象,这些对象包含该class对象表示的类或接口的所有公共方法,包括由该类或接口声明的方法以及从父类和父接口继承的方法。里面调用了privateGetPublicMethods方法

private 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方法,但不包括继承的方法。


@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() 

@CallerSensitive
public Field[] getFields() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyFields(privateGetPublicFields(null));
}

返回一个包含Field对象的数组,该数组包含Class对象表示的类或接口的所有可访问公共字段。包括父类和父接口的公共字段。调用的privateGetPublicFields方法如下:

private 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对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承字段。


@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)

public 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以'/'开头,则资源的绝对名称是'/'后面的部分。如果名称不是绝对的,则添加包名称前缀,如果名称是绝对的,则删除前导“/”。


InputStream resourceAsStream =
Student.class.getResourceAsStream("application.xml");

更多精彩内容请关注微信公众号:

最后

以上就是魁梧银耳汤为你收集整理的JDK源码(十四):Class的全部内容,希望文章能够帮你解决JDK源码(十四):Class所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部