java之反射技术

反射就是从内存当中找类的相关信息,从而构建一个对象,然后可以执行一系列的操作

简单说一下,类的字节码文件被加载到内存之后,就会构建一个Class对象,来保存相关类的信息与接口,我们反射的目的就是拿到这个Class对象进行操作。

既然是对象,那么内部就会有很多功能,有什么功能推也能推测出来,对象嘛,就有什么涉及成员变量的,成员方法的,还有构造方法的一系列操作

 下面列举出这些方法:

话不多说,直接上代码:

 Reflect1.java

package reflect;

import domain.Person;

import java.lang.reflect.Field;

public class Reflect1 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        //获取Person的class对象
        Class personClass = Person.class;

        //获取所有public修饰的变量
        Field[] fields = personClass.getFields();
        //把这些打出来
        for(Field data : fields) {
            System.out.println(data);//这里只能找到public String a,因为只有它是public的
        }

        System.out.println("-------------");

        //根据反射,来获取对象的值
        Field a = personClass.getField("a");
        Person person = new Person();
        //给a成员属性赋一个值
        person.a = "张三风";
        Object o1=  a.get(person);
        System.out.println(o1);//打印张三风

        System.out.println("-------------");
        //通过反射来操作对象,给person对象赋值
        a.set(person,"张三");

        System.out.println(person);

        System.out.println("-----------------");

        //获取所有变量(不管啥属性)
        Field[] fields2 = personClass.getDeclaredFields();

        for(Field data : fields2) {
            System.out.println(data);
        }

        System.out.println("------------");
        //获取私有变量来破解赋值
        personClass.getDeclaredField("d");

        //获取
        Field fields3 = personClass.getDeclaredField("age");
        fields3.setAccessible(true);//暴力破解,才可以为私有属性赋值
        fields3.set(person,20);
        Object value = fields3.get(person);
        System.out.println(person);

        System.out.println("------------------------");



    }
}

运行结果:

 

上面也就很明显,Field对象中get与set方法,都要带上已经声明的对象,否则我们不知道是得到或者设置哪一个对象的中属性的值。

下面还需要来说明一下,这个传入的是啥:

可变函数参数,是一个Class类型,所以,参数也是传入该参数在内存中的class对象,别忘了,数据类型就是一个对象。

代码实例:

首先看一下我们放在domain下面的一个类:

package domain;

public class Person {
    private String name;
    private int age;

    public String a;
    protected String b;
    String c;
    private String d;


    public Person() {
    }

    public Person(String name, int age) {

        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    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);
    }
}

 然后利用反射来构造一个对象

package reflect;

import domain.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Reflect2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

        //获得class类对象,类文件
        Class  person = Class.forName("domain.Person");
        //根据反射创建一个对象
        Constructor[] cons = person.getConstructors();
        for(Constructor data : cons) {
            System.out.println(data);
        }

        System.out.println("-----------");

        //利用反射构造一个对象
        Constructor cons1 = person.getConstructor(String.class,int.class);
        Object obj = cons1.newInstance("王五",20);
        Person p1 = (Person)obj;
        System.out.println(p1.getName());
    }

}

运行结果:

      
        上面可以看到传入getConstructor(类名.class...)这个就是传入了参数的Class对象,然后调用newInstance(传入参数值),这样就构造了一个class对象。

        这里在多说一下,对于Class类型饿对象,他还有如下的一个方法

         他会默认去调用无参构造创建一个相应的T类型的对象出来。

        利用反射来执行某个对象的方法: 

package reflect;

import domain.Person;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Reflect3 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        //得到Class类对象
        Class obj = Person.class;//得到对象
        Method[] method = obj.getDeclaredMethods();

        for(Method data : method) {
            System.out.println(data);
            data.setAccessible(true);
        }

        System.out.println("-------");

        //得到具体某一个方法,然后执行
        Method method_eat = obj.getMethod("eat");//没有参数
        Person p = new Person();
     //   method_eat.setAccessible(true);暴力破解对方法无效
        method_eat.invoke(p);

    }
}

运行结果:

        

在来看一个实例:

根据配置文件来找构建一个对象,然后执行一个方法:

什么是配置文件:以.properties结尾的文件,我们需要把这个配置文件以文件流的形式加载到内存中,传给Properties对象来获取相关信息。

 上面包含了加载的对象与需要执行的方法,下面看整体代码:

package reflect;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws IOException, NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //加载Properties对象
        Properties pro = new Properties();
        //获得一个类加载器,去寻找配置文件,你都能找到类文件还找不到配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        //加载配置文件
        pro.load(is);
        //在配置文件中定义数据
        String className= pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //加载该类进内存,找到这个类的字节码对象
        Class cls = Class.forName(className);
        Constructor cons = cls.getConstructor();
        //获得一个obj对象
        Object obj = cons.newInstance();
        //获取方法对象
        Method method = cls.getMethod(methodName);
        //再来执行方法
        method.invoke(obj);
    }
}

运行结果:

简单说一下注解对象的获取

 对于Java中使用@标明的注解,它们的底层实现都隐式地继承java.lang.annotation.Annotation接口。

我们可以通过上面两个方法获取注解对象

比如,我们判断某一个类上面有没有这个注解

传入注解的Class对象,注意这个对象是一个注解对象

其实这个函数接收的时候,里面泛型是会用一个Class<? extends Annotation> annotationClass

为什么要加这样一个泛型<? extends Annotation>

我们先来看一下上面的源码

 然后继续追进去

里面就是调用了一个getAnnotation()方法,只要这个对象不等于null,就返回真,反正就是只要返回这个对象

继续追进去

 他会给我们返回一个A类型的对象,这个对象必须是Annotation的对象

说一下强制类型转换如果类型不相关联,就会抛出一个ClassCastException异常,所以这里返回的一定与你传入的Class注解对象相互关联的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值