java反射机制是指对于运行中的任意一个类,都可以知道这个类的多有成员函数和成员变量,对于任意一个变量,都可以调用这些方法,包括私有方法,这种动态获取一个类的信息,以及动态调用这些类的方法就叫做java中的反射机制,反射机制是Struts2,Hibernate,Spring的基础。
下面使用简单的例子来学习一下java中反射机制:
学习反射必须知道的几个类:Class,Field,Method
java中的任意一个对象都有一个唯一与之对应的Class<?>对象与之对应,获得一个对象的Class对象主要有三种方法:
a)Class<?> classType=Class.forName("java.lang.String")//获得String对象的Class对象
b)Class<?> classType=String.class;//注意是用类名调用
c)Class<?> classType=new String().getClass();//getClass方法继承自Object方法,注意是用对象调用
例1:不使用构造函数,创建一个类,并将创建的一个类复制给另一个相同的对象
public class Person
{
private int id;
private String name;
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;
}
private void sayHello(String name)
{
System.out.println("Hello:"+name);
}
}
public class CopyTest
{
public static Object Copy(Object obj) throws Exception
{
Class<?> classType=obj.getClass();//通过object的getClass方法获得obj对象对应的Class 对象
Object newobj=classType.newInstance();
Field[]fields=classType.getDeclaredFields();
for(Field field:fields)
{
String name=field.getName();
String firstLettle=name.substring(0,1).toUpperCase();
String getMethodName="get"+firstLettle+name.substring(1);
String setMethodName="set"+firstLettle+name.substring(1);
System.out.println("get方法:"+getMethodName);
System.out.println("set方法:"+setMethodName);
Method get=classType.getDeclaredMethod(getMethodName,new Class[]{});
Method set=classType.getDeclaredMethod(setMethodName, new Class[]{field.getType()});
set.invoke(newobj, get.invoke(obj, new Object[]{}));
}
return newobj;
}
public static void main(String[] args) throws Exception
{
Person person1=new Person();
person1.setAge(24);
person1.setId(1);
person1.setName("gavin");
Person person2=null;
person2=(Person)Copy(person1);
System.out.println("id:"+person2.getId()+" name:"+person2.getName()+" age:"+person2.getAge());
}
}
现在对上面的一段代码进行解释:
1、创建一个Person类,包含一些属性和get,set方法,以及一个私有的成员方法sayHello(String name)
2、在CopyTest类中使用反射机制分别获得了各个属性的set,get方法的名字。然后通过调用Class对象的getDeclaredFields找到这些Method对象,最后调用Method对象中的invoke方法进行操作。
例2:
该实例主要完成使用反射机制实现访问一个类的私有成员函数以及私有成员变量
public class CallPrivate
{
public static void main(String[] args) throws Exception
{
Person per=new Person();
per.setAge(25);
per.setId(2);
per.setName("gavin");
//使用了上面的例子中的一个函数,其实可以不用这样,直接手工创建一个Person对象即可
Person person=(Person)CopyTest.Copy(per);
//获得Person对象对应的Class对象
Class<?> classType=Person.class;
//获得sayHello方法对象
Method hello=classType.getDeclaredMethod("sayHello", new Class[]{String.class});
hello.setAccessible(true);//压制访问权限检测
//访问私有成员函数
hello.invoke(person, new Object[]{person.getName()});
System.out.println("------------------------------------");
//访问私有成员变量
Field field=classType.getDeclaredField("name");
field.setAccessible(true);
field.set(person, "aviva");
System.out.println("修改后的值:"+person.getName());
}
}
该段代码要注意的地方是hello.setAccessible(true);这句代码的作用是压制访问权限的监测,就是说不检查该方法是不是私有的。
通过查找帮助文档我们会发现:Constructor,Field,Method都是继承了AccessibleObject这个类,该类中有个方法:
如图:
大概意思就是说当我们传入true时,就会压制java语法检查该方法的访问权限。