1:什么是反射机制?反射机制的应用场景有哪些?
        反射机制介绍JAVA 反射机制是在运行状态中,        对于任意一个类,都能够知道这个类的所有属性和方法;        对于任意一个对象,都能够调用它的任意一个方法和属性;        这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。    静态编译和动态编译    静态编译:在编译时确定类型,绑定对象    动态编译:运行时确定类型,绑定对象    反射机制优缺点优点:         运行期类型的判断,动态加载类,提高代码灵活度。    缺点:         性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。    反射是框架设计的灵魂    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,    但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关;    1: 我们在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序;    2:Spring 框架也用到很多反射机制,最经典的就是 xml 的配置模式。
2:反射的作用
    使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)    反射就是把java类中的各种成分映射成一个个的Java对象    例如:一个类有:    构造方法、成员变量、成员方法、包等等信息,    利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。         (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)      主要分为以下:        1:获取Class对象的方法        2:获取构造方法        3:获取成员变量        4:获取成员方法        5:通过反射运行配置文件内容        6:通过反射越过泛型检查
3:反射的加载 与 Class类的描述
    如图是类的正常加载过程:反射的原理在与class对象。    加载的时候:将class文件读入内存,并为之创建一个Class对象。    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。    也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)    Class 没有公共构造方法。    Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。    也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。


