一、反射的概念解释:
写一个类是把各属性、各方法、各构造器包装成目标类的过程。反过来看,通过一个确切的类把里面的个属性、各方法、各构造器解析出来的过程则是反射。
二、反射举例分别获取类的构造器、属性、方法
构建一个Student类如下:
public class Student {
String name;
int age;
private char sex;
public Student()
{
System.out.println("this is the constructor of no variable");
}
public Student(String name)
{
this.name=name;
System.out.println("set name with"+name);
}
public Student(int age)
{
this.age=age;
System.out.println("set age with"+age);
}
private Student(char sex)
{
this.sex=sex;
System.out.println("set sex with"+sex);
}
public String GetName()
{
return name;
}
public int GetAge()
{
return age;
}
private char GetSex()
{
return sex;
}
}
然后通过Class.forName方法获取该类对象,当然也可以用Student.getClass或者Student.class。再通过类对象的方法分别获取Studnet类的构造器、属性、方法。具体过程如下。
获取Student类的构造器:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class stuClass=Class.forName("person.Student"); //PakageName.ClassName
Constructor[] conArray=stuClass.getDeclaredConstructors();
for(Constructor tmp:conArray)
{
System.out.println(tmp);
}
}
}
输出结果:
private person.Student(char)
public person.Student(int)
public person.Student(java.lang.String)
public person.Student()
获取Student类的属性:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class stuClass=Class.forName("person.Student"); //PakageName.ClassName
Field[] conArray=stuClass.getDeclaredFields();
for(Field tmp:conArray)
{
System.out.println(tmp);
}
}
}
输出结果:
java.lang.String person.Student.name
int person.Student.age
private char person.Student.sex
获取Student类的方法:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class stuClass=Class.forName("person.Student"); //PakageName.ClassName
Method[] conArray=stuClass.getDeclaredMethods();
for(Method tmp:conArray)
{
System.out.println(tmp);
}
}
}
输出结果:
public int person.Student.GetAge()
public java.lang.String person.Student.GetName()
private char person.Student.GetSex()
三、利用反射破解私有构造器和私有方法
根据Student类的定义可知,由于属性sex是私有的,而且构造器Student(char sex)也是私有的,GetSex()也是私有的,如果正常操作的话sex这个属性根本无法赋值,也不可能通过构造器Student(char sex)去构造一个有性别的对象,更别提通过GetSex()方法获取对象的性别。为了让对象拥有性别,只能通过反射进行破解了,具体过程如下。
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
Class stuClass=Class.forName("person.Student"); //PakageName.ClassName
Constructor con=stuClass.getDeclaredConstructor(char.class); //通过形参设置使con指定为Student(char sex)私有构造器
con.setAccessible(true); //暴力使该私有构造器打开
Student sean=(Student)con.newInstance('m'); //通过该私有构造器构造一个性别为m的对象sean
Field fieName=stuClass.getField("name"); //找到name属性对象
fieName.set(sean, "sean"); //设置对象sean的name属性为sean
Method metGetsex=stuClass.getDeclaredMethod("GetSex", null); //找到Student类中的GetSex()私有方法
metGetsex.setAccessible(true); //暴力使该私有方法打开
char sex=(char) metGetsex.invoke(sean, null);//使用sean对象中的该私有方法
System.out.println("name:"+sean.name+" "+"sex:"+sex); //输出sean对象的名字和性别
}
}
输出结果:
set sex withm
name:sean sex:m
其中第一行输出说明了调用私有构造器Student(char sex)的过程,第二行输出分别说明了通过反射给对象属性赋值和调用对象私有方法过程。破解没有防备的singleton类也是这个办法。