类反射的基本用法

首先我们来了解一下什么是类反射:

☆什么是反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查, 也称自审,并能直接操作程序的内部属性。例如,使用它能获得Java类中各成员的名称并显示出来。

Java的这一能力在实际应用中应用得很多,在其它的程序语言中根本就不存在这一特性。例如,Pascal、C或者C++中就没有办法在程序中获得函数定义相关的信息。
JavaBean是类反射的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过类反射动态的载入并取得Java组件(类)的属性。后面学习的各种框架,基本上都会有反射的使用。

反射使用的三个步骤 

第一步:获得你想操作的类的java.lang.Class对象。在运行中的Java程序中,用java.lang.Class类来描述类和接口等。

第二步:调用诸如getDeclaredMethods的方法,取得该类中定义的所有方法的列表。

第三步:使用反射的API来操作这些信息。

如:

public void demo3() throws Exception{
		//1获取Class对象
		Class c = Class.forName("cn.hncu.reflect.hello.Person");//参数必须是:类全名
		
		//2获取要调用的方法--Method对象
		//c.getDeclaredMethod("aa", new Class[]{int.class,int.class});
		Class parameterTypes[] = {int.class,int.class};
		Method m = c.getDeclaredMethod("aa", parameterTypes);
		
		//3执行方法 --m.invoke()    //Person p = new Person(); p.aa(10,20);
		Object p = c.newInstance();
		Object objs[] = {10,20};
		Object returnValue = m.invoke(p, objs);
		System.out.println("a+b="+ returnValue);
		
	}
获取Class对象的三种方式 

★ 方式一

通过对象的getClass方法进行获取。这种方式需要具体的类和该类的对象,以及调用getClass方法。

★ 方式二

任何数据类型(包括基本数据类型)都具备着一个静态的属性class,通过它可直接获取到该类型对应的Class对象。这种方式要使用具体的类,然后调用类中的静态属性class完成,无需调用方法,性能更好。

★ 方式三

通过Class.forName()方法获取。这种方式仅需使用类名,就可以获取该类的Class对象,更有利于扩展。

package cn.hncu.reflect.fetchClass;

import org.junit.Test;

public class FetchClassDemo {
	
	@Test//通过对象的getClass()方法可以获取 Class对象(依赖:类+对象)
	public void demo1(){
		Person p=new Person();
		Class c=p.getClass();
		System.out.println(c);
	}
	
	@Test//任何数据类型(包括基本数据类型)都有一个静态的属性class。(依赖类)
	public void demo2(){
		System.out.println(int.class);
		System.out.println(Integer.class);
		System.out.println(String.class);
	}
	