4:获取Class对象的三种方式
在运行期间,一个类,只有一个Class对象产生。三种方式常用第三种:     第一种:对象都有了还要反射干什么。     第二种:需要导入类的包,依赖太强,不导包就抛编译错误。     第三种:一个字符串可以传入也可写在配置文件中等多种方法。
/** * 获取Class对象的三种方式 * 1 Object ——> getClass(); * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性 * 3 通过Class类的静态方法:forName(String  className)(常用) * */public class ClassDemo {    public static void main(String[] args) {        //第一种方式获取Class对象         //这一new 产生一个Student对象,一个Class对象。        Student stu1 = new Student();        //获取Class对象        Class stuClass1 = stu1.getClass();        System.out.println(stuClass1.getName());        //第二种方式获取Class对象        Class stuClass2 = Student.class;        //判断第一种方式获取的Class对象和第二种方式获取的是同一个        System.out.println(stuClass1 == stuClass2);        //第三种方式获取Class对象        try {             //注意此字符串必须是真实路径,就是带包名的类路径,包名.类名            Class stuClass3 = Class.forName("base.model.entity.Student");            //判断三种方式获取的是同一个Class对象            System.out.println(stuClass3 == stuClass2);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }            }}
5:获取Class对象的构造方法 并 调用
package base.model.entity ;public class Student {    //---------------构造方法-------------------        //无参构造方法    public Student(){        System.out.println("调用了公有、无参构造方法执行了。。。");    }    //私有构造方法    private Student(int age){        System.out.println("私有的构造方法   年龄:"+ age);    }     //(默认的构造方法)    Student(String str){        System.out.println("(默认)的构造方法 s = " + str);    }    //受保护的构造方法    protected Student(boolean n){        System.out.println("受保护的构造方法 n = " + n);    }   //有一个参数的构造方法    public Student(char name){        System.out.println("姓名:" + name);    }    //有多个参数的构造方法    public Student(String name ,Integer age){        System.out.println("姓名:"+name+"年龄:"+ age);    }}
import java.lang.reflect.Constructor; /* * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员; *  * 1.获取构造方法: *         1).批量的方法: *         所有"公有的"构造方法 *             public Constructor[] getConstructors() *        获取所有的构造方法(包括私有、受保护、默认、公有) *        public Constructor[] getDeclaredConstructors() *    *         2).获取单个的方法,并调用:        *         获取单个的"公有的"构造方法: *             public Constructor getConstructor(Class... parameterTypes) *         获取某个构造方法(私有的,或受保护、默认、公有) *             public Constructor getDeclaredConstructor(Class... parameterTypes): *          *             调用构造方法: *             Constructor-->newInstance(Object... initargs) */public class Constructors {    public static void main(String[] args) throws Exception {        //1.加载Class对象        Class clazz = Class.forName("base.model.entity.Student");        //2.获取所有公有构造方法        Constructor[] pubConArray = clazz.getConstructors();        for(Constructor c : pubConArray){            System.out.println(c);        }        //3.获取所有的构造方法(包括私有、受保护、默认、公有)        Constructor[] allConArray = clazz.getDeclaredConstructors();        for(Constructor c : allConArray){            System.out.println(c);        }        //获取公有、无参的构造方法        //1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型        //2>、返回的是描述这个无参构造函数的类对象。        Constructor con = clazz.getConstructor(null);                System.out.println("con = " + con);        //调用构造方法        Object obj = con.newInstance();        System.out.println("******************获取    某个构造方法 并调用*******************************");        con = clazz.getDeclaredConstructor(char.class);        System.out.println("con = " +con);        //调用构造方法        //暴力访问(忽略掉访问修饰符)        con.setAccessible(true);        obj = con.newInstance('hesuijin');    }    }//控制台打印结果**********************所有公有构造方法*********************************public base.model.entity.Student()public base.model.entity.Student(char)public base.model.entity.Student(java.lang.String,java.lang.Integer)************所有的构造方法(包括:私有、默认、受保护、公有)***************public base.model.entity.Student()private base.model.entity.Student(int)          base.model.entity.Student(java.lang.String)protected base.model.entity.Student(booleanpublic base.model.entity.Student(char))public base.model.entity.Student(java.lang.String,int)*****************获取公有、无参的构造方法*******************************con = public base.model.entity.Student()调用了公有、无参构造方法执行了。。。******************获取私有构造方法,并调用*******************************con = public base.model.entity.Student(char)姓名:hesuijin
6:获取成员变量并调用
package base.model.field;@Datapublic class Student {    public Student(){    }    //**********字段*************//    public String name;    protected int age;    char sex;    private String phone;}import java.lang.reflect.Field;/* * 获取成员变量并调用: *  * 1.批量的 *      获取所有的"公有字段" *         1).Field[] getFields() *     获取所有字段,包括:私有、受保护、默认、公有; *         2).Field[] getDeclaredFields() * * 2.获取单个的: *         1).public Field getField(String fieldName) *         2).public Field getDeclaredField(String fieldName) *  *      设置字段的值: *         Field --> public void set(Object obj,Object value): *                     参数说明: *                     1.obj:要设置的字段所在的对象; *                     2.value:要为字段设置的值; *  */public class Fields {        public static void main(String[] args) throws Exception {            //1.获取Class对象            Class stuClass = Class.forName("base.model.field.Student");            //2.获取字段            System.out.println("************获取所有公有的字段********************");            Field[] fieldArray = stuClass.getFields();            for(Field f : fieldArray){                System.out.println(f);            }            System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");            fieldArray = stuClass.getDeclaredFields();            for(Field f : fieldArray){                System.out.println(f);            }           //获取一个对象           //产生Student对象--》Student stu = new Student();            Object obj = stuClass.getConstructor().newInstance();            System.out.println("*************获取公有字段**并调用***********************************");            Field f = stuClass.getField("name");            System.out.println(f);            //为字段设置值           //为Student对象中的name属性赋值--》stu.name = "刘德华"            f.set(obj, "刘德华");            //验证            Student stu = (Student)obj;            System.out.println("验证姓名:" + stu.name);            System.out.println("**************获取私有字段****并调用********************************");            f = stuClass.getDeclaredField("phone");            System.out.println(f);            //暴力反射,解除私有限定            f.setAccessible(true);            f.set(obj, "18718747777");            System.out.println("验证电话:" + stu.phone);        }    }控制台输出*************获取公有字段**并调用***********************************public java.lang.String base.model.field.Student.name验证姓名:刘德华**************获取私有字段****并调用********************************private java.lang.String base.model.field.Student.phone验证电话:18718747777
7:获取成员方法并调用
package base.model.method ;public class Student {    //**************成员方法***************//    public void show1(String s){        System.out.println("调用了:公有的,String参数的show1(): s = " + s);    }    protected void show2(){        System.out.println("调用了:受保护的,无参的show2()");    }    void show3(){        System.out.println("调用了:默认的,无参的show3()");    }    private String show4(int age){        System.out.println("调用了:私有的,并且有返回值的,int参数的show4(): age = " + age);        return "我是返回值";    }}import java.lang.reflect.Method;/* * 获取成员方法并调用: * 1.批量的: *      获取所有"公有方法";(包含了父类的方法也包含Object类) *         public Method[] getMethods() *     获取所有的成员方法,包括私有的(私有、受保护、默认、公有)(不包括继承的) *         public Method[] getDeclaredMethods() * * 2.获取单个的: *         public Method getMethod(String name,Class<?>... parameterTypes): *                     参数: *                         name : 方法名; *                         Class ... : 形参的Class类型对象 *         public Method getDeclaredMethod(String name,Class<?>... parameterTypes) *  *      调用方法: *         Method --> public Object invoke(Object obj,Object... args): *                     参数说明: *                     obj : 要调用方法的对象; *                     args:调用方式时所传递的实参;): */public class MethodDemo {    public static void main(String[] args) throws Exception {        //1.获取Class对象        Class stuClass = Class.forName("base.model.method.Student");        //2.获取所有公有方法        System.out.println("***************获取所有的”公有“方法*******************");        stuClass.getMethods();        Method[] methodArray = stuClass.getMethods();        for(Method m : methodArray){            System.out.println(m);        }        System.out.println("***************获取所有的方法,包括私有的*******************");        methodArray = stuClass.getDeclaredMethods();        for(Method m : methodArray){            System.out.println(m);        }       //实例化一个Student对象        Object obj = stuClass.getConstructor().newInstance();        Method mehtod;        System.out.println("***************获取公有的show1()方法*******************");        m = stuClass.getMethod("show1", String.class);         //需要两个参数,一个是要调用的对象(获取有反射),一个是实参        System.out.println(m);                m.invoke(obj, "刘德华");        System.out.println("***************获取私有的show4()方法******************");        m = stuClass.getDeclaredMethod("show4", int.class);        System.out.println(m);        //暴力反射,解除私有限定        m.setAccessible(true);        //需要两个参数,一个是要调用的对象(获取有反射),一个是实参        Object result = m.invoke(obj, 20);        System.out.println("返回值:" + result);            }}控制台输出***************获取公有的show1()方法*******************public void fanshe.method.Student.show1(java.lang.String)调用了:公有的,String参数的show1(): s = 刘德华***************获取私有的show4()方法******************private java.lang.String fanshe.method.Student.show4(int)调用了,私有的,并且有返回值的,int参数的show4(): age = 20返回值:我是返回值
8:反射方法的其它使用之—-通过反射运行配置文件内容
public class Student {    public void show(){        System.out.println("is show()");    }}//配置文件以txt文件为例子(properties.txt):className = base.model.property.StudentmethodName = show/* * 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改 * 我们只需要将新类发送给客户端,并修改配置文件即可 */public class Demo {    public static void main(String[] args) throws Exception {        //1:通过反射获取Class对象        //"base.model.property.Student"        Class stuClass = Class.forName(getValue("className"));        //2:获取show()方法        //show        Method m = stuClass.getMethod(getValue("methodName"));        //3:调用show()方法        m.invoke(stuClass.getConstructor().newInstance());    }    //此方法接收一个key,在配置文件中获取相应的value    public static String getValue(String key) throws IOException{        //获取配置文件的对象        Properties pro = new Properties();        //获取输入流        FileReader fr = new FileReader("properties.txt");        //将流加载到配置文件对象中        pro.load(fr);        fr.close();        //返回根据key获取的value值        return pro.getProperty(key);    }}
9:反射方法的其它使用之—-通过反射越过泛型检查
/* * 通过反射越过泛型检查 *  * 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值? */public class Demo {    public static void main(String[] args) throws Exception{        ArrayList<String> strList = new ArrayList<>();        strList.add("string");        //    strList.add(100);        //获取ArrayList的Class对象,反向的调用add()方法,添加数据        Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象        //获取add()方法        Method m = listClass.getMethod("add", Object.class);        //调用add()方法        m.invoke(strList, 100);        //遍历集合        for(Object obj : strList){            System.out.println(obj);        }    }}