Java高级之反射

“在反射之下,一段Java程序也变得无所遁形。探索框架的精髓——反射”

 

什么是反射

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

 之前学习Java基础时候没注意到反射,一直到最近在研究 Spring动态代理和 IOC底层的时候才发现,原来有这么一个强大的机制都被我给忘了。

先来了解一下Java程序的三个阶段:

这三个阶段分别是:源代码阶段,Class类对象阶段,程序运行阶段。

  1. 第一阶段发生在磁盘内:javac 将 Java 代码编译成字节码(.class),类的属性成员们,构造方法们,成员方法们分别被管理到三个区域。
  2. 第二阶段发生在JVM内存中,这里并非堆内存:由ClassLoader类加载器将字节码加载到Class类对象中,三个区域仍被分区管辖,反射的一些操作在这一阶段引入。
  3. 第三阶段:对象在运行时被调用运行。

 

到这里就可以联想到IDE编写程序时的一些快捷操作了,实际上就是反射机制下,在JVM内存里找到对象对应的属性或方法们,然后放到一个表格里供快速选择。

 Java反射中的一些操作

Java中的反射相关类封装在 import java.lang.reflect 包中。常用的有操作Class对象、成员属性、构造方法、成员方法。

获取Class对象有三种实现方式,在一次运行中同一字节码文件只会被加载一次,所以这三种方式获取到的时同一个对象,用“==”比较结果毫无疑问时 true

@Test //测试获取class对象
public void testClass() throws Exception {
    //获取Class对象的方式一
    Class<?> clazz1 = Class.forName("com.duebass.reflect.Person");
    System.out.println(clazz1);
    //方式二
    Class<Person> clazz2 = Person.class;
    System.out.println(clazz2);
    //方式三
    Person person = new Person();
    Class<? extends Person> clazz3 = person.getClass();
    System.out.println(clazz3);
    //在一次运行中同一字节码文件只会被加载一次,结果毫无疑问是 true
    System.out.println(clazz1==clazz2);
    System.out.println(clazz1==clazz3);
}

在获取成员属性、构造器方法、成员方法时参考命名规范可以发现——

get***(参数): 是获取某一成员,参数时成员名,如果是构造器参数则是构造器的传参类型.class(例如String.class)

get***s(参数):是获取某一全部成员,这个和上面那个都找不到原类中的私有成员。

getDeclared***():这种方式对应着get***() 方法,不过这种情况下可以让返回对象调用 setAccessible(true) 方法设置成暴力反射,即便是私有属性也能访问。

getDeclared***s():带s,毫无疑问啊获取全部某一成员,这种和上面那位一样,可以设置暴力反射,如果不设置暴力反射而贸然访问私有属性运行时会被一个 java.lang.IllegalAccessException 异常中断程序。

 

获取成员属性:返回 Field 对象 有一个get() 方法传入一个真实对象可获取一个Object对象,同时也可以调用set() 方法传入一个有该属性的对象和一个值间接给对象赋值。

@Test  //测试获取属性
public void testField() throws Exception {
    Class<?> clazz = Class.forName("com.duebass.reflect.Person");
//        Field name = clazz.getField("name");//贸然访问私有属性会抛出异常
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true); //暴力反射开关

    Field[] fields = clazz.getFields();
    Field[] declaredFields = clazz.getDeclaredFields();

    Person person = new Person();
    Object result = name.get(person);
    System.out.println(result);
    name.set(person,"yang"); //给Person赋值
    System.out.println(person);
}

获取构造方法: 构造方法返回的一个Constructor 对象 有一个 newInstance() 方法可用于创建对象,传参时有参构造,不传参无参构造,要保证原类有对应方法。

@Test  //测试获取方法
public void testConstructor() throws Exception {
    Class<?> clazz = Class.forName("com.duebass.reflect.Person");
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
    Object result = constructor.newInstance("yang", 20);
    System.out.println(result);
}

获取成员方法:成员方法返回的一个Method 对象 有一个invoke() 方法可以用于调用类成员方法,真实对象当作参数传入就可以调用,这个传入得对象也可以是继承而来。

@Test
public void testMethod() throws Exception {
    Class<Person> clazz = Person.class;
    Method method = clazz.getMethod("speak");
    test tes = new test(); //test是继承Person得一个类
    method.invoke(tes);
}

 研究到这里不由得联想到学习Spring框架时的动态代理的底层实现,哦呦可以,有内味了

 

无了无了

——(其实还有很多Class成员方法,在这里不写了,想了解可点击这里:点我查看更多 )

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值