Java反射机制详解

          Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,RTTI,即Run-Time Type Identification,运行时类型识别。RTTI能在运行时就能够自动识别每个编译时已知的类型。它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。

 

(1).获取类信息

举例,有一个testreflection.Student类

package testreflection;

public class Student {
 
	public Student(String sex, int age) {
             this.sex=sex;
	     this.age=age;
	}
	public Student() {};
        private String sex="男";
        private int age=15;
 
        public String getSex() {
            return sex;
        }
 
        public void setSex(String sex) {
            this.sex = sex;
        }
       
        public int getAge() {
            return age;
        }
 
        public void setAge(int age) {
            this.age = age;
        }
 
        public void study()
        {
        	System.out.println(sex + " "+ String.valueOf(age)+ "  好好学习");
        }
  }

测试类:

package testreflection;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class testor
{
	@Test
	 public void test() throws ClassNotFoundException
	 {
	    Class<?> clazz=Class.forName("testreflection.Student");
	    Field[] field=clazz.getDeclaredFields();

		System.out.println("----------显示类的属性----------------------------");
	    for(Field f:field)
	    {
	    	System.out.println(f.getName()+"   "+f.getType());
	    }
	    System.out.println("----------显示类的方法-----------------------------");
	    Method[] methods=clazz.getDeclaredMethods();
	    for(Method m:methods)
	    {
	    	System.out.println(m.getName());
	    }
	    System.out.println("---------显示类的构造方法-----------------------------");
	    Constructor[] constructors=clazz.getDeclaredConstructors();
	    for(Constructor<?> c: constructors)
	    {
	    	System.out.println(c);
	    }
	    System.out.println("---------获取类的相关的信息--------------------------");
	 	System.out.println("类所在的包为:"+ clazz.getPackage().getName());
	 	System.out.println("类名:"+ clazz.getName());
	 	System.out.println("父类的名称:"+ clazz.getSuperclass().getName());  
	 } 
}

运行结果:

 这个例子通过java.lang.reflect中的反射,通过类的全名“testreflection.Student”就得到了该类的所有信息,这就是反射,这样就可以在运行时动态的获得类的信息,接下来要将如何生成Student类的实例对象

PS:Class<?>和Class,class有什么区别?
Class<?>和Class这两者并没有什么区别,最好写成Class<?>.
class是java中的关键字,而Class是一个类,就是可以看成Student类,Student类中有sex,age属性,Class类中则有和类相关的一些属性方法,如private transient String name、  public static Class<?> forName(String),也就是说Class也是一个普通类,跟Student,Person并无二致
Student stu=new Student();  这里的stu就等价于上例中的clazz, 因为Class类构造函数是私有的:

 private Class(ClassLoader loader) {
        classLoader = loader;
   }
所以只能通过静态方法如forName来得到实例clazz, 总而言之,Class就是一个包含类信息的普通类,跟Student一样

 

 

(2)得到类Class的三种方式

        @Test
	public void test2() throws ClassNotFoundException
	{
		//第一种,对象.getClass
		Student student=new Student();
		Class clazz=student.getClass();
		System.out.println(clazz.toString());


		//第二种,类名.class
		clazz=Student.class;
		System.out.println(clazz.toString());


		// 第三种:Class.forName("类的路径")
		clazz=Class.forName("testreflection.Student");
		System.out.println(clazz.toString());
	}

运行结果:

 

(3)使用反射动态创建对象实例的方式

        @Test
	public void test3() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException
	{
		//方法1:通过Class的newInstance()方法
		//该方法要求该Class对象的对应类有无参构造方法
		//执行newInstance()实际上就是执行无参构造方法来创建该类的实例
		Class<?> clazz=Class.forName("testreflection.Student");
		Object obj =  clazz.newInstance();
		((Student)obj).study();
		
		//方法2:通过Constructor的newInstance()方法
		//先使用Clazz对象获取指定的Constructor对象
		//再调用Constructor对象的newInstance()方法来创建该Class对象对应类的对象
		//通过该方法可选择使用指定构造方法来创建对象
		Constructor constructor=clazz.getConstructor(new Class[] {String.class,int.class});
		Object obj1 =constructor.newInstance(new Object[]{"女",30});
		((Student)obj1).study();
		
		//以下也可以调用无参构造方法
		Object obj2 = clazz.getConstructor().newInstance();
                ((Student)obj2).study();
	}

