Java 反射机制

一、 概述

  1. 集群 : 一组完成同一功能的服务器。
  2. 解耦: 降低两个功能 不同的模块之间的依赖性
  3. 高内聚,低耦合: 提高模块内的利用率 , 降低模块之间的依赖性 。
  4. Class : 一个代表字节码的类 。每个类编译之后都会有相应的字节码 , 所以也叫代表类的类 。
  5. Package : 代表包的类 。
  6. Field : 代表属性的类 。
  7. Method : 代表方法的类 。
  8. Constructor : 一个代表构造方法的类
  9. Annotation : 代表注解的类
  10. 反射: 作用就是剖析一个类 , 分析这个类的字节码 ,产生对应的字节码对象以及实例对象 。

二、应用

  1. 获取一个Class对象

    1. 通过对象的getClass() 方式获取对象的字节码 。
    2. 通过 类名.class 来获取类对应的字节码 。
    3. 通过Class.forName(“name”); 获取这个类的字节码对象 , 传入的类名必须是全类名 。
    4. 代码:

      //获取一个Class对象 。
      public class Test_01 {
          public static void main(String[] args) throws ClassNotFoundException {
              //只有java虚拟机才有权调用他的构造函数 。 
              //为什么要把Class的构造函数私有化?
              //Class -- 代表类的类 , 每一个Class对象应该表示一个具体的类
      //      Class c =  Class();//报错
      
              //获取一个Class对象
              //第一种
              // 表示获取“abc”所对应的类的字节码
              //c代表的就是String类的字节码
              Class c = "abc".getClass();
              System.out.println(c);
              //第二种
              //c表示Integer类的字节码
              Class c1 = Integer.class;//获取类的字节码
              Class c2 = List.class;//获取接口的字节码
              Class c3 = int[].class;//获取数组的字节码  数组本质上也是一个类
              Class c4 = int.class;//获取基本数据类型的字节码
              //在java中所有的数据类型都有对应的字节码文件 。 
              System.out.println(c1);
              System.out.println(c2);
              System.out.println(c3);
              System.out.println(c4);
              //第三种
              //传入类名 , 获取对应的字节码 .因为java中可能存在同名类 , 所以传入的类名必须是全类名
              Class c5  = Class.forName("java.util.List");
              System.out.println(c5);
          }
      }
      
      
      //第三种方式实现解耦
      public class Test_02 {
          public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
              //解耦
              Properties p = new Properties();
              p.load(new FileInputStream("config.properties"));
              Class c = Class.forName(p.getProperty("classname"));
          }
      }
      
  2. java是一门完全面向对象的语言 — 万物皆对象 即使是基本数据类型 , 底层的字节码文件 , 也是一个对象 。

  3. 获取一个类的实例对象

    //获取一个类的实例对象
    public class Test_03 {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
            //如果添加泛型 , 则表示后续的字节码代表的是泛型的子类或本身
            //c 代表的是Object类或Object的子类的字节码对象
            Class<Object> c = (Class<Object>) Class.forName("java.lang.Object");
    
            //如何产生一个c所对应的类的实例对象? --- 如何创建一个字符串呢 ?
            Object o = c.newInstance();//自动调用对应类的构造函数来创建一个实例对象
            System.out.println(0);
    
            //要求对应的类中必须提供了对应的无参构造 。 
    //      Class c1 = Integer.class;
    //      Integer i = (Integer) c.newInstance();
    //      System.out.println(i);//报错
    
            //获取构造函数
            //获取这个类的构造函数对象
            Class<Integer> c1 = Integer.class;
            //执行这个构造函数 , 传入对应的构造函数 , 产生一个Integer有参对象
            Constructor<Integer> con = c1.getConstructor(String.class);
            Integer oo =  con.newInstance("123");
            System.out.println(oo);
        }
    }
    
  4. 获取指定的构造函数

    public class Test_04 {
        public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            Class<String> c = String.class;
            //获取对应形式的公共构造函数
            Constructor<String> con = c.getConstructor(byte[].class);
            //执行构造函数 , 创建String实例
            String ni = con.newInstance(new byte[]{'a','c','f','f',});
            System.out.println(ni);
    
            //获取String类中所有的构造函数
            //只能获取public 修饰的构造函数 。 
            Constructor[] cons = c.getConstructors();
            for(Constructor conn : cons){
                System.out.println(conn);
            }
    
            //获取指定的构造函数
    //      Constructor<String> con1 = c.getConstructor(char[].class , boolean.class);//报错    这种方法只能获取公有的 , 而这个方法不是公有的函数
            //无论共有还是非共有的 , 都能获取到 。
            Constructor<String> dcon = c.getDeclaredConstructor(char[].class , boolean.class);
            //暴力破解    强制执行没有对应权限的方法
            dcon.setAccessible(true);
            //如果没有暴力破解则会报错  非法获取异常  这个方法不是public修饰的而是default修饰 , 没有对应的权限 。
            String str = dcon.newInstance(new char[]{'a','b','c'} , true);
            System.out.println(str); 
        }
    }
    
  5. 获取成员方法

    //获取方法
    public class Test_05 {
        public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            Class c = String.class;
            Constructor con = c.getConstructor(String.class);
            String str = (String) con.newInstance("sdfgdf");
            //获取方法
            Method m =  c.getMethod("charAt", int.class);
            //执行方法
            //第一个参数:执行方法的对象
            //第二个参数:  需要执行的方法需要的参数 
            char cc = (char) m.invoke(str, 0);
            System.out.println(cc);
    
    
            //获取私有的方法
    //      str.lastIndexOfSupplementary(1,3);//报错 , 因为该方法是私有的
            Method m2 = c.getDeclaredMethod("lastIndexOfSupplementary", int.class,int.class);
            //私有方法的执行 需要提前暴力破解
            m2.setAccessible(true);
            //执行方法
            int i  = (int) m2.invoke(str, 2,4);
            System.out.println(i);
            //获取方法的返回值类型
            Class rc = m.getReturnType();
            System.out.println(rc);
            //获取方法的参数列表
            Class[] pt = m.getParameterTypes();
            for(Object o :pt){
                System.out.println(o);
            }
            //获取方法抛出的异常
            Class[] et = m.getExceptionTypes();
            for(Object o :et){
                System.out.println(o);
            }
            //判断是否有可变参数
            System.out.println(m.isVarArgs());
            //获取方法名
            System.out.println(m.getName());
        }
    }
    
  6. 获取属性 , 设置属性

    //获取属性 , 设置属性
    public class Test_06 {
        public static void main(String[] args) throws Exception {
            Class c = String.class;
    
            //获取指定属性
            Field df = c.getDeclaredField("hash");
            System.out.println(df);
            //获取属性的值
            String str = "sdf";
            //暴力破解
            df.setAccessible(true);
            System.out.println(df.get(str));
            //设置属性的值
            df.set(str, 234);
            System.out.println(df.get(str));
            //获取声明类型
            System.out.println(df.getType());
        }
    }
    
  7. 获取类的信息

    //获取这个类的信息
    public class Test_07 {
        @SuppressWarnings({ "unchecked", "rawtypes" })
        public static void main(String[] args) {
            Class<String> c = String.class;
            //获取所有实现接口
            Class<String>[] interfaces = (Class<String>[]) c.getInterfaces();
            for(Class cc : interfaces){
                System.out.println(cc);
            }
            //获取类的全路径名    --- 包名+类名
            //toString() 底层   getClass().getName+"@"+hashcode()
            System.out.println(c.getName());
            //[获取所在包
            System.out.println(c.getPackage());
            //只获取类名
            System.out.println(c.getSimpleName());
            //获取父类
            System.out.println(c.getSuperclass());
            //判断是否是一个注解类型
            System.out.println(c.isAnnotation());
            //判断是否是一个匿名内部类
            System.out.println(c.isAnonymousClass());
            //判断是否是一个数组
            System.out.println(c.isArray());
            //判断是否是一个枚举
            System.out.println(c.isEnum());
            //判断传入的对象类型是否是本字节码对象的实例
            System.out.println(c.isInstance("afdsfd"));
            //判断是否是一个接口
            System.out.println(c.isInterface());
            //判断是否是一个方法内部类
            System.out.println(c.isLocalClass());
            //判断是否是一个成员内部类
            System.out.println(c.isMemberClass());
            //判断是否是一个基本类型
            System.out.println(c.isPrimitive());
            //判断参数类型是否是本字节码对象的子类|接口
            System.out.println(c.isAssignableFrom(String.class));
        }
    }
    
  8. 练习 : 实现数据与代码解耦

    //练习
    /* 
     * 接口Person 接口中方法: eat()吃 , work()工作 , tax()缴税
     * 医生类实现Person 属性:名字name 、 年龄age 、 性别gender  、 工资salary 、 入职日期date     
     * 方法:所有属性的get、set方法 、 eat(){name + 在手术室吃饭} , work(){治病救人} , tax(){工资*0.5}
     * 教师类 实现Person 属性: 名字name 、 年龄age 、 性别gender  、 工资salary 、 入职日期date
     * 方法: 所有属性的get、set方法 、 eat(){name + 在教室吃饭} , work(){教书育人} , tax(){工资*0.5}
     * config.properties文件中:
     * classname = 教师|医生
     * attrname = name/age/gender/entry
     * attrvalue = Amy/50/\u5973/2010-10-10
     * mothename = work
     * */
    public class Test_08 {
        @SuppressWarnings("unchecked")
        public static void main(String[] args) throws Exception {
            //读取配置文件
            Properties p = new Properties();
            p.load(new FileInputStream("src/com/tj/tedufanshe/config.properties"));
            String classname = p.getProperty("classname");
            String attrname = p.getProperty("attrname");
            String attrvalue =  p.getProperty("attrvalue");
            String methodname = p.getProperty("methodname");
            //创建类的字节码对象
            Class<Person> clz = (Class<Person>) Class.forName(classname);
            //创建字节码对象对应的实例对象
            Person per = clz.newInstance();
            //获取要操作的属性名
            String[] attrnames = attrname.split("/");
            //获取属性值
            String[] attrvalues = attrvalue.split("/");
            //遍历属性名数组
             for(int i = 0  ; i<attrnames.length ;i++){
                //获取属性名对应的属性
                 Field f = clz.getDeclaredField(attrnames[i]);
                 //获取属性的省名类型
                 Class<?> ft = f.getType();
                 //获取属性对应的set方法的名
                 String name = "set"+attrnames[i].substring(0,1).toUpperCase()+attrnames[i].substring(1,attrnames[i].length());
                 //获取对应的set方法
                 Method m = clz.getMethod(name, ft);
                 //判断属性值的类型, 然后转化为对应的类型
                 System.out.println(attrvalues[i]);
                 if(ft == int.class ||ft.equals(Integer.class)){
                    m.invoke(per, Integer.parseInt(attrvalues[i].trim()));
                 }else if(ft == char.class || ft.equals(Character.class)){
                     m.invoke(per, attrvalues[i].toCharArray()[0]);
                 }else if(ft == Date.class ){
                     m.invoke(per, new SimpleDateFormat("yyyy-MM-dd").parse(attrvalues[i].trim()));
                 }else{
                     m.invoke(per, attrvalues[i] );
                 }
            }
              //执行指定的方法
             Method m2 = clz.getMethod(methodname);
             m2.invoke(per);
        }
    }
    interface Person{
        void eat();
        void work();
        void tax();
    }
    class Teacher implements Person{
        private String name ;
        private int age;
        private char gender;
        private int salary;
        private Date entry;
        @Override
        public void eat() {
            System.out.println(name+"老师正在教师吃粉笔");
        }
    
        @Override
        public void work() {
            System.out.println("教书育人");
        }
    
        @Override
        public void tax() {
            System.out.println("缴税"+salary*0.5);
        }
        public Teacher() {
        }
        public Teacher(String name, int age, char gender, int salary, Date entry) {
            super();
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.salary = salary;
            this.entry = entry;
        }
    
        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 char getGender() {
            return gender;
        }
    
        public void setGender(char gender) {
            this.gender = gender;
        }
    
        public int getSalary() {
            return salary;
        }
    
        public void setSalary(int salary) {
            this.salary = salary;
        }
    
        public Date getEntry() {
            return entry;
        }
    
        public void setEntry(Date entry) {
            this.entry = entry;
        }
    
    }
    class Dectory implements Person{
        private String name ;
        private int age;
        private char gender;
        private int salary;
        private Date entry;
        @Override
        public void eat() {
            System.out.println(name+"医生正在手术室吃大腿");
        }
    
        @Override
        public void work() {
            System.out.println("治病救人");
        }
    
        @Override
        public void tax() {
            System.out.println("缴税"+salary*0.5);
        }
        public Dectory() {
        }
        public Dectory(String name, int age, char gender, int salary, Date entry) {
            super();
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.salary = salary;
            this.entry = entry;
        }
    
        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 char getGender() {
            return gender;
        }
    
        public void setGender(char gender) {
            this.gender = gender;
        }
    
        public int getSalary() {
            return salary;
        }
    
        public void setSalary(int salary) {
            this.salary = salary;
        }
    
        public Date getEntry() {
            return entry;
        }
    
        public void setEntry(Date entry) {
            this.entry = entry;
        }
    
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值