zoukankan      html  css  js  c++  java
  • 反射(反射、获取成员变量、构造方法、成员方法)

    1、反射

    (1)概念:

    反射:将类的各个组成部分封装为对象,对于任何一个实体类,都能够知道这个类的属性和方法,对于任意一个对象,都能够调用它的任意方法和属性。

    (2)好处:

             可以在程序运行的过程中,操作这些对象。

             解耦,提高可扩展性。

    (3)获取Class对象的三种方法:

    Class.forname("包名.类名");此方式用于配置文件方式,通过配置文件加载类名。

    类名.class,多用于参数传递。

    对象.getClass(),用于对象获取字节码对象的方式。

    (4)三种方法获取Class对象:

    Person类:

    package pers.reflect.person;
    
    public class Person {
    private String name;
    private int age;
    public Person(){
        
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    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;
    }
    
    }

    测试类:

    import pers.reflect.person.Person;
    
    public class ReflectDemo {
        public static void main(String[] args) throws Exception {
            Class c1 = Class.forName("pers.reflect.person.Person");
            System.out.println("c1 = " + c1);
    
            Class c2 = Person.class;
            System.out.println("c2 = " + c2);
    
            Person p1 = new Person();
            Class c3 = p1.getClass();
            System.out.println("c3 = " + c3);
            System.out.println(c1==c2);
            System.out.println(c2==c3);
            System.out.println(c1==c3);
    
        }
    }

    通过程序运行结果可以看出,不管通过哪种方式,获取的字节码文件对象是同一个。也就是说,运行期间,一个类只产生一个Class对象。

     2、Class对象获取成员变量

    (1)Class类的常用方法(获取Field对象):

    创建Person类:

    package pers.reflect.person;
    
    public class Person {
    private String name;
    private int age;
    public String hobby;
    public String height;
    protected String sex;
    String address;
    
    public Person(){
        
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    
    
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
                + ", height=" + height + ", sex=" + sex + ", address=" + address
                + "]";
    }
    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;
    }
    
    }
    import java.lang.reflect.Field;
    
    import pers.reflect.person.Person;
    
    public class ReflectDemo {
    
        public static void main(String[] args) throws SecurityException,
                NoSuchFieldException, IllegalArgumentException,
                IllegalAccessException {
    
            Class c = Person.class;
            System.out.println("getFields(),获取公共的成员变量:");
            Field[] fields = c.getFields();
            for (Field field : fields) {
                System.out.println(field);
            }
    
            System.out.println("getField(),获取指定的公共的成员变量:");
    
            Field hobbyField = c.getField("hobby");
            System.out.println(hobbyField);
    
            System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。");
    
            Field[] fields1 = c.getDeclaredFields();
            for (Field field : fields1) {
                System.out.println(field);
            }
    
            System.out.println("获取私有的指定的成员变量");
    
            Field nameField = c.getDeclaredField("age");
    
            System.out.println(nameField);
    
        }
    }

    (2)Field类的常用方法:

    返回变量的类型:

    返回属性的名字:

    import java.lang.reflect.Field;
    
    import pers.reflect.person.Person;
    
    
    public class ReflectDemo1 {
    public static void main(String[] args) {
        Class c = Person.class;
        System.out.println("getDeclaredFields(),获取所有的成员变量,与修饰符无关。");
        System.out.println();
    
        Field[] fields1 = c.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println("成员变量:"+field);
            System.out.println("属性的类型:"+field.getType());
            System.out.println("属性的名字:"+field.getName());
            System.out.println();
        }
    }
    }

    import java.lang.reflect.Field;
    
    import pers.reflect.person.Person;
    
    
    public class ReflectDemo2 {
    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Class c = Person.class;
        System.out.println("getField(),获取指定的公共的成员变量:");
        Field hobbyField = c.getField("hobby");
        System.out.println(hobbyField);
        Person p=new Person();
        Object value=hobbyField.get(p);
        System.out.println(value);
        hobbyField.set(p, "张可可");
        System.out.println(p);
        System.out.println();
    }
    }

    访问不是被public修饰的成员变量(要用暴力反射,否者无法访问):

    import java.lang.reflect.Field;
    
    import pers.reflect.person.Person;
    
    public class ReflectDemo3 {
        public static void main(String[] args) throws SecurityException,
                NoSuchFieldException, IllegalArgumentException,
                IllegalAccessException {
            Class c = Person.class;
            Field nameField = c.getDeclaredField("name");
            nameField.setAccessible(true);//暴力反射
            System.out.println(nameField);
            Person p = new Person();
            Object value = nameField.get(p);
            System.out.println(value);
            nameField.set(p, "赵晓霞");
            System.out.println(p);
        }
    }
    setAccessible(true);忽略权限修饰符的安全检查。

    3、获取构造方法
    package pers.reflect.Constructor;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    import pers.reflect.person.Person;
    
    public class ReflectDemo1 {
    public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
    InstantiationException, IllegalAccessException, InvocationTargetException { Class c = Person.class; System.out.println("getDeclaredConstructors(),获取所有的构造方法:"); Constructor[] cons = c.getDeclaredConstructors(); for (Constructor con : cons) { System.out.println(con); } System.out.println(); System.out.println("getConstructors(),获取所有的构造方法:"); Constructor[] cons1 = c.getConstructors(); for (Constructor con : cons1) { System.out.println(con); } System.out.println(); Constructor con=c.getConstructor(String.class,int.class); Object p=con.newInstance("张珊珊",12); System.out.println(p); Constructor con1=c.getConstructor();//空参数的构造方法创建Person类对象 Object p1=con1.newInstance(); System.out.println(p1); } }

     4、获取成员方法

    (1)常用方法:

     public Method getMethod(String name, Class<?>... parameterTypes)   获取Public修饰的一个方法

     public Method getDeclaredMethod(String name, Class<?>... parameterTypes)  获取所有权限的一个方法

     public Method[] getMethods()                      本类与父类中所有public 修饰的方法所有方法

    public Method[] getDeclaredMethods()          获取本类中所有的方法

    (2)应用:           

    package pers.reflect.person;
    
    public class Person {
    private String name;
    private int age;
    public String hobby;
    public String height;
    protected String sex;
    String address;
    
    public Person(){
        
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    
    protected  void sports() {
        System.out.println("我爱运动");
    }
    private  void sport() {
        System.out.println("我不爱运动");
    }
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", hobby=" + hobby
                + ", height=" + height + ", sex=" + sex + ", address=" + address
                + "]";
    }
    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;
    }
    public void study(String name){
        System.out.println(name+"爱学习");
    }
    }

    获取公共的空参的成员方法:

    package pers.reflect.method;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.rmi.StubNotFoundException;
    
    import pers.reflect.person.Person;
    
    public class reflectDemo {
        public static void main(String[] args) throws SecurityException,
                NoSuchMethodException, IllegalArgumentException,
                IllegalAccessException, InvocationTargetException {
            Class c = Person.class;
            Method study_method = c.getMethod("study");
            Person p = new Person();
            study_method.invoke(p);
        }
    }

    获取公共的带参数的成员方法:

    package pers.reflect.method;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import pers.reflect.person.Person;
    
    public class reflectDemo {
        public static void main(String[] args) throws SecurityException,
                NoSuchMethodException, IllegalArgumentException,
                IllegalAccessException, InvocationTargetException {
            Class c = Person.class;
            Method study_method1 = c.getMethod("study",String.class);
            Person p = new Person();
            study_method1.invoke(p,"Tom");
        }
    }

    获取所有的公共的方法:

    package pers.reflect.method;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import pers.reflect.person.Person;
    
    public class reflectDemo {
        public static void main(String[] args) throws SecurityException,
                NoSuchMethodException, IllegalArgumentException,
                IllegalAccessException, InvocationTargetException {
            Class c = Person.class;
            Method[] methods = c.getMethods();
            for (Method method:methods){
                System.out.println(method);
            }
        }
    }

    获取方法名字:

    package pers.reflect.method;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import pers.reflect.person.Person;
    
    public class reflectDemo {
        public static void main(String[] args) throws SecurityException,
                NoSuchMethodException, IllegalArgumentException,
                IllegalAccessException, InvocationTargetException {
            Class c = Person.class;
            Method[] methods = c.getMethods();
        for(Method method:methods){
            System.out.println(method.getName());
        }
        }
    }

    获取所有的方法(忽略权限修饰符):

    package pers.reflect.method;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import pers.reflect.person.Person;
    
    public class reflectDemo {
        public static void main(String[] args) throws SecurityException,
                NoSuchMethodException, IllegalArgumentException,
                IllegalAccessException, InvocationTargetException {
            Class c = Person.class;
            Method[] methods = c.getDeclaredMethods();
            
        for(Method method:methods){
            method.setAccessible(true);
            System.out.println(method);
        }
        }
    }

     5、反射的好处(转载自博客园:https://www.cnblogs.com/bihanghang/p/9992237.html

    我们在第一次接触反射的时候,总会有个很大的疑问,反射看起来好麻烦啊,各种get.get,他究竟有什么好处,能用来做什么呢?

    我们先来看一下《编程思想》这本书中是怎么说的.

    RTTI和反射之间真正的区别只在于,对RTTI来说,编译器在在编译时打开和检查.class文件.(换句话说,我们可以用"普通"方式调用对象的所有方法).对于反射机制来说,.class文件在编译时是不可获取的,所以在运行时打开和检查.class文件。 --《编程思想》

      这段话看起来很叼的样子,有点云里雾里的,首先RTTI的意思就是以普通的方式来创建对象,调用方法,就是我们常用的new关键字。这段话的意思简化版就是:编译器将.java文件编译成.class文件之后,普通方式创建的对象就不能再变了,我只能选择是运行还是不运行这个.class文件。是不是感觉很僵硬,假如现在我有个写好的程序已经放在了服务器上,每天供人家来访问,这时候Mysql数据库宕掉了,改用Oracle,这时候该怎么怎么办呢?假如没有反射的话,我们是不是得修改代码,将Mysql驱动改为Oracle驱动,重新编译运行,再放到服务器上。是不是很麻烦,还影响用户的访问。

    假如我们使用反射Class.forName()来加载驱动,只需要修改配置文件(配置文件不参与编译)就可以动态加载这个类,Class.forName()生成的结果在编译时是不可知的,只有在运行的时候才能加载这个类,换句话说,此时我们是不需要将程序停下来,只需要修改配置文件里面的信息就可以了。这样当有用户在浏览器访问这个网站时,都不会感觉到服务器程序程序发生了变化。

    所以在《Mybatis技术原理与实战》是这么说反射的好处的。

    配置性大大提高,如同Spring IOC容器,给很多配置设置参数,使得java应用程序能够顺利跑起来,大大提高了Java的灵活性和可配置性,降低模块间的耦合。--《Mybatis技术原理与实战》

    
    

    简单来说就是,没有反射的话如果想要调用其他方法和属性就必须重新修改代码,再编译运行。使用反射修改代码后就不需要再次编译程序了

  • 相关阅读:
    滑动窗口(单调队列)
    蒜头君的排序
    P2024 食物链
    STL
    P2880 [USACO07JAN]平衡的阵容Balanced Lineup(RMQ的倍增模板)
    LCA的两种写法
    P1439 最长公共子序列(nlognLCS问题)
    P3383 【模板】线性筛素数
    P2158 [SDOI2008] 仪仗队(欧拉函数模板)
    alifhab
  • 原文地址:https://www.cnblogs.com/zhai1997/p/11389796.html
Copyright © 2011-2022 走看看