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

  • 相关阅读:
    Codeforces Round #592 (Div. 2)C. The Football Season(暴力,循环节)
    Educational Codeforces Round 72 (Rated for Div. 2)D. Coloring Edges(想法)
    扩展KMP
    poj 1699 Best Sequence(dfs)
    KMP(思路分析)
    poj 1950 Dessert(dfs)
    poj 3278 Catch That Cow(BFS)
    素数环(回溯)
    sort与qsort
    poj 1952 buy low buy lower(DP)
  • 原文地址:https://www.cnblogs.com/gode/p/10007440.html
Copyright © 2011-2022 走看看