zoukankan      html  css  js  c++  java
  • java 反射运用

    一,获取私有的属性,方法,构造器(俗名:暴力反射)

     现有一个类,属性,方法,构造器均为私有的,如何创建实例对象,更该属性值,调用方法?

    public class Student {
        private String name;
        private int age;
        private Student() {
            System.out.println("调用了Student()无参私有构造器");
        }
        private String info() {
            System.out.println("调用了info()无参私有方法");
            return "Student [name=" + name + ", age=" + age + "]";
        }
        private void look(String str) {
            System.out.println("调用了look(String str)参数为String类型的私有方法,参数为:"+str);
        }
    }

    main方法:

    首先要创建Student类的实例对象,即调用该类私有的构造方法

    public static void main(String[] args) {
            try {
                //1.首先要创建Student类的实例对象
                //1.1创建Student类的反射对象
                Class<Student> clazz = Student.class;
                //1.2获取私有构造器
                Constructor<Student> c0 = clazz.getDeclaredConstructor();
                //1.3设置访问权限
                c0.setAccessible(true);
                //1.4创建实例对象
                Student student = c0.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    运行,控制台输出结果:

    调用了Student()无参私有构造器

    证明调用了Student类的构造器,并创建了该类的一个实例对象

    更改,获取该类的私有属性

    public static void main(String[] args) {
            try {
                //1.首先要创建Student类的实例对象
                //1.1创建Student类的反射对象
                Class<Student> clazz = Student.class;
                //1.2获取私有构造器
                Constructor<Student> c0 = clazz.getDeclaredConstructor();
                //1.3设置访问权限
                c0.setAccessible(true);
                //1.4创建实例对象
                Student student = c0.newInstance();
                
                //获取私有属性 name
                Field name = clazz.getDeclaredField("name");
                //设置访问权限
                name.setAccessible(true);
                //为该对象的该属性赋值
                name.set(student, "张三");
                
                Field age = clazz.getDeclaredField("age");
                age.setAccessible(true);
                age.set(student, 18);
                //获取该属性的值:get(实例对象)
                Object nameVal = name.get(student);
                System.out.println("name:"+nameVal);
                Object ageVal = age.get(student);
                System.out.println("age:"+ageVal);
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    运行结果:

    调用了Student()无参私有构造器
    name:张三
    age:18

    调用私有方法

    public static void main(String[] args) {
            try {
                //1.首先要创建Student类的实例对象
                //1.1创建Student类的反射对象
                Class<Student> clazz = Student.class;
                //1.2获取私有构造器
                Constructor<Student> c0 = clazz.getDeclaredConstructor();
                //1.3设置访问权限
                c0.setAccessible(true);
                //1.4创建实例对象
                Student student = c0.newInstance();
                
                //获取私有属性 name
                Field name = clazz.getDeclaredField("name");
                //设置访问权限
                name.setAccessible(true);
                //为该对象的该属性赋值
                name.set(student, "张三");
                
                Field age = clazz.getDeclaredField("age");
                age.setAccessible(true);
                age.set(student, 18);
                //获取该属性的值:get(实例对象)
                Object nameVal = name.get(student);
                System.out.println("name:"+nameVal);
                Object ageVal = age.get(student);
                System.out.println("age:"+ageVal);
                
                //获取info方法
                Method infoMethod = clazz.getDeclaredMethod("info");
                //设置访问权限
                infoMethod.setAccessible(true);
                //执行该方法,获取返回值
                Object infoRet = infoMethod.invoke(student);
                //打印返回值
                System.out.println(infoRet);
                
                //获取look方法
                Method lookMethod = clazz.getDeclaredMethod("look", String.class);
                //设置访问权限
                lookMethod.setAccessible(true);
                //执行该方法,传参
                lookMethod.invoke(student, "Hello World");
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    运行结果:

    调用了Student()无参私有构造器
    name:张三
    age:18
    调用了info()无参私有方法
    Student [name=张三, age=18]
    调用了look(String str)参数为String类型的私有方法,参数为:Hello World

    小结:通过java反射机制,可以调用任意类中的任意修饰符的属性,方法,构造器

    java的反射机制跟封装冲突吗?

    一个房子,没有门,没有窗户,但我为了进去,只能穿墙了...

    二,通过反射机制灵活调用(多态)

    先上一组简单代码

    public interface Father {
        void look();
        String see(String str);
    }
    public class AAA implements Father{
        @Override
        public void look() {
            System.out.println("this is AAA look()");
        }
        @Override
        public String see(String str) {
            System.out.println("this is AAA see()");
            System.out.println("str is " + str);
            return str;
        }
    }
    public class BBB implements Father{
        @Override
        public void look() {
            System.out.println("this is BBB look()");
        }
        @Override
        public String see(String str) {
            System.out.println("this is BBB see()");
            System.out.println("str is " + str);
            return str;
        }
    }
    public class Test01 {
        public static void main(String[] args) {
            Father a = new AAA();
            a.look();
            String seeA = a.see("Hello");
            System.out.println(seeA);
            System.out.println("==================");
            Father b = new BBB();
            b.look();
            String seeB = b.see("Hello");
            System.out.println(seeB);
        }
    }

    打印结果:

    this is AAA look()
    this is AAA see()
    str is Hello
    Hello
    ==================
    this is BBB look()
    this is BBB see()
    str is Hello

    当我们需要在程序运行时,有选择性的调用AAA类或BBB类

    即:运行时编译,我们增加一个工厂类

    public class Factory {
        public static Father getInstance(String className) {
            if("AAA".equals(className)) {
                return new AAA();
            }else if("BBB".equals(className)) {
                return new BBB();
            }else {
                return null;
            }
        }
    }

    在main方法中调用:

    public static void main(String[] args) {
            //可从外部获取(properties文件,数据库,或其他方法返回值)
            String className = "BBB";
            
            Father a = Factory.getInstance(className);
            a.look();
            String seeA = a.see("Hello");
            System.out.println(seeA);
        }

    这样,我们就可以在运行时选择性的创建对象了

    这和反射有什么关系呢?

    假设,需求变更,要增加一个CCC类,同样实现了Father接口,并也动态调用

    需要修改的代码:

    //增加一个CCC类,实现Father接口
    public class CCC implements Father{
        @Override
        public void look() {
            System.out.println("this is CCC look()");
        }
        @Override
        public String see(String str) {
            System.out.println("this is CCC see()");
            System.out.println("str is " + str);
            return str;
        }
    }
    //修改Factory工厂类,增加CCC类的创建方法
    public class Factory {
        public static Father getInstance(String className) {
            if("AAA".equals(className)) {
                return new AAA();
            }else if("BBB".equals(className)) {
                return new BBB();
            }else if("CCC".equals(className)){
                return new CCC();
            }else {
                return null;
            }
        }
    }

    注意:在实际项目中,修改一个已经运行成功没问题的方法,是存在风险的,改完万一出错了呢...(程序员都懂...)

    所以,在这里如果使用反射机制,就更加灵活,以下代码举例说明

    public class Factory {
        public static Father getInstance(String className) {
            Father f = null;
            
    //        if("AAA".equals(className)) {
    //            return new AAA();
    //        }else if("BBB".equals(className)) {
    //            return new BBB();
    //        }else if("CCC".equals(className)){
    //            return new CCC();
    //        }else {
    //            return null;
    //        }
            
            try {
                f = (Father)Class.forName(className).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            
            return f;
        }
    }
    public class Test01 {
        public static void main(String[] args) {
            //可从外部获取(properties文件,数据库,或其他方法返回值)
            String className = "com.dream.springboot.test.clazzTest.BBB";
            
            Father f = Factory.getInstance(className);
            f.look();
            String see = f.see("Hello");
            System.out.println(see);
        }
    }

    在Factory工厂类中,使用全类名获取实例,这样避免了增加类时就修改Factory类中的方法,可减少错误,也减少工作量

    总结:反射就是当詹姆斯·高斯林给你关了一扇门,又给你打开的一扇窗

     代码上传地址:https://download.csdn.net/download/lijian0420/10803158

  • 相关阅读:
    获取远程图片的Blob资源
    Vue使用SCSS进行模块化开发
    Vue设置页面的title
    Vue里边接口访问Post、Get
    module.exports 、 exports 和 export 、 export default 、 import
    Vue设置不同的环境发布程序
    记一个鼠标略过时候的css动画
    关于正则表达式中^和$
    [LOJ#2305]「NOI2017」游戏
    [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC
  • 原文地址:https://www.cnblogs.com/gode/p/10007440.html
Copyright © 2011-2022 走看看