	@Test//通过Class.forName()方法获取,依赖 java.lang.String
	public void demo3(){
		try {
			Class c=Class.forName("cn.hncu.reflect.fetchClass.Person");	//这里需要用类全名
			System.out.println(c);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}
类的解剖(获取类的定义信息)

Person

package cn.hncu.reflect.decompose;

import java.io.IOException;

import org.junit.Test;

public class Person {
	private String name;
	public int age;
	
	public Person() {
	}
	
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	@Test
	public void aa(int a,String s) throws IOException,Exception{
		System.out.println("aa");
	}
	
	public int bb(Integer i,int a)throws RuntimeException,Exception{
		return 0;
	}
}
★ 获取类的方法(找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的反射用法。)

@Test//获取所有的Method对象
	public void fetchMethods(){
		try {
			Class c=Class.forName("cn.hncu.reflect.decompose.Person");
			
			Method[] m1=c.getDeclaredMethods();	//获得当前类声明的方法,包括私有方法
			Method[] m2=c.getMethods();	//获取当前类,以及父类的声明的public方法
//			Method m=c.getMethod(name, parameterTypes);	//获取当前类,以及父类的单个方法
//			Method m=c.getDeclaredMethod(name, parameterTypes);//获取当前类,以及父类的public方法
			for(Method m:m1){
				System.out.println("方法名"+m.getName());	//获得方法名
				
				int modifiers=m.getModifiers();		//获得修饰符
				System.out.println("修饰符"+Modifier.toString(modifiers));
				
				Class exceptions[]=m.getExceptionTypes();	//获取异常类型
				System.out.println("异常类型");
				for(Class exception:exceptions){
					System.out.print(exception.getName()+" ");
				}
				System.out.println();
				
				Class parameters[]=m.getParameterTypes();	//获取参数类型
				System.out.println("参数类型");
				for(Class parameter:parameters){
					System.out.print(parameter.getName()+" ");
				}
				System.out.println();
				
				System.out.println("注解类型");
				Annotation anns[]=m.getAnnotations();
				for(Annotation ann:anns){
					System.out.print(ann.toString()+" ");
				}
				
				System.out.println("返回值类型"+m.getReturnType());	//获取返回值类型
				System.out.println("--------------------------------------");
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
运行结果:

方法名bb
修饰符public
异常类型
java.lang.RuntimeException java.lang.Exception 
参数类型
java.lang.Integer int 
注解类型
返回值类型int
--------------------------------------
方法名aa
修饰符public
异常类型
java.io.IOException java.lang.Exception 
参数类型
int java.lang.String 
注解类型
@org.junit.Test(expected=class org.junit.Test$None, timeout=0) 返回值类型void
--------------------------------------
★ 获取类的构造器(找出一个类中定义的构造方法,构造器没有返回类型。)
@Test//获取所有的Constructor对象
	public void fetchConstructor(){
		try {
			Class c=Class.forName("cn.hncu.reflect.decompose.Person");
			
			Constructor[] cons=c.getDeclaredConstructors(); //获得当前类声明的构造方法
//			Constructor[] cons2=c.getConstructors(); //获得当前类,及其父类声明的public构造方法
//			Constructor cons=c.getDeclaredConstructor(parameterTypes); //获得一个当前类声明的构造方法
//			Constructor cons=c.getConstructor(parameterTypes); //获得一个当前类,及其父类声明的public构造方法
			for(Constructor con:cons){
				System.out.println("方法名:"+con.getName());
				
				int modifies = con.getModifiers();
				System.out.println("修饰符:"+Modifier.toString(modifies));
				
				Class[] parameters = con.getParameterTypes();
				System.out.println("参数类型:");
				for(Class parameter:parameters){
					System.out.print(parameter.getName()+" ");
				}
				System.out.println();
				
				Class[] exceptions = con.getExceptionTypes();
				System.out.println("异常类型");
				for(Class exception:exceptions){
					System.out.print(exception.getName()+" ");
				}
				System.out.println();
				
				Annotation[] anns = con.getAnnotations();
				System.out.println("注解类型");
				for(Annotation ann:anns){
					System.out.println(ann.toString());
				}
				System.out.println();
				
				System.out.println("---------------------------------");
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
运行结果:
方法名:cn.hncu.reflect.decompose.Person
修饰符:public
参数类型:

异常类型

注解类型

---------------------------------
方法名:cn.hncu.reflect.decompose.Person
修饰符:public
参数类型:
java.lang.String int 
异常类型

注解类型

---------------------------------
★ 获取类的属性字段(找出一个类中定义了哪些属性字段。)
@Test
	public void fetchFields(){
		try {
			Class c=Class.forName("cn.hncu.reflect.decompose.Person");
			
			Field fields[]=c.getDeclaredFields();
			for(Field field:fields){
				System.out.println("属性名:"+field.getName());
				
				int midifies = field.getModifiers();
				System.out.println("修饰符:"+Modifier.toString(midifies));
				
				Class type=field.getType();
				System.out.println("属性类型"+type.getName());
				
				Annotation[] anns = field.getAnnotations();
				System.out.println("注解类型:");
				for(Annotation ann:anns){
					System.out.print(ann.toString()+" ");
				}
				System.out.println();
				
				System.out.println("--------------------");
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
运行结果:
属性名:name
修饰符:private
属性类型java.lang.String
注解类型:

--------------------
属性名:age
修饰符:public
属性类型int
注解类型:

--------------------
类的调用(调用类中的成员)

Person

package cn.hncu.reflect.operatorObj;

public class Person {
	private String name;
	public int age;
	
	public Person() {
		super();
	}
	public Person(String name) {
		this.name = name;
	}
	
	public int getAge(int a){
		return age;
	}
	public static String aa()throws Exception{
		return null;
	}
	
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

★ 构造类对象 

使用构造器新建对象。根据指定的参数类型找到相应的构造函数,传入相应参数调用执行,以创建一个新的对象实例。

@Test//使用构造器来创建对象
	public void operatorConstructor() throws Exception{
		//步骤1.
		Class c=Class.forName("cn.hncu.reflect.operatorObj.Person");
		//空参构造
		Object obj1=c.newInstance();	
		System.out.println("空参构造:"+obj1);
		
		//使用指定参数构造
		//步骤2.通过形参获得指定的构造器对象
		Class parameterTypes[]={ String.class };
		Constructor con=c.getConstructor(parameterTypes);
		
		//步骤3.根据构造器对象con.newInstance(..),传入实参数据
		Object[] initargs={ "Tom" };
		Object obj2 = con.newInstance(initargs);
		
		System.out.println("有参构造:"+obj2);
	}
结果:

空参构造:Person [name=null, age=0]
有参构造:Person [name=Tom, age=0]
★ 调用方法 
根据方法名称执行方法。根据方法名与参数类型匹配指定的方法,传入相应参数与对象进行调用执行。若是静态方法,则不需传入具体对象。
@Test//使用Method对象,调用方法
	public void method() throws Exception{
		//步骤1.
		Class c=Class.forName("cn.hncu.reflect.operatorObj.Person");
		
		调用空参方法//
		//步骤2.获取Method对象
		Method m1=c.getMethod("toString", null);
		
		//步骤3.通过m.invoke()调用方法
		Object obj1=c.newInstance();
		System.out.println("调用空参方法");
		Object obj = m1.invoke(obj1, null);		//返回值,就是toString()方法的返回值
		System.out.println(obj);
		
		调用有参方法/
		//步骤2.获取Method对象
		Class[] parameterTypes2={int.class};
		Method m2=c.getMethod("getAge", parameterTypes2);
		
		//步骤3.通过m.invoke()调用方法
		Object obj2=c.newInstance();
		Object args[]={ 1 };
		System.out.println("调用有参方法");
		obj=m2.invoke(obj2, args);		//返回值就是getAge()方法的返回值
		System.out.println(obj);
		
		//调用静态方法/
		//步骤2.获取Method对象
		Method m3=c.getMethod("aa", null);
		
		//步骤3.通过m.invoke()调用方法
		Object obj3=c.newInstance();
		System.out.println("调用静态方法");
		obj=m3.invoke(obj3, null); 	//返回值就是aa()方法的返回值
		System.out.println(obj);
	}
结果:
age:22
name:Tom
调用空参方法
Person [name=null, age=0]
调用有参方法
0
调用静态方法
null
空参构造:Person [name=null, age=0]
有参构造:Person [name=Tom, age=0]
★ 获取与设置属性值 
根据属性名称读取与修改属性的值,访问非静态属性需传入对象为参数。

@Test//使用Filed对象来访问类中的属性变量--读取或者设置属性的值
	public void field() throws Exception{
		//步骤1.
		Class c=Class.forName("cn.hncu.reflect.operatorObj.Person");
		
		//步骤2.获取指定的Field对象
		Field field=c.getDeclaredField("age");
		
		//步骤3.通过Field对象获取或者给属性设置值
		Object obj=c.newInstance();
		field.set(obj, 22);		//相当于给属性age=22
		
		Object age=field.get(obj);	//获取age的值	这里的age为public
		System.out.println("age:"+age);
		
		//若属性值为private,需要进行暴力访问
		Field field2=c.getDeclaredField("name");
		
		Object obj2=c.newInstance();
		field2.setAccessible(true);		//在访问之前打开此开关,就可以进行访问了
		/* 
		 * setAccessible()是AccessibleObject类中的方法,
		 * 该类是Constructor、Method和Field三者的公共父类,
		 * 因此都可以调用---都可打开开关进行暴力访问
		 */
		field2.set(obj2, "Tom");		
		
		Object name=field2.get(obj2);
		System.out.println("name:"+name);
		
		//注意:※暴力访问一般只在特殊场合如做框架功能时使用,平时开发不能使用,否则会违反设计原则
	}	
结果:
age:22
name:Tom

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值