Java反射

1. 什么反射 (What is reflect)

  1. 当实例化类的时候,jvm都会寻得.class文件,加载进代码区,为它创建一个Class对象(这个对象是jvm自动创建的,每个.class文件只创建一个Class对象)

  2. 通过Class对象获得Constructor Method Field 对象,然后就可以使用.class里面的所有内容

2.反射的各种操作 (How to use)

欲用之,必先有对象

  • 获得.class文件的对象

    //方式一:(推荐的方式,优点语法简介,使用灵活)
    Class classFileObj1 = Class.forName(完整的类名);<下面步骤中都有使用>
    //完整的类名 = 包名 + 类名
    
    //方式二:(缺点要导入包,灵活性较低)
    Class classFileObj2 = 类名.class;
    //所有的类都有一个class的静态属性

    //方式三:
    类类型 标识符 = new 类类型();
    //这个中规中矩,没啥好说的
  • 这里可能有个疑问,为什么是加类名,而不是加.java的文件名:
    • 有这个疑问的原因是不清楚,jvm的解释机制
      • 当还是.java文件的时候可能会在一个文件里面储存多各类
      • jvm在把.java文件解释成字节码文件的时候会为每个class生成一个.class文件
    • 所以就能解释完整的类名 = 包名 + 类名,而不是加.java的文件名
  • 获得类的构造函数

类类型 标识符 = new 类类型();

常规的实例化类就是通过new调用类的构造方法

    //第一步获得.class的对象
    Class classFileObj = Class.forName("完整的类名");

    //第二步 获得Constructor 有四种方式:
    //方式一:(获得所有public修饰的构造方法)
    Constructor[] consObj1 = classFileObj.getConstructors();

    //方式二:(获得所有** 修饰符 **修饰的构造方法)
    Constructor[] consObj2 = classFileObj.getDeclaredConstructors();

    //方式三:(通过指定parameter列表获取public修饰的构造方法)
    Constructor consObj3 = classFileObj.getConstructor(Class.. parameter);

    //方式四:(通过指定parameter列表获取** 所有修饰符 **修饰的构造方法)
    Constructor consObj4 = classFileObj.getDeclaredConstruct(Class.. parameter);

    //第三步:
    //通过获得的构造函数实例化一个一个对象
    Object obj = consObje3.newInstance(parameter); <后面使用了它>

    //第四步:
    //使用它 use it
  • 获得类的方法

    //方式一:(获得所有public修饰的方法,包括父类的方法)
    Method[] method1 = classFileObj1.getMethods();

    //方式二:(获得所有** 标识符 **修饰的方式,不包括父类的方法)
    Method[] method2 = classFileObj1.getDeclaredMethods();

    //方式三:(通过指定方法名和parameter列表获取方法)
    Method method3 = classFileObj1.getMethod(methodName,parameter);

    //方式四:(通过指定方法名和parameter列表获取** 所有修饰符修饰的方法)
    Method method4 = classFileObj1.getDeclaredMethod(MethodName,parameter);

    //使用获得的方法
    method4.invoke(方法所属的对象,方法所需的参数)

    //如果是私有方法
    method4.setAccessible(true);//暴力使用
    method4.invoke(方法所属的对象,方法所需的参数)

  • 获得类的字段

    //方式一:(获得所有public修饰的字段)
    Field[] field1 = classFileObj1.getFields();

    //方式二:(获得所有** 标识符 **修饰的Field)
    Field[] field2 = classFileObj1.getDeclaredFields();

    //方式三:(通过指定Field名获取方法)
    Field field3 = classFileObj1.getField(FieldName);

    //方式四:(通过指定Field名获取** 所有修饰符修饰的字段)
    Field field4 = classFileObj1.getDeclaredField(FieldName);

    //使用设置获得的字段
    field4.set(字段所属对象,要设置的值);

    //如果是私有字段
    field4.setAccessible(true);//暴力使用
    field4.set(字段所属的对象,要设置的值)

3.反射的简单使用

    //创建一个反射要使用的类
    package com.person;

    class Person{

        //私有Field
        private int age;
        private String name;
        private int weight;

        //public Field
        public int height = 170;

        //private Constructor
        private Person(){
            this.age = 10;
            this.weight = 20;
        }

        //public Constructot
        public Person(String name){
            this();
            this.name = name;
        }

        //public Method
        public void getPersonName(){
            System.out.println("我的名字是:"+this.name);
        }

        //private Method
        private void privateGetAge(){
            System.out.println("我的年龄是:"+this.age);
        }

        //protected Method
        protected void getHeight(){
             System.out.println("我的身高是"+this.height);
        }


    }

    import java.lang.reflect.*;

try{
    //通过完整的类名,获取Class对象
    Class cls = Class.forName("com.person.Person");

    //获得其中一个构造方法
    Constructor oneOfCons = cls.getConstructor(String.class);
    //创建对象
    Person obj = (Person)oneOfCons.newInstance("小明");
    
    //获得方法
    Method oneOfMethod = cls.getDeclaredMethod("getPersonName");
    //使用它
    oneOfMethod.invoke(obj,null);

    //获得字段
    Field name = cls.getDeclaredField("name");
    //使用它,因为是私有字段所以必须暴力使用
    name.setAccessible(true);
    name.set(obj,"呼啸");
    //查看是否改变
    oneOfMethod.invoke(obj,null);

}catch(Exception e){
    e.printStackTrace();
}

    //结果
    我的名字是:小明
    我的名字是:呼啸
posted @ 2018-05-01 21:45  话少心在  阅读(174)  评论(0编辑  收藏  举报