反射[reflection]在java中的使用

最近在学习j2ee和设计模式两门课时同时遇到这个技术,按道理讲是挺基础的一个概念,但是在以前的编程中没有应用到,所以也没有注意,现在设计模式刚刚入门,发现反射技术真的是非常的好用。

首先看一个实体类

public class Admin {

	// Field
	private int id = 13416123;
	private String name = "xujingfeng";
	
	// Constructor
	public Admin(){
		System.out.println("Admin.Admin()");
	}
	public Admin(String name){
		System.out.println("Admin.Admin()" + name);
	}
	
	// Method
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}

其实一个类说的详细点主要是由以下几个部分组成:Class = Field + Constructor + Method (这里说主要由这几个组成,其实还可以有注解Annotation之类生僻的概念,不做讨论了)

Field 就是常说的 属性+属性值,这里其实可以这样理解,属性主要是针对类的,属性值主要是针对对象的。为了方便解释反射,直接在类中定义了默认初始值,让类也具备了属性值。

Constructor 包括了有参构造和无参构造...这些构造方法。

Method就是那些有参,无参,又返回,无返回的各类方法。

这样我们就讲类总结了,主要由这些部分组成,看完组成,我还没有提到反射呢,不急。

想想我们平时主要是怎么使用类的?是不是拿到一个类,然后new一个对象,就像这样:

Admin admin = new Admin();

再总结一下,我们面向对象编程,把所有东西抽象成类,但是实际使用的大部分是对象,也就是 类 -> 对象。(当然,还有静态类的概念,不要纠结...我是为了讲出我想讲的所以这么讲的)

这个时候我说,在项目有中有些时候你不能这么新建对象!为什么呢?这样也可以得到admin对象啊?问题就在于

这样把对象生成的方式写死了,如果我现在要new的是一个Student对象,你就必须要修改源代码

Student student = new Student();

你可能会想,拜托,这不就是一句话改一下吗,有必要使用一个新的技术吗?再说了这是两个完全不同的对象,需求肯定也不一样啊,改就改了啊!

先解决第一个疑惑,没错,这的确只是生成了一个对象,改起来比较简单,但是,如果我项目中有1000个这样类似需要修改的地方,你都要一个个找出来手动改掉?显然,我们程序需要一个通用的方法,来新建对象,这样只需要修改一个地方,大家就都改了。

再来解决第二个疑惑,其实项目设计中,大多会讲究设计模式的一些原则,里式替换原则等等,所以你程序的正确写法可能变成这样。

Object admin = new Admin();

好像不就是多态吗?那是面向对象的特性叫多态,但是这么写的好处,需要学习设计模式才能体会,不在今天的讨论范围。也就是说,左边是固定的,右边是可变的,这个时候,王晖大大的教诲就会萦绕在我们耳边:面向对象和设计模式同时需要我们做一个事,那就是把可变的东西东西封装起来。

怎么封装?那就要用到反射了,讲到这儿终于回到正题了。

还是先看看,如果我们用反射,怎么新建一个对象吧。

public void test() throws Exception {
	// 类全名
	String className = "cczu.xu.Admin";
	// 得到类字节码
	Class clazz = Class.forName(className);
		
	// 创建对象1: 默认构造函数简写
	Admin admin = (Admin) clazz.newInstance();
}

这样通过反射就可以实现创建对象了,和之前直接new对象最本质的区别就是,现在的className是字符串,可以通过读取配置文件来获取,当然我这里为了省事是写死的,完全可以把字符串写在配置文件中,然后可以结合泛型,动态的创建配置文件中对象。

在这个过程中其实不难发现,Class.forName通过类全名获取类字节码,实际上我们干了一件和以往不同的事,那就是,我们由 类名 -> 类字节码 -> 对象 不一样要使用new关键字了。

知道对象也得到Class,也就是 对象 -> 类

Class clazz = admin.getClass();
Class clazz = admin.Class;

 所以,反射机制解决一个问题就是,动态生成对象,说的通俗一点就是说,现在我们可以在配置文件里面写上类的全名,然后用反射机制,封装成方法,这样就可以直接生成对象了。通过上面的例子,还可以发现打破我们以往有类得到对象习惯,最起码让你知道了,由对象还可以得到类。 

反射还有其他作用,我们获取到类之后,往往不仅仅需要他的实例,可能还需要得到他内部的东西(内部东西,就是在最前面讲的那三个东西Field + Constructor + Method)

再简单说下另一个作用吧,其实还有其他作用的。

// 反射技术
public class App {

	// 1. 创建对象
	@Test
	public void testInfo() throws Exception {
		// 类全名
		String className = "cczu.xu.Admin";
		// 得到类字节码
		Class<?> clazz = Class.forName(className);
		
		// 创建对象1: 默认构造函数简写
		//Admin admin = (Admin) clazz.newInstance();
		
		// 创建对象2: 通过带参数构造器创建对象
		Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
		Admin admin = (Admin) constructor.newInstance("Jack");
		
	}
	@Test
	//2. 获取属性名称、值
	public void testField() throws Exception {
		
		// 类全名
		String className = "cczu.xu.Admin";
		// 得到类字节码
		Class<?> clazz = Class.forName(className);
		// 对象
		Admin admin =  (Admin) clazz.newInstance();
		
		// 获取所有的属性名称
		Field[]  fs =  clazz.getDeclaredFields();
		// 遍历:输出每一个属性名称、值
		for (Field f : fs) {
			// 设置强制访问
			f.setAccessible(true);
			// 名称
			String name = f.getName();
			// 值
			Object value = f.get(admin);
			
			System.out.println(name + value);
		}
	}
	
	@Test
	//3. 反射获取方法
	public void testMethod() throws Exception {
		
		// 类全名
		String className = "<span style="font-family: Arial, Helvetica, sans-serif;">cczu.xu.Admin</span><span style="font-family: Arial, Helvetica, sans-serif;">";</span>
		// 得到类字节码
		Class<?> clazz = Class.forName(className);
		// 对象
		Admin admin =  (Admin) clazz.newInstance();
		
		// 获取方法对象    public int getId() {
		Method m = clazz.getDeclaredMethod("getId");
		// 调用方法
		Object r_value = m.invoke(admin);
		
		System.out.println(r_value);
	}
	
}
其中注意一个细节
clazz.getDeclaredXX()
拿到的是全部的方法,属性,如果是

clazz.getXX()
拿到的就是一些受限制的,例如getMethod()就只有公共方法才能被获取到

有了反射,我们就可以洞悉一个类了。至于反射的具体应用,我现在只在工厂模式,BeanUtils组件,重写BaseServlet,BaseDao这些地方用到,但至少可以明晰一点,在
大量的公用方法,工具类,以及框架的书写中,会大量使用到反射的。先记录这么多吧。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值