Java学习笔记——反射机制

一、反射的概述
从使用上来讲,反射就是获取某一类对象的属性、构造方法和方法,并对这些属性和方法进行操作,如设置访问权限、运行方法等。
效果上,反射能够提高代码的复用性,降低耦合度,因此许多的框架中都使用了反射的机制,下面就对反射的相关使用进行介绍,分别对应获取类及对类的操作、获取构造方法及对构造方法的操作、获取熟悉及对属性的操作、获取方法及对方法的操作。并最后给出一个使用实例,更好地体会反射机制所带来的代码复用性的提高。

二、反射的方法概述

在这里插入图片描述

在测试开始之前先设置一Student测试类如下所示,该测试类参考
https://blog.csdn.net/sinat_38259539/article/details/71799078

public class Student {
    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex
                + ", phoneNum=" + phoneNum + "]";
    }


    //无参构造方法
    public Student(){
        System.out.println("调用了公有、无参构造方法执行了。。。");
    }

    //有一个参数的构造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }

    //有多个参数的构造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+"年龄:"+ age);
    }

    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }

    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法   年龄:"+ age);
    }
    public void show1(String s){
        System.out.println("调用了:公有的,String参数的show1(): s = " + s);
    }
    protected void show2(){
        System.out.println("调用了:受保护的,无参的show2()");
    }
    void show3(){
        System.out.println("调用了:默认的,无参的show3()");
    }
    private String show4(int age){
        System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
        return "abcd";
    }
}

2.1、关于类本身的反射操作方法

关于获取Class对象,有三种方式,分别是通过类的class属性获得、通过对象的getClass方法获得和通过Class类的静态方法利用类的名称获得,三者都会返回一个Class对象,下面就对这三种方法进行演示

        Student stu = new Student("姓名字段",1);

        /************下面演示获取Class对象的三种方式**********/
        //通过类名.class的方式
        Class<Student> studentClass = Student.class;
        System.out.println(studentClass);
        //通过调用对象的getClass的方式
        Class<? extends Student> aClass = stu.getClass();
        System.out.println(aClass);
        //通过Class的静态方法
        Class<?> student = Class.forName("Student");
        System.out.println(student);

输出结果如下
在这里插入图片描述

2.2、关于构造方法的反射操作方法

2.2.1、构造方法Construcor<?>对象的获取

getConstructors()方法和getDeclaredConstructors()方法分别会获得public修饰的构造方法和所有的构造方法,返回一个Constructor数组

//获取所有的公共构造方法
        Constructor<?>[] constructors = studentClass.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("********分割线**********");

        //获取所有的构造方法(不论何种访问权限符修饰)
        Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }

运行效果:
在这里插入图片描述

//根据参数获得构造方法,注意这里的int.class与Integer.class还是不一样的,一定要区分好
Constructor<Student> constructor = studentClass.getConstructor(String.class,int.class);
System.out.println(constructor);

使用getConstructor方法,根据参数可以获得特定的构造方法
这里需要注意两点
第一点是getConstructor方法只能从public修饰的公共方法中获取,第二点是在获取Constructor对象的方法中,Integer.class和int.class是不一样的,要做好区分

在这里插入图片描述

2.2.2、反射得到的构造方法的使用

使用Constructor类的newInstance方法进行执行,可以得到一个实例化的对象

       Student student = constructor.newInstance("反射构造测试", 1);

        System.out.println(student);

运行结果:
在这里插入图片描述

2.3、关于属性的反射操作方法

2.3.1、属性Field对象的获取

与构造方法的获取一样,属性同样有获取公共与获取所有的两种方式,下面给出代码和运行结果

        //获取所有公共属性并打印
        Field[] fields = studentClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("********分界线**********");

        //获取所有属性并打印
        Field[] declaredFields = studentClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

运行结果:
在这里插入图片描述

2.3.2、反射得到的属性的使用

获取到Field对象之后就可以对Filed对象调用set方法进行修改,set方法需要传递两个值,一个是实例化的对象,也就是要修改哪个对象的字段,另一个是修改后的值,set方法是void类型的,不返回值。
值得注意的是,除了public修饰的字段之外,要修改的话需要调用setAccessible方法,传递true,将这一字段设置成可以修改的,下面给出代码和运行结果。

        //获取属性
        Field name = studentClass.getField("name");
        //更改某一对象的这一属性
        name.set(student,"属性已更改");
        System.out.println(student);

        //更改非公有属性的时候就需要调用
        Field phoneNum = studentClass.getDeclaredField("phoneNum");
        phoneNum.setAccessible(true);
        phoneNum.set(student,"123");
        System.out.println(student);

运行结果:
在这里插入图片描述

2.4、关于类中方法的反射方法

2.4.1、方法Method对象的获取

Method对象的获取也是有获取public修饰的与所有的两种方式,与上文所述基本类似,不再赘述,因此只给出代码使用实例与运行效果如下

//获取所有public修饰的方法
        for (Method method : studentClass.getMethods()) {
            System.out.println(method);
        }

        //获取所有方法
        for (Method declaredMethod : studentClass.getDeclaredMethods()) {
            System.out.println(declaredMethod);
        }

运行效果:
在这里插入图片描述
从运行结果可以看出getMethods()方法还会输出父类的public方法,包括Object类的

2.4.2、反射得到的方法的使用

Method对象通过invoke方法进行执行,invoke方法需要两组参数,一是一个实例化的对象,第二就是要执行的方法所需要的参数,如果是无参的,可以传递null或者直接不写,下面给出代码和运行效果

        //运行特定方法(public的与非public修饰的)
        Method show1 = studentClass.getMethod("show1", String.class);
        show1.invoke(student,"乌拉!");

        Method show2 = studentClass.getDeclaredMethod("show2");
        show2.invoke(student);

运行效果:
在这里插入图片描述

三、反射的使用实例

在黑马面面项目的前台系统中,通过获取URI来调用不同的方法,代码如下
BaseServlet类的doGet和doPost方法

    //运用反射的思想通过不同的路径,调用不同的子类中的路径同名方法,完成了代码的抽取
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //requestURI是不包含?后面的参数的
        String url = req.getRequestURI();
        //提取URI的包含操作内容的部分
        String methodName = url.substring(url.lastIndexOf('/') + 1);
        //因为是子类调用doGet方法,所以this此处就是得到的具体实行的子类的类对象
        Class clazz = this.getClass();
        try {
            //获取子类的URI同名方法
            Method method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            //执行方法并返回值
            Result result = (Result) method.invoke(this, req, resp);
            this.returnData(resp,result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

对应的子类的代码

@WebServlet("/member/*")
public class MemberServlet extends BaseServlet {

    public Result register(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        Member member = getData(req, Member.class);
        boolean registerResult = memberService.register(member);
        if(registerResult){
            return new Result("注册成功!", null);
        } else {
            return new Result("注册失败!", null);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值