运行结果:

男 15  好好学习
女 30  好好学习
男 15  好好学习

 

 

(4)使用反射动态修改和查询字段的值

 getXxx(Object   obj)setXxx(Object obj,Xxx val) :获取或设置obj对象该Field的属性值。此处的Xxx对应8个基本数据类型,如果该属性类型是引用类型则直接使用get(Objectobj)

setAccessible(Boolean flag):若flag为true,则取消属性的访问权限控制,即使private属性也可以进行访问

 

        @Test
	public void test4() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
			NoSuchFieldException, SecurityException {
		Class<?> clazz = Class.forName("testreflection.Student");
		Object object = clazz.newInstance();
		//获得 Student类中的指定属性对应的Field对象
		Field field = clazz.getDeclaredField("age");
		
		//取消属性的访问权限控制,即使private 属性也可以进行访问
		field.setAccessible(true);
		
                //通过field对象获取真实field的值,有两种方式
		System.out.println(field.get(object));
		System.out.println(field.getInt(object));
		
                //通过field给真实对象中的field赋值
		field.set(object, 33);
		System.out.println(field.getInt(object));
	}

运行结果:

15
15
33

 

(5)使用反射动态执行方法

通过Class对象的getMethods()方法可以获得该类所包括的全部方法,返回值是Method[]
通过Class对象的getMethod() 方法可以获得该类所包括的执行方法,返回值是Method
每个Method对象对应一个方法,获得Method对象后,可以调用其invoke()     来调用对应方法   

        @Test
	public void test5()throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException,
			SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		Class<?> clazz = Class.forName("testreflection.Student");
		Object obj = clazz.newInstance();

		//调用该对象的 setSex方法
		Method method = clazz.getMethod("setSex", new Class[] { String.class });
		Object result = method.invoke(obj, new Object[] { "iam a man" }); // obj.setName("iam a man");

		//调用对象的getSex()方法
		Method method1 = clazz.getMethod("getSex", new Class[] {});
		Object obj1 = method1.invoke(obj, new Object[] {});
		System.out.println("已设置为" + obj1);
	}

运行结果:

已设置为iam a man

 

(6)使用反射动态创建数组并存取元素

在java.lang.reflect包提供了Array类,包括一系列static方法,可动态的创建数组、给元素赋值、取出元素值等                      
Array提供的主要方法如下:
static ObjectnewInstance(Class<?> componentType, int[] dim) :创建一个具有指定的组件类型和维度的新数组
static void setXxx(Objectarray, int index ,xxx val):给数组对象array中第index个元素赋值val
static xxx getXxx(Objectarray, int index):以 xxx形式返回指定数组对象array中第index个元素值

        @Test
	public void test6()throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException,
			SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		Class clazz = Class.forName("java.lang.Integer");
		Object array = Array.newInstance(clazz, 10);// 根据类的class 创建大小为10的数组
		Array.set(array, 5, 111);// 给数组的第5个元素赋值为111
		Object el = Array.get(array, 5);// 取出数组的第5个元素值显示
		System.out.println(el);
	}

运行结果:

111

 

总结:

1.反射就是java.lang.reflect包所提供的一系列类和方法,里面包含了Class,Field,Method等类
2.Felid类跟Method,Class类本质上是一样的,他们都是用来保存class相关信息的类,跟Student类并无二致
3.通过反射,我们可以知道类的所有信息,可以动态创建类,调用类方法,查看修改类字段,动态创建类的数组等等
 

 

参考:https://blog.csdn.net/L19921009/article/details/8214542  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值