反射

反射:框架设计的灵魂

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
通俗来说: 将类的各个组成部分封装为其他对象,这就是反射机制。
好处:

  • 1可以在程序的运行过程中,操作这些对象
  • 2可以解耦,降低程序的紧密程度,提高程序的可扩展性

java代码在计算机内部的三个阶段

Source源代码阶段——>Class类对象的阶段——>Runtime运行时阶段

阶段
Source源代码源代码通过javac编译产生class字节码文件
Class类对象成员变量+构造方法+成员方法
Runtime运行可以产生许多对象

反射是可以通过类文件来获取类的内容,包括成员变量,成员方法,构造函数。

Person类是下面使用的类

public class Person {
    private String name;
    private int age;
    //用来说明可以从Class中获取的成员变量
    public String a;
    protected String b;
    String c;
    private String d;
    public Person(){}
    public Person(String name,int age){
        this.age=age;
        this.name=name;
    }
    public String getName(){
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name){
        this.name=name;
    }
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                ", d='" + d + '\'' +
                '}';
    }
    public  void eat(){
        System.out.println ("eat.........");
    }
    public  void eat(String food){
        System.out.println ("eat........."+food);
    }
}

获取类文件(3种)

1Class.forName(“全限定类名”)
2类名.class
3对象.getClass()

   public static void main(String[] args) throws ClassNotFoundException {
        /*
        获取Class对象的3种方式:
        1Class.forName("全类名");
        2类名.class
        3对象.getClass()方法
         */
        //1Class.forName("全类名");
        Class class1 = Class.forName("cn.itcast.domain.Person");
        System.out.println(class1);
        //2类名.class
        Class class2 = Person.class;
        System.out.println(class2);
        //3对象.getClass()
        Person p = new Person();
        Class class3 = p.getClass();
        System.out.println(class3);

        //比较3个对象,==比较的是内存的地址
        //得到的结论:同一个字节码文件,不管通过哪种方式获取的Class对象是同一个
        System.out.println(class1==class2);
        System.out.println(class2==class3);
    }    

获取成员变量

Field[] getField():获取所有public修饰得成员变量
Field getField(String name):获取指定的用public修饰的成员变量
Field[] getDeclaredField():获取所有的成员变量
Field getDeclaredFields(String name):获取指定的成员变量
成员变量的操作:
		1. 设置值
			* void set(Object obj, Object value)  
		2. 获取值
			* get(Object obj) 
		3. 忽略访问权限修饰符的安全检查
			* setAccessible(true):暴力反射
  public static void main(String[] args) throws Exception {
        //1获取Person的字节码文件
        Class class1 = Person.class;
        //2Field[] getFields();
        Field[] fields =class1.getFields();
        for(Field field : fields)
        {
            System.out.println(field);
        }
        System.out.println("--------------");
        Field field = class1.getField("a");
        //获取成员变量的值,并加以设置
        Person  p = new Person();
        Object value = field.get(p);
        System.out.println(value);
        field.set(p,"张三");
        System.out.println(field.get(p));
        System.out.println ("--------------");
        //获取所有的成员变量
        Field[] declaredFields = class1.getDeclaredFields ();
        for (Field  declaredField:declaredFields) {
            System.out.println (declaredField);
        }
        //获取指定的值,非public,必须忽略修饰符
       Field d = class1.getDeclaredField ("d");
        d.setAccessible (true);//暴力破解
        System.out.println (d.get (p));
    }

注意:获取指定的值,但是该变量为非public的,需要设置setAccessible 为true

获取成员方法

Method[] getMethods()  
Method getMethod(String name,<?>... parameterTypes)  
Method[] getDeclaredMethods()  
Method getDeclaredMethod(String name,<?>... parameterTypes)  
方法的操作:
	执行方法:
		 Object invoke(Object obj, Object... args)  
	获取方法名称:
		 String getName:获取方法名
  public static void main(String[] args) throws Exception {
     
        Class personClass = Person.class;
        //获取指定名称的方法——空参方法运行
        Method eat_method = personClass.getMethod ("eat");
        Person p = new Person ();
        eat_method.invoke (p);
        //获取指定名称的方法——带有参数的方法
        Method eat_Method1 = personClass.getMethod ("eat",String.class);
        eat_Method1.invoke (p,"饭");
        Method[] methods  = personClass.getMethods ();
        for (Method method :
                methods) {
//            method.setAccessible (true);暴力反射
            System.out.println (method.getName ());//获取类名
            System.out.println (method);
        }

    }

获取构造函数

Method[] getMethods()  
Method getMethod(String name,<?>... parameterTypes)  
Method[] getDeclaredMethods()  
Method getDeclaredMethod(String name,<?>... parameterTypes)
 创建对象:
		T newInstance(Object... initargs)   
public static void main(String[] args) throws Exception {
     
        //1获取Person对象的Class对象
        Class personClass= Person.class;
        //2获取构造方法
            //带参数的构造方法
        Constructor constructor = personClass.getConstructor (String.class,int.class);
        System.out.println (constructor);
        Object person = constructor.newInstance ("张三",23);
        System.out.println (person);
            //空参数的构造方法
        Constructor constructor1 = personClass.getConstructor ();
        Object person1 = constructor1.newInstance ();
        System.out.println (person1);
            //Class提供的空参数的构造函数
        Object o = personClass.newInstance ();
        System.out.println (o);
    }

不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法

1首先定义一个pro.properties文件

className=cn.itcast.domain.Person
methodName=eat

2然后使用代码对文件内容进行读取,然后使用反射创建对象,执行方法

 public static void main(String[] args) throws Exception {
        //可以创建任意类的对象,可以执行任意方法
        //1加载文件
            //1.1创建properties对象
        Properties pro = new Properties ();
            //1.2加载配置文件,转换为一个集合
                //1.2.1获取class目录下的配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader ( );
        InputStream resourceAsStream = classLoader.getResourceAsStream ("pro.properties");
        pro.load (resourceAsStream);

        //2获取配置文件中定义的数据
        String className = pro.getProperty ("className");
        String methodName = pro.getProperty ("methodName");

        //3加载该类进入内存
        Class cls = Class.forName (className);
        //4创建对象
        Object obj = cls.newInstance ();
        //5获取方法对象
        Method method = cls.getMethod (methodName);
        //6执行方法
        method.invoke (obj);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值