首先我们来了解一下什么是类反射:
☆什么是反射
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