Java反射机制 01:概述&应用

一、反射机制

  1. 反射机制的作用:通过Java语言中的反射机制可以操作字节码文件(代码片段、Class文件)。
    —— 可以读和修改字节码文件
  2. 反射机制的相关类在java.lang.reflect.*包下。

二、反射机制相关的重要的类

  1. java.lang.Class:代表整个字节码,代表一个类型。代表整个类。
  2. java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
  3. java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法。
  4. java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量和实例变量)

三、java.lang.Class

  1. 要操作一个类的字节码,首先要获取这个类的字节码文件,获取java.lang.Class实例有三种方式:
    • Class c = Class.forName("完整类名带包名");

      如果只希望一个类的静态代码块执行,其他代码一律不执行
      可以使用:Class.forName(“完整类名”);
      这个方法的执行会导致类加载类加载时,静态代码块执行。

    • Class c = 对象.getClass();
    • Class c = 任何类型.class; 在这里插入图片描述
    public class ReflectTest01 {
       public static void main(String[] args) {
           /*
           Class.forName()
               1、静态方法
               2、方法的参数是一个字符串。字符串需要的是一个完整类名。
               3、完整类名必须带有包名。java.lang包也不能省略。
            */
           Class c1 = null;
           Class c2 = null;
           try {
               c1 = Class.forName("java.lang.String");//c1代表String.class文件(c1代表St>ring类型)
               c2 = Class.forName("java.util.Date");//c2代表Date类型
               Class c3 = Class.forName("java.lang.Integer");//c3代表Integer类型
               Class c4 = Class.forName("java.lang.System");//c4代表System类型
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           }
    
           // java中任何一个对象都有一个方法:getClass()
           String s = "abc";
           Class x = s.getClass();//x代表的是String.class字节码文件(x代表的是String类型)
           System.out.println(x == c1);//true
    
           Date date = new Date();
           Class y = date.getClass();//y代表Date.class字节码文件(y代表Date类型)
           System.out.println(y == c2);//true
    
           // 第三种方式,java语言中任何一种类型,包括基本数据类型,它都有.class属性。
           Class a = String.class;//a代表String类型
           Class b = Date.class;//b代表Date类型
           System.out.println(a == c1);//true
           System.out.println(b == c2);//true
       }
    }
    

  2. 使用反射机制来实例化对象
    1. 获取到Class实例,可以Class的 newInstance() 方法来实例化的对象(反射机制实例化对象)
      注:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以。
    2. 使用反射机制实例化对象更具有灵活性
      java代码不需要改动(不改变源代码),可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。
    public class ReflectTest03 {
        public static void main(String[] args) {
            // 这种方式代码就写死了。只能创建一个User类型的对象
            //User user = new User();
            
            //以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。
            //获取文件路径,较通用方法
            String path = Thread.currentThread().getContextClassLoader()
                    .getResource("com/javaSE/reflect/classinfo.properties").getPath();
            //定义一个文件字符输入流
            FileReader fileReader = null;
            try {
                //通过IO流读取属性配置文件
                fileReader = new FileReader(path);
                //创建一个属性类对象Map集合
                Properties properties = new Properties();
                //把属性配置文件加载进Properties集合
                properties.load(fileReader);
                //获得类名
                String className = properties.getProperty("className");//com.javaSE.reflect.User
                //通过反射机制的方式来实例化对象
                Class c = Class.forName(className);//c代表的是className对应的类
                Object o = c.newInstance();//newInstance() 这个方法会调用User这个类的无参构造方法,完成对象的创建,必须保证无参构造是存在的!
                System.out.println(o);//com.javaSE.reflect.User@7a0ac6e3
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } finally {
                if (fileReader != null) {
                    try {
                        fileReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    

四、java.lang.reflect.Field

  1. 当获得类的字节码文件(Class文件),可以通过其获得Field属性
  2. 通过反射机制访问一个java对象的属性
    public class Student {
        // Field翻译为字段,其实就是属性/成员
        // 4个Field,分别采用了不同的访问控制权限修饰符
        private String name; // Field对象
        protected int age; // Field对象
        boolean sex;
        public int no;
    }
    
    public class ReflectTest05 {
        public static void main(String[] args) {
            try {
                //首先获取类的字节码文件(Class文件)
                Class studentClass = Class.forName("com.javaSE.reflect.Student");
                //创建对象o
                Object o = studentClass.newInstance();
                //获得类中的所有属性
                Field[] declaredFields = studentClass.getDeclaredFields();
                for (Field field : declaredFields) {
                	//获得所有所有属性的名字
                    System.out.println(field.getName());
                }
                //获得类中的no属性
                Field noField = studentClass.getDeclaredField("no");
                //设置o对象中的no属性
                noField.set(o, 1111);
                //读取o对象中no属性的值
                System.out.println(noField.get(o));//1111
    
                /*
                如果要获取并设置private修饰的属性
                不能直接获取,直接获取会出现异常
                需要先setAccessible()打破封装
                 */
                Field nameField = studentClass.getDeclaredField("name");
                nameField.setAccessible(true);//打破封装
                //给name属性赋值
                nameField.set(o, "张三");
                //获得name属性的值
                System.out.println(nameField.get(o));//张三
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
    }
    

五、java.lang.reflect.Method

  1. 当获得类的字节码文件(Class文件),可以通过其获得Method属性。
  2. 通过反射机制调用一个java对象的方法
    /**
     * 用户业务类
     */
    public class UserService {
        /**
         * 登录方法
         * @param name 用户名
         * @param password 密码
         * @return true表示登录成功,false表示登录失败!
         */
        public boolean login(String name,String password){
            if("admin".equals(name) && "123".equals(password)){
                return true;
            }
            return false;
        }
    
        // 可能还有一个同名login方法
        // java中怎么区分一个方法,依靠方法名和参数列表。
        public void login(int i){
    
        }
    
        /**
         * 退出系统的方法
         */
        public void logout(){
            System.out.println("系统已经安全退出!");
        }
    }
    
    public class ReflectTest06 {
        public static void main(String[] args) {
            try {
                //获取UserService类的Class文件
                Class userServiceClass = Class.forName("com.javaSE.reflect.UserService");
                //通过反射机制创建一个UserService对象
                Object o = userServiceClass.newInstance();
                //通过反射机制获取类中的login方法
                Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
                //通过反射机制调用login方法
                Object returnValue = loginMethod.invoke(o, "admin", "123");
                System.out.println(returnValue);//true
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

六、java.lang.reflect.Constructor

  1. 当获得类的字节码文件(Class文件),可以通过其获得Constructor属性。
  2. 通过反射机制调用一个java对象的构造方法
    public class Vip {
        int no;
        String name;
        String birth;
        boolean sex;
    
        public Vip() {
        }
    
        public Vip(int no) {
            this.no = no;
        }
    
        public Vip(int no, String name) {
            this.no = no;
            this.name = name;
        }
    
        public Vip(int no, String name, String birth) {
            this.no = no;
            this.name = name;
            this.birth = birth;
        }
    
        public Vip(int no, String name, String birth, boolean sex) {
            this.no = no;
            this.name = name;
            this.birth = birth;
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Vip{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    ", birth='" + birth + '\'' +
                    ", sex=" + sex +
                    '}';
        }
    }
    
    public class ReflectTest07 {
        public static void main(String[] args) {
            try {
                //获得Vip类的Class文件
                Class vipClass = Class.forName("com.javaSE.reflect.Vip");
                //调用无参构造方法,可以直接使用newInstance()方法
                Object o = vipClass.newInstance();
                System.out.println(o);//Vip{no=0, name='null', birth='null', sex=false}
    
                //或者使用如下通用方法
                //获取类中的无参构造方法
                Constructor c1 = vipClass.getDeclaredConstructor();
                //调用无参的构造方法
                Object o1 = c1.newInstance();
                System.out.println(o1);//Vip{no=0, name='null', birth='null', sex=false}
    
                //获得类中形参为四个的构造方法
                Constructor c2 = vipClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
                //调用形参为四个的构造方法
                Object o2 = c2.newInstance(110, "zhangsan", "1997-05-16", true);
                System.out.println(o2);//Vip{no=110, name='zhangsan', birth='1997-05-16', sex=true}
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    

七、通过反射机制获得这个类的父类和接口

public class ReflectTest08 {
    public static void main(String[] args) {
        try {
            //获取String的class文件
            Class stringClass = Class.forName("java.lang.String");
            //获得String的父类
            Class superclass = stringClass.getSuperclass();
            System.out.println(superclass.getName());//java.lang.Object
            //获得String类的所有接口
            Class[] interfaces = stringClass.getInterfaces();
            for (Class in : interfaces) {
                System.out.println(in.getName());
                /*
                java.io.Serializable
                java.lang.Comparable
                java.lang.CharSequence              
                 */
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值