反射是Java中一个非常重要、非常强大的机制。曾看到一句话“反射是框架的灵魂”,初学时不懂,等到学完框架之后才慢慢理解其意。

什么是反射?我们先通过几个类和示例来初步体会一下反射

一、ClassLoader类

什么是类加载器? 

ClassLoader是一个抽象类,它的实例是类加载器。磁盘上存在的xxx.class文件需要被加载进JVM才能执行。类加载器则是负责加载.class文件的对象,然后在JVM中生成该类的Class对象。每一个Class对象都关联着定义它的那个类加载器。数组的类加载器与其元素的加载器是同一个,如果元素类型是基本类型,则数组没有类加载器。

类加载器工作原理

类加载器都有一个与之关联的父加载器,当加载器需要加载一个文件时,它首先将该任务”委派”给父加载器,如果父加载器无法加载该文件,再自己进行加载。JVM的引导加载器(bootstrap class loader)没有父加载器,但可作为父加载器。关于类加载器更详细的分析 点击这里

二、Class类

什么是Class<T>类?

Class不是我们平常声明类时所用的关键字class,它是一个类,它的对象用来描述一个运行状态的类或接口。一个xxx.java文件编译后生成一个xxx.class文件,一个xxx.class文件被JVM加载后生成该类对应的Class对象,该对象包含了该类的所有信息,比如,类中有字段、构造器、方法等信息。一个类有一个对应的Class对象,元素类型相同且长度相同的数组共享一个Class对象,java基本类型包括void也都有各自的Class对象。Class是一个泛型类,如果不加泛型,需要强转。

如何获取一个类的Class对象?

Class没有public构造器,当类被加载时,JVM会通过调用ClassLoader的defineClass方法来自动创建该类的Class对象。

获取一个类的Class对象有三种方式:

1)类名.class

2)  该类的对象.getClass()

3)  Class.forName(String 类名) (包名加类名)

Class对象有何作用?

下面列出几个Class类的方法:

1)   获取类加载器:

getClassLoader()

2)  获取Constructor构造器对象:

getConstructor(Class... parameterType)                               获取具有指定参数的公共构造器对象

getConstructors()                                                                   获取所有公共构造器对象

getDeclaredConstructor(Class... parameterType)         获取具有指定参数的构造器对象

getDdclaredConstructors()                                                     获取所有构造器对象

3)  获取Method对象:

getMethod(String name,Class...parameterType)        获取具有指定名称和参数的公共方法对象

getMethods()                                                                               获取所有公共方法对象

getDeclaredMethod(String name,Class...parameterType)          获取具有指定名称和参数的方法对象

getDeclaredMethods()                  获取所有的方法对象

4)获取Field字段对象:

getField(String name)                      获取具有指定名称的公共字段对象

getFields()                        获取具有所有公共字段对象

getDeclaredField(String name)               获取具有指定名称的字段对象

getDeclaredFields()                      获取所有字段对象

5)获取Class对象所代表的类的一个对象(非常重要的一个方法)

Object  newInstance()                                                                  用默认的无参数构造器创建一个对象

(带Declared的get方法可以获取任意访问权限的成员,不带Declared的只能获取public成员)

测试Class,更多的测试在其他类的测试中体现。

package cn.edu;

public class User {

	private String username;

	private int age;

	public User() {

	}

	public User(String username , int age) {
this.username = username;
this.age = age;
}
private User(String username) {
this.username = username;
}
     public void say(String str) {
        System.out.println(str);
     } @Override
public String toString() {
return "User [username=" + username + ", age=" + age + "]";
} }

  

@Test
public void fun2() throws Exception {
Class userClass = User.class; System.out.println(userClass.getName()); //获取该class对象的类的类名 System.out.println(userClass.getClassLoader().toString()); //获取类加载器 User user = (User)userClass.newInstance(); //调用默认的无参数构造器创建对象
System.out.println(user.toString());
}

  运行结果:

三、Constructor类

构造器类,封装构造器的有关信息。

主要方法 Object newInstance(Object...arg)                                  用指定参数创建对象

测试Constructor

@Test
public void fun2() throws Exception {
Class userClass = User.class; Constructor userConstructor1 = userClass.getConstructor(String.class , int.class); //有参构造器
User user1 = (User)userConstructor1.newInstance("小红",18);
System.out.println(user1.toString()); Constructor userConstructor2 = userClass.getConstructor(); //无参构造器
User user2 = (User)userConstructor2.newInstance();
System.out.println(user2); Constructor userConstructor3 = userClass.getDeclaredConstructor(String.class); //私有构造器
userConstructor3.setAccessible(true); //开启访问权限
User user3 = (User)userConstructor3.newInstance("小明");
System.out.println(user3);
}

  运行结果:

默认是不可以访问private成员的,userConstructor3.setAccessible(true)是用于开启访问权限的,这样就可以访问了,感觉是开挂一样!

四、Method类

方法类,封装方法的有关信息

主要方法

Object invoke(Object obj , Object... args)                                     调用obj对象的Method对象代表的方法,args为参数

测试Method:

@Test
public void fun2() throws Exception {
Class userClass = User.class;
User user = (User)userClass.newInstance(); //用默认无参数构造方法创建对象 Method method = userClass.getMethod("say",String.class); //获取名为"say",参数为string的method对象
method.invoke(user,"hello"); //调用user的say方法
}

  运行结果:

五、Field类

字段类,封装字段的有关信息

主要方法

Object get(Object obj)                                                                   获取obj对象的此Field对象代表的字段的值

void set(Object obj , Object value)              设置obj对象的此Field对象代表的字段的值

测试Fidle

@Test
public void fun2() throws Exception {
Class userClass = User.class;
Constructor userConstructor = userClass.getConstructor(String.class,int.class);
User user = (User)userConstructor.newInstance("小明",18); System.out.println(user.toString()); Field userField = userClass.getDeclaredField("username"); //获取username字段
userField.setAccessible(true); //开启访问权限
userField.set(user, "小红"); //给user对象的该字段设置值 System.out.println(user.toString());
}

   运行结果:

  到此关于反射的几个类就简单的认识了一下,我们可以不用new关键字来创建对象,调用对象的方法也与传统的调用方式有很大区别,我们甚至可以操作private成员(虽然这样做破坏了封装性),相对于传统的操作方式,反射更像是一种逆向思维,以前操作成员,主体在于对象,而反射的主体在于Class和成员本身。到此我们对反射有了初步的认识。接下在叙述一个重要的概念,有助于我们更好的理解反射。

六、动态加载与静态加载

注意此处所说的加载是针对编译的,将xxx.java转化成xxx.class,而不是运行的加载字节码。Java创建对象的常用方式是使用new 关键字,如 User user  = new User(); 这种是静态加载,即在编译期就已经获取User类的有关信息,如果User类不存在或有错误,编译会报错。动态加载就是用上面的Class.forName("包名.User");来加载User类,如果User类不存在或是有错误,在编译时是不会报错的,因为根本没去加载User类。只有当程序运行到该处,JVM才会去加载User,而动态加载则是依赖反射实现的。

好了,可以给出最终概念了,通过上面的重重示例与解析,应该不难理解反射了。

七、反射  

  Java反射机制是指java程序在运行过程中,可以获取任意一个类的相关信息,并且能够调用其方法和属性,这种动态获取信息和动态调用方法的功能叫做Java的反射机制。

上面写了这么多,总结起来也就这一句话。

 本文个人编写,水平有限,如有错误,恳请指出,欢迎讨论分享。

最新文章

  1. Android WebView 302斗争之旅
  2. JavaScript:关于事件处理程序何时可以直接访问元素的属性
  3. google高级搜索
  4. 无法加载协定为“ServiceReference1.xxxxx”的终结点配置部分,因为找到了该协定的多个终结点配置。请按名称指示首选的终结点配置部分
  5. 解决Regsvr32: DllRegisterServer entry point was not found
  6. UI5_UINavigation传值
  7. HDU 1863 畅通工程(最小生成树,prim)
  8. MCM试题原文及翻译 AB题 2014美国数学建模竞赛
  9. &quot;ORA-00942: 表或视图不存在 &quot;的原因和解决方法[转]
  10. 一对TCP协议及OSI简介模式
  11. atom插件
  12. Java数组操作十大方法 (转)
  13. scrapy框架原理学习
  14. android动态设置组件LayoutParams
  15. 同步阿里云镜像到本地,在本地搭建YUM仓库
  16. python操作haproxy.cfg文件
  17. windows 7 64位出现Oracle中文乱码
  18. POJ--1699 Best Sequence(DP+dfs)
  19. linux 和windows系统下同时可用的UML建模工具(umbrello),超强
  20. modprobe

热门文章

  1. python 图形界面
  2. Intellij idea用快捷键自动生成序列化id
  3. June 21st 2017 Week 25th Wednesday
  4. 018os模块
  5. sso(single sign on)
  6. PhoneGap 的消息推送插件JPush极光推送
  7. WebSphere Studio Application Developer 5.0 优化设置
  8. @autoclosure-可以让表达式自动封装成一个闭包:输入的是一个表达式
  9. ADF中VO的查询方法比较
  10. EasyUI使用之鼠标双击事件