Java学习笔记54(反射详解)

反射概念:

java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法

对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制

实际作用:

已经完成一个java程序,但是想再添加新功能,又不能修改源码,这时候就用到反射机制了

获取class文件的三种方式:

简单地自定义一个Person类:

package demo;public class Person {    public String name;    private int age;    public Person() {    }    public Person(String name, int age) {        this.name = name;        this.age = age;    }    private Person(int age, String name) {        this.name = name;        this.age = age;    }    public void eat() {        System.out.println("人吃饭");    }    public void sleep(String s, int a, double d) {        System.out.println("人在睡觉" + s + "....." + a + "....." + d);    }    private void playGame() {        System.out.println("人在打游戏");    }    public String toString() {        return "Person [name=" + name + ", age=" + age + "]";    }    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;    }}

View Code

获取person类class文件(三种方法本质上获取的是同一个对象):

package demo;public class ReflectDemo {    public static void main(String[] args) {        //1.对象获取        Person p = new Person();        Class c = p.getClass();        System.out.println(c);        //2.类名获取        Class c1 = Person.class;        System.out.println(c1);                System.out.println(c==c1);//true        System.out.println(c.equals(c1));//true        //只存在一个class文件,两种方式都是获得同一个对象                //3.Class类的静态方法,参数注意带着包名防止重名        try {            Class c2 =     Class.forName("demo.Person");            System.out.println(c2);        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }}

反射获取空参构造方法:

package demo;import java.lang.reflect.Constructor;public class ReflectDemo {    public static void main(String[] args) throws ClassNotFoundException {        Class c = Class.forName("demo.Person");        function1(c);        function2(c);    }    private static void function1(Class c) {        // 获得所有公共权限(public)的构造器        Constructor[] cons = c.getConstructors();        for (Constructor con : cons) {            System.out.println(con);            // 输出:            // public demo.Person(java.lang.String,int)            // public demo.Person()        }    }    public static void function2(Class c) {        // 获取空参构造器并执行(toString方法)        try {            Constructor con = c.getConstructor();            Object obj = con.newInstance();            System.out.println(obj);            // 输出:Person [name=null, age=0]        } catch (Exception ex) {            ex.printStackTrace();        }    }}

反射获取有参构造方法:

package demo;import java.lang.reflect.Constructor;public class ReflectDemo {    public static void main(String[] args) throws Exception {        Class c = Class.forName("demo.Person");        Constructor con = c.getConstructor(String.class, int.class);        System.out.println(con);        Object object = con.newInstance("张三", 20);        System.out.println(object);    }}/*输出:public demo.Person(java.lang.String,int)Person [name=张三, age=20]*/

发现上边的方式代码量偏大,快捷一些的方式:

前提:被反射的类,必须具有空参构造方法,且构造方法权限必须是public

package demo;public class ReflectDemo {    public static void main(String[] args) throws Exception {        Class c = Class.forName("demo.Person");        // Class类中定义方法, T newInstance() 直接创建被反射类的对象实例        Object obj = c.newInstance();        System.out.println(obj);    }}

反射获取私有构造方法(日常开发不建议使用,这种方法了解即可):

package demo;import java.lang.reflect.Constructor;public class ReflectDemo {    public static void main(String[] args) throws Exception {        Class c = Class.forName("demo.Person");        // 获取所有构造方法(包括私有的)        // Constructor[] cons = c.getDeclaredConstructors();        Constructor con = c.getDeclaredConstructor(int.class, String.class);        con.setAccessible(true);// 取消权限,破坏了封装性        Object object = con.newInstance(18, "张三");        System.out.println(object);        // Person [name=张三, age=18]    }}

反射获取类的成员变量并修改:

package demo;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class ReflectDemo {    public static void main(String[] args) throws Exception {        Class c = Class.forName("demo.Person");        // 获得所有public成员        Field[] fields = c.getFields();        // 获得所有成员变量        Field[] fields2 = c.getDeclaredFields();        for (Field field : fields2) {            System.out.println(field);        }        // 获取指定成员变量并修改        Field field = c.getField("name");        Object object = c.newInstance();        field.set(object, "张三");        System.out.println(object);        // 输出:Person [name=张三, age=0]    }}

反射获取成员方法并执行:

package demo;import java.lang.reflect.Method;public class ReflectDemo {    public static void main(String[] args) throws Exception {        Class c1 = Class.forName("demo.Person");        // 获得所有public方法        /*         * Method[] methods = c1.getMethods();          * for(Method method:methods){         * System.out.println(method); }         */        // 获取指定方法运行(空参)        Method method = c1.getMethod("eat");        Object obj = c1.newInstance();        method.invoke(obj);        // 输出:人吃饭        // 有参        Method method1 = c1.getMethod("sleep", String.class, int.class, double.class);        Object obj1 = c1.newInstance();        method1.invoke(obj1, "休息", 10, 10.11);        // 输出:人在睡觉休息.....10.....10.11        // 可以利用前面提到的方法暴力运行私有方法    }}

反射的泛型擦除:

package demo;import java.lang.reflect.Method;import java.util.ArrayList;public class ReflectTest {    public static void main(String[] args) throws Exception {        ArrayList<String> array = new ArrayList<String>();        // 通常添加方式        array.add("a");        array.add("1");        Class class1 = array.getClass();        Method method = class1.getMethod("add", Object.class);        method.invoke(array, 100);        method.invoke(array, 666.666);        method.invoke(array, 0.1);        System.out.println(array);        // 输出:[a, 1, 100, 666.666, 0.1]    }}

反射实现通过配置文件运行:

有时候想改源码,但是不能改源码,可以这样做:

自定义三个类:

package demo;public class Person {    public void eat(){        System.out.println("人在吃饭");    }}

View Code

package demo;public class Student {    public void study(){        System.out.println("学生在学习");    }}

View Code

package demo;public class Worker {    public void job(){        System.out.println("上班族在工作");    }}

View Code

配置文件:config.properties

#className=demo.Student#methodName=studyclassName=demo.PersonmethodName=eat#className=demo.Worker#methodName=job

测试类:

package demo;import java.io.FileReader;import java.lang.reflect.Method;import java.util.Properties;/* *  调用Person方法,调用Student方法,调用Worker方法 *  类不清楚,方法也不清楚 *  通过配置文件实现此功能 *    运行的类名和方法名字,以键值对的形式,写在文本中 *    运行哪个类,读取配置文件即可 *  实现步骤: *    1. 准备配置文件,键值对 *    2. IO流读取配置文件  Reader *    3. 文件中的键值对存储到集合中 Properties *        集合保存的键值对,就是类名和方法名 *    4. 反射获取指定类的class文件对象 *    5. class文件对象,获取指定的方法 *    6. 运行方法 */public class Test {    public static void main(String[] args) throws Exception{        //IO流读取配置文件        FileReader r = new FileReader("config.properties");        //创建集合对象        Properties pro = new Properties();        //调用集合方法load,传递流对象        pro.load(r);        r.close();        //通过键获取值        String className = pro.getProperty("className");        String methodName = pro.getProperty("methodName");        //反射获取指定类的class文件对象        Class c = Class.forName(className);        Object obj = c.newInstance();        //获取指定的方法名        Method method = c.getMethod(methodName);        method.invoke(obj);    }}

在爱情里,有时候简单的一句话,能胜过千言万语。

Java学习笔记54(反射详解)

相关文章:

你感兴趣的文章:

标签云: