Java 的反射机制 2021-07-10

Reflection 反射

反射是被视为动态语言的关键,反射机制允许程序在执行期间借助于 
Reflection Api 取得任何类的内部信息,并能直接操作任对象的内部属性及其方法

反射是什么:反射就是可以获取到所有在运行时的类,并且可以获取到他们的方法,属性,构造函数

加载完类之后,在JVM堆内存中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构。

这个对象就就像一面镜子,可以通过这个镜子看到类的结构,所以,我们形象的称之:反射

区别

正常的方式:引入 Java 类的路径 → new 一个类 → 获取到实例化对象 反射获取类:实例化对象
→ getClass() → 得到完整的包类名称

动态语言 VS 静态语言

动态语言

是一个类在运行时可以改变其结构的语言:列入:新的函数,对象,甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗来说就是在运行时代码可以根据某些条件改变自身的类结构
主要的动态语言有:Object-C,C#,JavaScript,PHP,Python,Eriang,Vue

静态语言

与静态语言相对应的。运行结构不可变的语言就是静态语言。如Java,C,C++

注:Java 是准动态语言,因为Java 有一定的动态性,我们可以利用反射机制,字节码操作获取类型动态语言的特性。Java 的动态性让编程的时候更加灵活

Java 反射机制提供的功能

1.在运行是判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.运行是获取泛型信息
5.在运行时调用任意一个对象的成员变量和方法
6.在运行时处理注解
7.生成动态代理

在运行时调用任意一个对象的成员变量和方法

实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
 * @author FengRui
 * @Title: 人
 * @date 2021/07/10 18:17
 */
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class  Person {

    private String name;
    public Integer age;

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

    public Person(Integer age){
        this.age = age;
    }

    public void show(){
        System.out.println("姓名为:"+this.name+",年龄为:"+this.age);
    }

    private String showNation(String nation){
        System.out.println("我的国籍是:"+nation);
        return nation;
    }
}

测试类代码

package reflection;


import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @author FengRui
 * @Title: 反射测试
 * @date 2021/07/10 18:15
 */
@Slf4j
public class ReflectionTest {

    /** methodsEffect
    * @Description:  反射之前 person  的操作
    * @Param:
    * @return:
    * @Author: FengRui
    * @Date: 2021/07/11
    */
    public static void test1(){
        //正常情况下,不能调用类的私有的方法或者属性
        log.info("1.创建Person 类的对象");
        Person person = new Person(
                "封瑞"
        );
        log.info("2.通过对象,调用其内部的属性方法");
        person.setAge(20);
        person.show();
    }

  	/** methodsEffect
    * @Description: 通过反射调用调用私有的方法
    * @Param:
    * @return:
    * @Author: FengRui
    * @Date: 2021/07/11
    */
    public static void test3() throws  Exception{
        log.info("1.获取到 类的class");
        Class aClass=Person.class;
        log.info("2.给看类的构造函数设设置类型");
        Constructor cons = aClass.getConstructor(String.class);
        log.info("3.设置 为 true 可以调用私有方法, 设置为false 不可以调用私有方法,默认为false");
        //如果构造函数是公共的就不用设置
        cons.setAccessible(true);
        log.info("4.将值塞入到 class 的构造函数中");
        Person obj =(Person)cons.newInstance("封瑞");
        log.info("5.根据方法名获取到方法");
        //aClass.getDeclaredMethod() 其中 第一个参数是方法名,第二个参数是 方法名中参数的类型
        Method showNation = aClass.getDeclaredMethod("showNation", String.class);
        log.info("6.将私有方法设置为可以可以调用的");
        //如果方法是公共的就不用设置
        showNation.setAccessible(true);
        log.info("7.将参数塞到名称为 showNation 方法中");
        showNation.invoke(obj,"中国");
        log.info("8.根据字段名称来获取字段");
        Field name = aClass.getDeclaredField("name");
        log.info("9.将私有的字段设置为可以赋值的");
        name.setAccessible(true);
        log.info("10.将值设置到name字段中");
        name.set(obj,"封瑞");
        log.info("11.输出");
        System.out.println(obj.toString());
    }


    public static void main(String[] args)throws Exception {
        ReflectionTest.test3();
    }


    public static void test100(){
        int list[]= new int[]{1,2,3,4,5,6,-10,7};
        int listLength = list.length-1;
        for (int i = listLength;i>=list.length/2;i--){
            int value =list[listLength-i];
            list[listLength-i] =list[i];
            list[i] = value;
        }
        System.out.println(Arrays.toString(list));
    }
    public static void test101(){
        int list[]= new int[]{1,2,3,4,5,6,-10,7};
        for (int i = 0; i < list.length / 2; i++) {
            int temp = list[i];
            list[i] = list[list.length - i - 1];
            list[list.length - i - 1] = temp;
        }

        for (int i = 0; i < list.length; i++) {
            System.out.print(list[i ]+ "\t");
        }
    }
}

输出的结果

在这里插入图片描述

疑问

问题一:通过直接new 的方式或者反射的方式都可以调用公共的方法,开发中到底用那个?
问题二:反射机制与面向对象中的封装是不是矛盾?如何看待这2个技术?

问题一的解答

如果能确定一个类 需要实现 哪一个类的话建议直接用 new 既可
如果不能确定需要实现某个类 的话,建议使用 反射的方式
反射的特性:动态性

问题二的解答

不矛盾的!因为Java 中本来就是推荐是用封装后的方法去赋值,但是你就是不想用封装后的方法去赋值也是可以的;也就相当于在开发一个项目中,某些功能我可以不用,但是你一定要有

注释:

 关于Java。Lang.Class 类的理解
 1.类的加载
 程序经过Java.exe 命令以后,会生成一个或多个字节码文件(.class 结尾),接着我们使用 java.exe 命令对某个字节码文件允许解释既可,也就相当于将某个文件加载到内存当中
 加载到内存中的类,我们就称之为运行时类,此运行时类,就作为Class 的一个实例
2.换句话说,Class 的实例就对应着一个运行时类.
3. 反射主要是想要获动态性

在这里插入图片描述

获取运行时类的注解,方法(方法的注解),构造函数,字段(字段的注解)

package com.test;

import lombok.Data;

import java.io.Serializable;

/**
 * @author FengRui
 * @Title: 父类
 * @date 2021/07/12 17:20
 */
@Data
public class Creaturn<T> implements Serializable {
    private char gener;
    public double weight;

    private void breath(){
        System.out.println("弟弟开始吃哦里给");
    }

    public void eat(){
        System.out.println("弟弟开始呀屎");
    }
}

package com.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Type;

/**
 * @author FengRui
 * @Title: 测试注解
 * @date 2021/07/12 19:39
 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE, ElementType.MODULE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "hello";
}
package com.test;

/**
 * @author FengRui
 * @Title: 测试接口
 * @date 2021/07/12 19:30
 */
public interface MyInferface {

    void info()throws Exception;
}
package com.test;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;

/**
 * @author FengRui
 * @Title: 测试类
 * @date 2021/07/12 17:19
 */
@AllArgsConstructor
@NoArgsConstructor
@ToString
@MyAnnotation(value = "注解:弟弟爱吃哦里给")
public class Person extends Creaturn<String> implements Comparable<String>,MyInferface{

    @MyAnnotation(value = "注解:弟弟爱吃哦里给")
    public int id;
    int age;
    private String name;


    @MyAnnotation(value = "person的构造函数,形参名称:name")
    private Person(String name){
        this.name= name;
    }


    Person(String name,int age){
        this.name = name;
        this.age=age;
    }
    @MyAnnotation
    private String show(String name)throws Exception{
        System.out.println("我的是:"+name);
        return name;
    }

    public String display(String interests)throws IndexOutOfBoundsException,NullPointerException{
        return interests;
    }

    @Override
    public int compareTo(String s) {
        return 0;
    }

    @Override
    public void info()throws Exception {
        System.out.println("我叫河蚌猪,每天爱呀屎");
    }
}

测试类

package com.test2;

import com.test.Person;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import javax.print.PrintService;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;

/**
 * @author FengRui
 * @Title: 获取运行时类的所有属性,方法,注解,构造函数等等
 * @date 2021/07/12 19:48
 */
@Slf4j
public class ClassTest {

    /**
     * methodsEffect
     *
     * @Description: 获取当前运行时类的变量
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/12
     */
    @Test
    public void test1() {
        Class<Person> clazz = Person.class;
        log.info("获取到所有参数的名称");
        // 可以获取到当前运行时类及其父类的所有public的属性
        for (Field field : clazz.getFields()) {
            System.out.println(field);
        }
        log.info("获取到当前运行时类所有的属性(包含私有的)(不包含父类中的属性)");
        for (Field declaredField : clazz.getDeclaredFields()) {
            System.out.println(declaredField);
        }
    }

