反射

来源:互联网 发布:最新人口普查数据 编辑:程序博客网 时间:2024/05/19 09:12
 1.反射:一个类有多个组成部分,例如,成员变量,成员方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。( 解析编译好之后的.class文件 )
    变成时什么情况下才需要加载类,并解剖出类的各个组成部分? 
    当只有一个类的.class文件或不知道类的内部结构的时候,或只知道某个包名下的.class文件并且知道这个类里边大方法名称,需要反射,解析出需要的原有java类的成员变量,成员方法,构造方法等。

2.详解:
2-1.反射的主要步骤:
第一步:先加载类
第二部:解析出所需类型的构造器
第三部:创建解析出来的实体
第四步:根据实体对象解析出实体对象里的成员方法或成员属性

2-2. 加载类:java中有一个Class类用于代表某一个类的字节码,并且提供了加载某个类字节码的方法forName(),forName()方法用于加载某个类的字节码到内存中并使用.class对象进行封装,还有另外两种得到class对象的方式 :
--- 类名.class,
--- 对象.getClass()
例: //1.加载类--直接加载
Class cla=Class.forName("cn.isoftstone.reflect.Student");

//2.加载类--创建对象,调用.getClass
Student stu=new Student();
Class cla1= stu.getClass();

//3.加载类--直接 类名.class
Class cla2=Student.class;

2-3.实例演示:

public class Student {
 
 /**

  *单纯的声明一个变量那么它可以叫做一个字段,当这个字段有get方法返回的时候那么它就可以叫做属性
  * 不声明字段,直接返回生命get方法的时候,例:getEmail()那么Email就是一个属性
  * */
 private String name;
 
 private int sum; //字段
 private String args[];
  
 public String getEmail(){ //属性
  return "zhangsansan@163.com";
 }
 public String getName(){
  return name;
 }
 public Student() {
        //默认不带参数的构造器
 }
 private  Student(List list) {
  //带List参数的构造器
 }

 public Student(String name, int age) {
  //带基本数据类型参数的构造器
 }
 public Student(String str[]) {
  
 }
   
 public Student(String args[],double dou) {
  //带数组参数的构造器
 }
 
 //返回无返回值不带参数的成员方法
 public void study() {
  System.out.println("学习中,请勿打扰 ... ... ");
 }
 
 //无返回值 带参数的成员方法
 public void study(Integer i){
  System.out.println(1);
 }
 
 //带返回值带参数的成员方法
 public int getSum(int a,int b){
  sum=a+b;
  return sum;
 }
   
 //主方法
 public static void main(String[] args) {
  System.out.println("-------");
 }
}


解析Student类的各种情况下的构造方法,Junit测试类:

@Test
public void test1() throws Exception{

//1.加载类
Class cla=Class.forName("cn.isoftstone.reflect.Student");
//2.解析---通过无参数的构造器解析
Constructor constructor=cla.getConstructor(null);
//3.创建类的实例
Student entity=(Student) constructor.newInstance(null);
entity.study();
}

@Test
public void test2() throws Exception{

//1.加载类
Class cla=Student.class;
//2.解析---通过带参数的构造器解析
Constructor constructor=cla.getConstructor(String.class,int.class);
//3.创建类的实例
Student stu=(Student) constructor.newInstance("zhang sansan",90);
stu.study();
System.out.println(stu.getName());
}

@Test
public void test3(){
//怎么知道类中有哪些构造器
Class cla=Student.class;
Constructor csr[]=cla.getConstructors();
for(Constructor c:csr){
System.out.println(c.toGenericString());
}
}

@Test
public void test4()throws Exception{
//解析带数组参数的构造器 ---解析带数组的构造器,不能只有一个参数(jdk1.4 jdk1.5的区别) ...........
/* ---或者参数必须声明在外面 ,把数组强制造型成一个Object对象,如下:
String str[]={"a","b","c"};
Student stu=(Student) con.newInstance((Object)str);
*/
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor constructor=cla.getConstructor(String[].class,double.class);
Student stu=(Student) constructor.newInstance(new String[]{"test","test1","test2"},9.0);
stu.study();
}

@Test
public void test6() throws Exception{
//解析私有构造器,私有方法,私有属性要用getDeclaredConstructor(x.class),getDeclaredMethod(ClassObject)解析
Class cla=Class.forName("cn.isoftstone.reflect.Student");
Constructor con=cla.getDeclaredConstructor(List.class);
con.setAccessible(true); //暴力访问 ,强制修改访问权限

Student stu=(Student) con.newInstance(new ArrayList());

stu.study();
}

@Test
 public void test8() throws Exception{//解析Student类中固定的成员方法
  /**
   *  注:如果解析的是private的私有成员方法,那么解析成员方法的时候要用getDeclaredMethod()方法,
   * 然后Method对象调用setAccessible(true)方法强制执行反射
   * */
  Class cla=Student.class;  
  Student entity=(Student) cla.newInstance();//解析出实体对象的新实例,使用con.newInstance()方法的时候,必须保证Student类中有一个无参的构造方法
  
  //1.解析出所有的成员方法,并遍历
  Method methods[]=cla.getMethods();
  for(Method method:methods){
   System.out.println(method.toGenericString());
  }
  
  //2.解析不带返回值 不带参数的成员方法
  Method mt1=cla.getMethod("study",null); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
  mt1.invoke(entity,null);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
  
  //3.解析不带返回值的成员方法
  Method mt2=cla.getMethod("study",Integer.class); //解析出目标成员方法,第二个参数是待解析方法的参数数据类型
  mt2.invoke(entity, 1);//执行解析出的成员方法,第一个参数是方法对应的实体对象,第二个参数是给待解析方法传的值
  
  //4.解析带返回值 带参数的成员方法
  Method mt3=cla.getMethod("getSum",int.class,int.class);
  Object obj=mt3.invoke(entity, 2,3);//返回的是一个Object
  System.out.println(obj);
  
  /**解析主函数main函数  
   * jdk1.4 -- main(String args[])当做数组来处理
   * jdk1.5 -- main(String...str )当做可变参数来处理
   * */  
  Method mt4=cla.getMethod("main",String[].class);  
  mt4.invoke(entity, new Object[]{new String[]{"aa"}});
  
  /*或  String args[]={};
       mt4.invoke(entity, (Object)args);
   */  
 }
 
 
 @Test
 public void test9() throws Exception{ // 解析成员属性或字段,注,解析的成员属性必须是定义好的
  Class cla=Class.forName("cn.isoftstone.reflect.Student");
  Student entity=(Student) cla.newInstance();
  
  //1.解析所有的成员属性,解析私有的成员属性调用getDeclaredFields()方法,然后强制执行
  Field fields[]=cla.getDeclaredFields();
  for(Field field:fields){
   field.setAccessible(true);//强制执行
   System.out.println(field.getName());
  }
  
  //2.解析并操作字段或属性---例:赋值
  Field fd1=cla.getDeclaredField("name");
  fd1.setAccessible(true);
  fd1.set(entity, "zhangsansan");//赋值
  //System.out.println(stu.getName());//直接通过实体对象的get方法获取值---X
  String value=(String) fd1.get(entity);//通过实体对象获取值
  System.out.println(value);
 }