第8章 反射

反射是动态语言的关键.

为什么需要反射呢?

一个已经开发完全的程序,如果需要对功能进行升级、更新,虽然可以通过修改源代码进行编写,从而升级java程序的功能.但实际开发的时候这并不是一个好的办法.

实际开发中,不会去修改原先的程序代码,而是创建一个新类,将升级的功能封装在新类的方法中,通过反射来解刨这个心累的class文件,然后去调用新类的成员和方法.

获取Class类对象

例子:

public class Person {//创建一个Person类
    public String name;
    public    int id;
    public  Person()//无参构造方法
    {
    }
    public Person(String name, int id) {
        super();
        this.name = name;
        this.id = id;
    }


    public void display() {
        System.out.println("姓名为:"+name+"id为:"+id);
    }
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo {

    public static void main(String args[]) throws Exception {
    //获取Class类的对象的三种方法 通过类名.class、对象名.getClass()、forName方法来获取类的对象
    Class class1=Person.class;
Person p1
=new Person("小张",1); Class class2=p1.getClass(); Class class3=Class.forName("反射练习.Person"); //每一个类都存在一个类对象,用于描述该类有什么方法、成员 System.out.println(class1); }
}

Class类对象创建常用类对象:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo {

    public static void main(String args[]) throws Exception {
    //获取Class类的对象的三种方法 通过类名、对象名、forName方法来获取类的对象
    Class class1=Person.class;
    Person p1=new Person("小张",1);
    Class class2=p1.getClass();
    Class class3=Class.forName("反射练习.Person");
    //每一个类都存在一个类对象,用于描述该类有什么方法、成员
    
    System.out.println(class1);
    
    
    //用Class对象来创建新的对象
    //第一步:首先先获取Constructor对象,这是该类的公共构造函数
    Constructor con1=class1.getConstructor(); //获取该类的无参构造函数.
    Constructor con2=class2.getConstructor(String.class,int.class);//这是获取该类的有参构造函数在getConstructor方法括号中加上构造方法参数类型.class;
    //使用con1获取的无参构造函数来创建对象 使用Constructor类的newInstance方法.
    Person p2=(Person) con1.newInstance();//想获得无参构造函数的时候,如果想获取的无参构造函数是隐式的会发生错误,需要将无参构造函数添加进类
    p2.id=20;
    p2.name="小张";
    p2.display();
    //newInstance方法返回的是Object对象,所以需要强制类型转换
    //Constructor是用于存储构造方法的类型.
    //使用 con2获取的有参构造函数来创建对象 
    Person p3=(Person) con2.newInstance("小李",30);
    p3.display();
    System.out.println(p2+""+p3);
}
}

获取和设置成员变量

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo {

    public static void main(String args[]) throws Exception {
    //获取Class类的对象的三种方法 通过类名、对象名、forName方法来获取类的对象
    Class class1=Person.class;
    Person p1=new Person("小张",1);
    Class class2=p1.getClass();
    Class class3=Class.forName("反射练习.Person");
    //每一个类都存在一个类对象,用于描述该类有什么方法、成员
    
    System.out.println(class1);
    
    
    //用Class对象来创建新的对象
    //第一步:首先先获取Constructor对象,这是该类的公共构造函数
    Constructor con1=class1.getConstructor(); //获取该类的无参构造函数.
    Constructor con2=class2.getConstructor(String.class,int.class);//这是获取该类的有参构造函数在getConstructor方法括号中加上构造方法参数类型.class;
    //使用con1获取的无参构造函数来创建对象 使用Constructor类的newInstance方法.
    Person p2=(Person) con1.newInstance();//想获得无参构造函数的时候,如果想获取的无参构造函数是隐式的会发生错误,需要将无参构造函数添加进类
    p2.id=20;
    p2.name="小张";
    p2.display();
    //newInstance方法返回的是Object对象,所以需要强制类型转换
    //Constructor是用于存储构造方法的类型.
    //使用 con2获取的有参构造函数来创建对象 
    Person p3=(Person) con2.newInstance("小李",30);
    p3.display();
    System.out.println(p2+""+p3);
    
    //获取和设置成员变量
    //Field用于存储成员变量信息   Class的getFields方法能够获取公有成员变量信息(如果想要获得私有字段的名称 得使用getDeclared-Fields()方法)
    Field[] filed1=class1.getFields();
    for(Field filed:filed1)//加强型for循环,即for-each循环 for(数据类型 变量名:数组、集合名){ \执行语句  }
    {
        System.out.println(filed.getName()); //Field的getName方法获得字段的名称
    }
    //那如何设置某个字段的值呢?
    Constructor con3=class1.getConstructor();//获取无参构造函数
    
    
    Object obj=con3.newInstance();//新建一个Object类型的变量来指向con3所存储的构造函数所新建的对象
    
    Field name=class1.getField("name");//获得name的Field类的对象
    name.set(obj, "张三");//这个时候name获取    //值为想要设置的字段的Field类型的对象.set(想要设置成员属性所属的对象,属性值);
    
    Field id=class1.getField("id");
    id.set(obj, 02);
    
    System.out.println(name.get(obj)+" "+id.get(obj));
    
  }
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo {

    public static void main(String args[]) throws Exception {
    //获取Class类的对象的三种方法 通过类名、对象名、forName方法来获取类的对象
    Class class1=Person.class;
    Person p1=new Person("小张",1);
    Class class2=p1.getClass();
    Class class3=Class.forName("反射练习.Person");
    //每一个类都存在一个类对象,用于描述该类有什么方法、成员
    
    System.out.println(class1);
    
    
    //用Class对象来创建新的对象
    //第一步:首先先获取Constructor对象,这是该类的公共构造函数
    Constructor con1=class1.getConstructor(); //获取该类的无参构造函数.
    Constructor con2=class2.getConstructor(String.class,int.class);//这是获取该类的有参构造函数在getConstructor方法括号中加上构造方法参数类型.class;
    //使用con1获取的无参构造函数来创建对象 使用Constructor类的newInstance方法.
    Person p2=(Person) con1.newInstance();//想获得无参构造函数的时候,如果想获取的无参构造函数是隐式的会发生错误,需要将无参构造函数添加进类
    p2.id=20;
    p2.name="小张";
    p2.display();
    //newInstance方法返回的是Object对象,所以需要强制类型转换
    //Constructor是用于存储构造方法的类型.
    //使用 con2获取的有参构造函数来创建对象 
    Person p3=(Person) con2.newInstance("小李",30);
    p3.display();
    System.out.println(p2+""+p3);
    
    //获取和设置成员变量
    //Field用于存储成员变量信息   Class的getFields方法能够获取公有成员变量信息(如果想要获得私有字段的名称 得使用getDeclared-Fields()方法)
    Field[] filed1=class1.getFields();
    for(Field filed:filed1)//加强型for循环,即for-each循环 for(数据类型 变量名:数组、集合名){ \执行语句  }
    {
        System.out.println(filed.getName()); //Field的getName方法获得字段的名称
    }
    //那如何设置某个字段的值呢?
    Constructor con3=class1.getConstructor();//获取无参构造函数
    
    
    Object obj=con3.newInstance();//新建一个Object类型的变量来指向con3所存储的构造函数所新建的对象
    
    Field name=class1.getField("name");//获得name的Field类的对象
    name.set(obj, "张三");//这个时候name获取    //值为想要设置的字段的Field类型的对象.set(想要设置成员属性所属的对象,属性值);
    
    Field id=class1.getField("id");
    id.set(obj, 02);
    
    System.out.println(name.get(obj)+" "+id.get(obj));
    
    
    //Class类如何获取和调用方法?
    Method method1=class1.getMethod("display");//1、获取指定字符串的方法,//如果想获取的方法需要参数,方法名后面就跟上 参数类型.class 用逗号分隔
    Object object1= con2.newInstance("小张",03);//2、使用con2存储的有参构造函数来创建一个Object对象
    method1.invoke(object1);//执行无参的方法,如果该方法需要参数,直接按照顺序将参数用逗号分隔加上即可.
        
    }
    }

课后习题:

1、获取Class类的常用方法是什么?

有三种,1、通过类名.class来获得Class类对象

   2、通过该类型的对象.getClass()方法来获取该类型的Class类对象

      3、使用Class.forName("包名.类名")方法来获取字符串中描述的类Class类对象

2、如何获取Class类的构造方法?

使用getConstructor()方法,如果想获取无参构造函数,则不需要填写参数,如果想获取有参数的构造函数,括号中需要class.参数类型 多个参数类型之间使用逗号分隔.

原文地址:https://www.cnblogs.com/youjunhui/p/14905323.html