java中的api有源码_Java 反射源码(基于API 29 JDK8)

反射原理

先看一段java反射使用的代码:

public class RefTest {

@Test

public void main() {

try {

// 加载class对象

Class clazz = Class.forName("cn.com.rabi.demotest.bean.Student");

// 获取所有公开构造函数

Constructor[] constructors = clazz.getConstructors();

for (Constructor constructor : constructors) {

System.out.println("1:"+constructor);

}

// 获取所有构造函数

constructors = clazz.getDeclaredConstructors();

for (Constructor constructor : constructors) {

System.out.println("2:"+constructor);

}

System.out.println("----------------------------------------------------------------");

// 调用protected构造

Constructor con = clazz.getDeclaredConstructor(String.class);

con.setAccessible(true);

Object o = con.newInstance("rabi");

// 调用private构造

con = clazz.getDeclaredConstructor(int.class);

con.setAccessible(true);

o = con.newInstance(11);

// 调用公有无参构造

con = clazz.getConstructor(null);

o = con.newInstance();

System.out.println("----------------------------------------------------------------");

// 获取所有公有字段

Field[] fields = clazz.getFields();

for (Field field : fields) {

System.out.println("3:"+field);

}

// 获取所有字段

fields = clazz.getDeclaredFields();

for (Field field : fields) {

System.out.println("4:"+field);

}

System.out.println("----------------------------------------------------------------");

// 获取公有字段并赋值

Field field = clazz.getField("name");

field.set(o,"mavis");

// 获取私有字段并赋值

field = clazz.getDeclaredField("age");

field.setAccessible(true);

field.set(o,11);

// 输出当前状态

Student student = (Student) o;

System.out.println(student.getName()+":"+student.getAge());

System.out.println("----------------------------------------------------------------");

// 获取所有公有方法

Method[] methods = clazz.getMethods();

for (Method method : methods) {

System.out.println("5:"+method);

}

// 获取所有方法

methods = clazz.getDeclaredMethods();

for (Method method : methods) {

System.out.println("6:"+method);

}

System.out.println("----------------------------------------------------------------");

// 获取公有方法调用

Method method = clazz.getMethod("setName", String.class);

method.invoke(o,"rabi");

System.out.println(student.getName()+":"+student.getAge());

// 获取私有方法并调用

method = clazz.getDeclaredMethod("setAge", int.class);

method.setAccessible(true);

method.invoke(o,17);

System.out.println(student.getName()+":"+student.getAge());

// 调用protected方法

method = clazz.getDeclaredMethod("getInfo");

method.setAccessible(true);

method.invoke(o);

System.out.println("----------------------------------------------------------------");

} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchFieldException e) {

e.printStackTrace();

}

}

}

// 新建一个Student类