    /**
     * methodsEffect
     *
     * @Description: 获取当前运行时类的 属性 的 权限修饰符,数据类型,变量名
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/12
     */
    @Test
    public void test11() {
        Class<Person> clazz = Person.class;
        log.info("获取到所有参数的名称");
        // 可以获取到当前运行时类及其父类的所有public的属性
//        for (Field field : clazz.getFields()) {
//            for (Annotation annotation : field.getAnnotations()) {
//                // 属性的注解
//                System.out.println(annotation);
//            }
//            System.out.println(Modifier.toString(field.getModifiers())+" "+field.getType()+" "+field.getName()+"\n");
//        }
        log.info("获取到当前运行时类所有的属性(包含私有的)(不包含父类中的属性)");
        for (Field field : clazz.getDeclaredFields()) {
            for (Annotation annotation : field.getAnnotations()) {
                // 属性的注解
                System.out.println(annotation);
            }
            System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getType() + " " + field.getName() + "\n");
        }
    }

    /**
     * methodsEffect
     *
     * @Description: 获取当前运行时类的方法 ,方法名,权限修饰符,返回类型,形参
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/12
     */
    @Test
    public void test2() {
        Class<Person> clazz = Person.class;
        log.info("获取到所有的方法(不包含私有的)(包含父类的public 方法)");
        // 获取到所有的方法(不包含私有的,但是包含父类的public 方法)
//        for (Method declaredMethod : clazz.getMethods()) {
//            for (Annotation annotation : declaredMethod.getAnnotations()) {
//                //获取到方法上的注解
//                System.out.println(annotation);
//            }
//            System.out.print(Modifier.toString(declaredMethod.getModifiers())+" "+declaredMethod.getReturnType().getName()+" "+declaredMethod.getName());
//            System.out.print("(");
//            for (Parameter parameter : declaredMethod.getParameters()) {
//                //获取形参和形参名称
//                System.out.print(parameter.getType()+" "+parameter.getName());
//            }
//            System.out.print(")");
//            //开始获取方法抛出的异常
//            if (declaredMethod.getExceptionTypes()!=null &&declaredMethod.getExceptionTypes().length>0) {
//                System.out.print("throws ");
//                for (Class<?> exceptionType : declaredMethod.getExceptionTypes()) {
//                    System.out.print(exceptionType.getTypeName());
//                    if (declaredMethod.getExceptionTypes().length>1) {
//                        System.out.print(", ");
//                    }
//                }
//            }
//            System.out.println();
//        }
        log.info("获取到当前运行时类的所有的方法(不包含父类的方法)");
        //可以获取到 当前运行时类的的所有方法包括私有的(不包含父类的方法 (但是包含重写的方法)
        for (Method declaredMethod : clazz.getDeclaredMethods()) {
            for (Annotation annotation : declaredMethod.getAnnotations()) {
                //获取到方法上的注解
                System.out.println(annotation);
            }
            System.out.print(Modifier.toString(declaredMethod.getModifiers()) + " " + declaredMethod.getReturnType().getName() + " " + declaredMethod.getName());
            System.out.print("(");
            for (Parameter parameter : declaredMethod.getParameters()) {
                //获取形参和形参名称
                System.out.print(parameter.getType() + " " + parameter.getName());
            }
            System.out.print(")");
            //开始获取方法抛出的异常
            if (declaredMethod.getExceptionTypes() != null && declaredMethod.getExceptionTypes().length > 0) {
                System.out.print("throws ");
                for (Class<?> exceptionType : declaredMethod.getExceptionTypes()) {
                    System.out.print(exceptionType.getTypeName());
                    if (declaredMethod.getExceptionTypes().length > 1) {
                        System.out.print(", ");
                    }
                }
            }
            System.out.println();
        }
    }

    /**
     * methodsEffect
     *
     * @Description: 通过反射获取到父类
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/13
     */
    @Test
    public void test3() {
        Class<Person> clazz = Person.class;
        log.info("获取到所有的方法(不包含私有的)(包含父类的public 方法)");
        Class aClass = clazz.getSuperclass();
        for (Field field : aClass.getDeclaredFields()) {
            //后续操作统一和上面的方法是一样的
            System.out.println(field);
        }
    }


    /**
     * methodsEffect
     *
     * @Description: 调运运行时类的指定属性
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/13
     */
    @Test
    public void test4() throws Exception {
        Class<Person> clazz = Person.class;
        Person person = clazz.newInstance();
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(person, "弟弟爱吃哦里给");
        System.out.println(person.toString());
    }


    /**
     * methodsEffect
     *
     * @Description: 调运运行时类的指定构造函数
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/13
     */
    @Test
    public void test5() throws Exception {
        Class<Person> clazz = Person.class;
        Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Person person = constructor.newInstance("河蚌猪是傻逼");
        System.out.println(person.toString());
    }


    /**
     * methodsEffect
     *
     * @Description: 调运运行时类的指定方法
     * @Param:
     * @return:
     * @Author: FengRui
     * @Date: 2021/07/13
     */
    @Test
    public void test6() throws Exception {
        Class<Person> clazz = Person.class;
        Person person = clazz.newInstance();
        Method show = clazz.getDeclaredMethod("show", String.class);
        show.setAccessible(true);
        show.invoke(person,"中国");
    }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值