java的反射机制,通俗易懂

我将从四个方面谈java的反射,分别是反射的本质,为何会有反射,反射的底层原理,以及如何去利用反射。

java的反射机制,其本质是使java程序在运行的过程中,动态地加载一个类的信息,从而去访问这个类的属性,调用这个类的方法。java为什么会有反射机制呢?这与java程序的运行机制有关系,java程序要想运行,必须先将源代码编译成class字节码文件,再加载到JVM中才能运行,这个时候就会有一个问题,java程序都是提前编译好的,假如java程序在运行的过程中想要动态地使用某个类的方法或变量,这个时候怎么办呢?假如没有反射,这个时候如果以硬编码的方式写在java源程序中肯定是不行的,可能这次java需要用这个类,下次需要用那个类,总不能次次修改源代码吧;那假如用ifelse判断呢,根据传递参数的不同,判断加载哪些,这种方法显得就很蠢,假如我新写了一个类,我就要调用这个类呢?这个时候java程序总不能提前猜好我要调用哪个类了吧,所以,不管怎么样,java没有反射机制,想要在java程序运行的过程中,动态地使用一个类,那是相当麻烦,因此,java反射机制就恰当地解决了这个问题。

Java有了反射机制,那该如何动态加载一个类呢?这与类的加载机制有关系,类的加载机制核心就是类加载器根据类的全限定路径名(包名+类名,其实就是一个字符串),将该类的class字节码文件加载到内存,并生成这个类的java.lang.Class对象。在这个过程中,类加载器不用考虑,在启动JVM过程中就已经创建好了类加载器,也不用自己选,我们需要关心的就是全限定路径名,只要给定不同的全限定路径名,java程序就可以加载不同的类,这下岂不是爽歪歪,我们只要在相应的配置文件中,提前写好全限定路径名,让java程序运行的时候去读取这个配置文件,这样就可以让java程序运行的时候动态加载一个类了,这同时也是框架里面采用的思想。

明白了动态加载类的机制问题,就可以考虑如何用代码实现类的加载了,一行代码就可以搞定:

Class clazz=Class.forName("com.xxxx.xxx");

仅这一行代码就生成了该类的Class对象,接下来就可以对这个对象为所欲为了(奸笑)。何为为所欲为,就是想干嘛干嘛,意味着即使一个类的属性或者方法是私有的,咱们也可以通过Class对象访问到,有没有想到透视眼镜呢?(又一次奸笑)

网上说获得Class对象有三种方式,一种是:类名.class方式,二种是:对象名.getClass()方式,三种是:Class.forName()方式。我认为哈,前两种是内存中已经存在Class对象了,通过这两种方式去获取Class对象,而第三种才是真正的无中生有,从class字节码文件,生成Class对象。

到了这里我们不妨想想,我们获得Class对象究竟想干嘛,无非有四:一生成该类对象,二访问属性,三调用其方法,四访问注解,访问途径也有四:分别利用Java.lang.reflect.Constructor类,Java.lang.reflect.Filed类,Java.lang.reflect.Method类,Annotation注解类型,那接下来就用代码实现如何获取一个类中以上四种信息。

代码一:自定义注解AnnotationClass和AnnotationField

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationClass {
	String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationField {
	String fieldName();
	String fieldType();
	int fieldLength();
}

代码二:Person.java,是一个javabean

@AnnotationClass("Student_info")
public class Person {
	@AnnotationField(fieldName = "Sid",fieldType = "int",fieldLength = 10)
	private int id;
	@AnnotationField(fieldName = "Sname",fieldType = "varchar",fieldLength = 10)
	private String name;
	@AnnotationField(fieldName = "Sage",fieldType = "int",fieldLength = 3)
	private int age;
	 
	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;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Person(int id, String name, int age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
	private Person() {
		
	}
}

代码三:利用反射获取上面Person类的所有信息。

public class TestReflection {

	public static void main(String[] args){
		try {
			//0. 获取Person类的Class对象
			Class<?> clazz = Class.forName("com.xxx.pojo.Person");
			
			//1. 获取Person的构造器,并调用构造器创建info的对象
			Constructor<?> constructor01=clazz.getDeclaredConstructor();//获得无参构造器
			Constructor<?> constructor02=clazz.getConstructor(int.class,String.class,int.class);//获取含参构造器
			constructor01.setAccessible(true);//打开访问权限
			Info obj01=(Info)constructor01.newInstance();//利用无参构造器创建对象
			Info obj02=(Info)constructor02.newInstance(1001,"张三",18);//利用含参构造器创建对象
			System.out.println(obj02.getAge());//输出18
			 
			//2. 获取Person的属性,并对属性进行赋值
			Field field01=clazz.getDeclaredField("age");//获得age属性
			field01.setAccessible(true);//打开age属性的访问权限
			field01.set(obj02, 19);//给对象obj02设置age属性为19
			System.out.println(obj02.getAge());//输出19
			
			//3. 获得Person的方法,并调用info的方法
			Method fun01=clazz.getMethod("getAge");//获得getAge()方法
			fun01.invoke(obj02);//调用obj02对象的getAge()方法
			Method fun02=clazz.getMethod("setAge",int.class);//获得setAge(int age)方法
			fun02.invoke(obj02, 20); //调用obj02对象的setAge(int age)方法,参数是20
      System.out.println(obj02.getAge());//输出20
			
			//4. 获取Person的注解,之后可以利用注解构造sql语句。
			AnnotationClass classAnnotation=clazz.getAnnotation(AnnotationClass.class);//获得对Person类的注解
			Field[] fields=clazz.getDeclaredFields();
			System.out.println(fields.length);
			for(Field f:fields) {
				AnnotationField fieldAnnotation=f.getAnnotation(AnnotationField.class);//获得对属性的注解
				if(fieldAnnotation!=null) {		
					System.out.print(fieldAnnotation.fieldName()+"--");//获得属性注解中的fieldName字段
					System.out.print(fieldAnnotation.fieldType()+"--");//获得属性注解中的fieldType字段
					System.out.println(fieldAnnotation.fieldLength());//获得属性注解中的fieldLength字段
				} 
			} 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值