public class Student {

public String name;

private int age;

public Student() {

System.out.println("Student()");

}

private Student(int age) {

this.age = age;

System.out.println("Student(int age)");

}

protected Student(String name) {

this.name = name;

System.out.println("Student(int name)");

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

private void setAge(int age) {

this.age = age;

}

protected void getInfo() {

System.out.println(name+":"+age);

}

}

上面这段代码的测试结果如下:

1:public cn.com.rabi.demotest.bean.Student()

2:public cn.com.rabi.demotest.bean.Student()

2:private cn.com.rabi.demotest.bean.Student(int)

2:protected cn.com.rabi.demotest.bean.Student(java.lang.String)

----------------------------------------------------------------

Student(int name)

Student(int age)

Student()

----------------------------------------------------------------

3:public java.lang.String cn.com.rabi.demotest.bean.Student.name

4:public java.lang.String cn.com.rabi.demotest.bean.Student.name

4:private int cn.com.rabi.demotest.bean.Student.age

----------------------------------------------------------------

mavis:11

----------------------------------------------------------------

5:public int cn.com.rabi.demotest.bean.Student.getAge()

5:public java.lang.String cn.com.rabi.demotest.bean.Student.getName()

5:public void cn.com.rabi.demotest.bean.Student.setName(java.lang.String)

5:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

5:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

5:public final void java.lang.Object.wait() throws java.lang.InterruptedException

5:public boolean java.lang.Object.equals(java.lang.Object)

5:public java.lang.String java.lang.Object.toString()

5:public native int java.lang.Object.hashCode()

5:public final native java.lang.Class java.lang.Object.getClass()

5:public final native void java.lang.Object.notify()

5:public final native void java.lang.Object.notifyAll()

6:private void cn.com.rabi.demotest.bean.Student.setAge(int)

6:protected void cn.com.rabi.demotest.bean.Student.getInfo()

6:public int cn.com.rabi.demotest.bean.Student.getAge()

6:public java.lang.String cn.com.rabi.demotest.bean.Student.getName()

6:public void cn.com.rabi.demotest.bean.Student.setName(java.lang.String)

----------------------------------------------------------------

rabi:11

rabi:17

rabi:17

----------------------------------------------------------------

这里我们取其中调用调用公有的空构造方法,然后调用公有的setName方法进行分析。

首先是获取class,查看源码:

public static Class> forName(String className)

throws ClassNotFoundException {

Class> caller = Reflection.getCallerClass();

return forName(className, true, ClassLoader.getClassLoader(caller));

}

public static Class> forName(String name, boolean initialize,

ClassLoader loader)

throws ClassNotFoundException

{

if (loader == null) {

loader = BootClassLoader.getInstance();

}

Class> result;

try {

result = classForName(name, initialize, loader);

} catch (ClassNotFoundException e) {

Throwable cause = e.getCause();

if (cause instanceof LinkageError) {

throw (LinkageError) cause;

}

throw e;

}

return result;

}

可以看到这里是调用的ClassLoader获取了class对象并返回,然后获取公有无参构造函数,查看源码:

public Constructor getConstructor(Class>... parameterTypes)

throws NoSuchMethodException, SecurityException {

return getConstructor0(parameterTypes, Member.PUBLIC);

}

private Constructor getConstructor0(Class>[] parameterTypes,

int which) throws NoSuchMethodException

{

// 这里我们传入的参数是null

if (parameterTypes == null) {

parameterTypes = EmptyArray.CLASS;

}

for (Class> c : parameterTypes) {

if (c == null) {

throw new NoSuchMethodException("parameter type is null");

}

}

Constructor result = getDeclaredConstructorInternal(parameterTypes);

if (result == null || which == Member.PUBLIC && !Modifier.isPublic(result.getAccessFlags())) {

throw new NoSuchMethodException(getName() + ". "

+ Arrays.toString(parameterTypes));

}

return result;

}

这里的getDeclaredConstructorInternal是native方法,返回Constructor对象,查看其newInstance方法:

public T newInstance(Object ... initargs)

throws InstantiationException, IllegalAccessException,

IllegalArgumentException, InvocationTargetException

{

if (serializationClass == null) {

return newInstance0(initargs);

} else {

return (T) newInstanceFromSerialization(serializationCtor, serializationClass);

}

}

这里也是调用的native方法,返回了T对象,其中serializationClass!=null的情况会有一次类型转换。接着往下看,获取公有方法的getMethod函数和获取所有方法的getDeclaredMethods函数:

@CallerSensitive

public Method getMethod(String name, Class>... parameterTypes)

throws NoSuchMethodException, SecurityException {

return getMethod(name, parameterTypes, true);

}

public Method getDeclaredMethod(String name, Class>... parameterTypes)

throws NoSuchMethodException, SecurityException {

return getMethod(name, parameterTypes, false);

}

private Method getMethod(String name, Class>[] parameterTypes, boolean recursivePublicMethods)

throws NoSuchMethodException {

// 方法名不能为空

if (name == null) {

throw new NullPointerException("name == null");

}

// 如果没有参数

if (parameterTypes == null) {

parameterTypes = EmptyArray.CLASS;

}

// 检查参数对象中是否有null

for (Class> c : parameterTypes) {

if (c == null) {

throw new NoSuchMethodException("parameter type is null");

}

}

// 获取公有方法的时候这里为true

// getPublicMethodRecursive是一个native方法,最终返回一个method对象

Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)

: getDeclaredMethodInternal(name, parameterTypes);

// Fail if we didn't find the method or it was expected to be public.

// 检查public

if (result == null ||

(recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {

throw new NoSuchMethodException(getName() + "." + name + " "

+ Arrays.toString(parameterTypes));

}

return result;

}

private Method getPublicMethodRecursive(String name, Class>[] parameterTypes) {

// 遍历继承类

for (Class> c = this; c != null; c = c.getSuperclass()) {

// 找到该方法

Method result = c.getDeclaredMethodInternal(name, parameterTypes);

// 判断该方法是否是公有的

if (result != null && Modifier.isPublic(result.getAccessFlags())) {

return result;

}

}

return findInterfaceMethod(name, parameterTypes);

}

可以看到两个方法的区别就是传入getMethod的第三个参数true/false,之后返回一个Method对象,查看invoke方法:

public native Object invoke(Object obj, Object... args)

throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;

这里返回的也是一个Object对象。感觉jdk8和jdk12在这部分的差异挺大的,具体相信部分可以参考末尾的《大家都说 Java 反射效率低,你知道原因在哪里么》一文。

分析源码之后,我们这里也回答一下为什么反射效率低:

1.校验参数,当传递参数类的时候,需要校验参数类型。

2.方法查找,无论是公有还是私有,都是遍历的操作。

3.类型转换,参数以class>传入的,返回值是object的时候需要转换为T。

感觉意犹未尽,待续。

参考文献

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值