java反射路径_java反射

java反射是指是在运行状态中,对于任意一个类都可以通过它的Class字节码文件得到对应的的Class类型的对象,从而获取到该类的所有内容,包括所有的属性与方法。当然也可以调用到它的所有内容。

那么这个字节码文件是怎么来的呢?我们在对java文件进行编译时会执行javac XXX.java,这个时候就会产生一个xxx.class文件,此即对应的字节码文件。

是如何通过Class字节码文件得到对应的的Class类型的对象的呢?类加载器。

类加载器是什么呢?

类加载器负责将class文件加载到内存中,并为之生成对应的Class对象。在java中类加载器把一个类装入JVM,需要以下几个步骤:

1.装载:查找和导入Class文件

2.链接:执行校验、准备、解析步骤,其中解析步骤是可以选择的:

a)校验:是否有正确的内部结构,并和其他类协调一致

b)准备:负责为类的静态成员分配内存,并设置默认初始化值

c)解析:将类的二进制数据中的符号引用替换为直接引用

3.初始化:对类的静态变量、静态代码执行初始化工作

类加载器的组成:

bootstrap ClassLoader 根类加载器 (负责将存话在\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如rt.jar,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存了中。开发者不能直接引用启动类加载器)

extension ClassLoader 扩展类加载器(这个加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器)

Application ClassLoader 应用程序类加载器(这个类加载器由sun.misc.Lanucher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径上所指定的类库)

这三种加载器是父子关系,加载的方式为双亲委派模型(parents delegation model)。即如果一个加载器收到了类加载的请求,首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,以此类推,只有当代加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。

扯远了

说回反射。现在我们的类加载器从字节码文件中获取到的Class对象,共有以下三种方式获取

1.Class clazz = new A().getClass()

2.Class clazz = A.class;

3.Class clazz = Class.forName()

开发中建议用方式三,因为类的全路径名可以写在配置文件里,这样很灵活。

那么我们如何使用反射呢?代码如下

package ReflectDemo;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

/**

* Created by zuzhaoyue on 2019/2/13.

*/

public class ReflectTest {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {

Class clazz = Class.forName("model.Person");

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

Class clazz4 = classLoader.loadClass("model.Person");

System.out.println(clazz);

System.out.println(clazz4);

//得到所有的构造方法

/*Constructor[] constructors = clazz.getDeclaredConstructors();

for(Constructor constructor:constructors){

System.out.println("构造方法:"+constructor);

A a = (A) constructor.newInstance("aa",11);

System.out.println("A a:"+a.getAge());

}*/

//得到单个带参构造方法,不带参的类似

Constructor constructor = clazz.getConstructor(String.class,int.class);//返回构造方法对象,通过Class对象使用其中的成员变量对象

System.out.println("带参构造方法"+constructor);

Object p1 = constructor.newInstance("zzy",11);

System.out.println(p1.toString());

//访问私有的构造方法

Constructor privateConstructor = clazz.getDeclaredConstructor();

System.out.println("私有构造方法:" + privateConstructor);

privateConstructor.setAccessible(true);//暴力访问

Object p2 = privateConstructor.newInstance();

System.out.println(p2.toString());

/*//获取成员变量

Field[] fields = clazz.getDeclaredFields();//获取所有的成员变量

for(Field field:fields){

System.out.println("成员变量:" + field);

}*/

//给成员变量赋值

Field name = clazz.getDeclaredField("name");

name.setAccessible(true);//因为是私有的,所以又来暴力访问了

name.set(p2,"aaaaa");//给p2的name属性赋值

System.out.println(p2.toString());

Field age = clazz.getDeclaredField("age");

age.setAccessible(true);

age.set(p2,13);

System.out.println(p2.toString());

//method的调用

// Method[] methods = clazz.getMethods();//获取自己的及父亲的方法

Method[] methods = clazz.getDeclaredMethods();//获取自己的方法,不包括父亲的

for(Method method:methods){

String name1 = method.getName();

Class[] arg = method.getParameterTypes();

System.out.println("方法名:" + name1);

for(Class a: arg){

System.out.println("参数类型:" + a);

}

}

Method method = clazz.getDeclaredMethod("say");//获取一个方法

method.invoke(p2);//调用

Method method1 = clazz.getMethod("say2",String.class);

method1.invoke(p2,"祖祖侠");

Method method2 = clazz.getMethod("say3",String.class);

Object object = method2.invoke(p2,"mm");

System.out.println("返回值:" + object);

}

}

package model;

/**

* Created by zuzhaoyue on 2019/2/14.

*/

public class Person {

private String name;

private int age;

private Person()

{

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

@Override

public String toString() {

return "Person{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

public Person(String name, int age) {

this.name = name;

this.age = age;

}

public void say(){

System.out.println("大家好,我是" + this.name + ",今年" + age + "岁!");

}

public void say2(String friend){

System.out.println("大家好,我是" + this.name + ",今年" + age + "岁!" + "我最好的朋友是" + friend);

}

public String say3(String enName){

System.out.println("英文名是"+enName+"....瞎说一气,重点是返回值。");

return "hello world";

}

}

方法具体怎么使用不是那么重要,api文档里都能找到,关键是理解反射是从字节码文件获取到Class对象,然后获取到相应的Method,Field,Constructor对象,与new Person().say()等使用是反着来的,就可以了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值