Java学习——Java动态性之反射机制(reflection)

本文深入解析Java反射机制,包括动态加载类、获取类信息、构造器、方法和属性的动态操作,以及反射在泛型和注解上的应用,揭示Java的动态特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java学习——Java动态性之反射机制(reflection)

动态性:
  • 动态语言:程序在运行时,可以改变程序结构或者变量类型。典型的动态语言:Python、ruby、JavaScript等。
  • C、C++、Java不是动态语言,但是Java可以称之为准动态语言。但是Java有一定的动态性、我们可以利用反射机制、字节码操作获得类似于动态语言的特性。这样就使得Java更加灵活
反射机制:
  • 指的是在运行时再加载一些新的类
  • 程序在运行状态时,可以动态加载一个只有名称的类,对于任意一个已经加载的类都能知道这个类的所有信息(属性、方法);对于任何一个对象,都能调用它的任何一个属性和方法
  • 这个就是我们在反射中常用的一段代码,用来通过类名获取这个类的字节码对象
   	Class clazz = Class.forName("cn.xiyou.Scanner.MyTest");
  • 加载完类之后,在堆内存中就产生了一个class类型的对象(一个类只有一个class对象),这个对象包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像是一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
利用反射获取相关信息:

先创建一个标准的实体类:

public class Student {
    private String name;
    private int age;
    private int id;
    
    public Student() {
    }

    public Student(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

反射机制获取相关信息:

public class Test01 {
    public static void main(String[] args) throws Exception {
        /**
         * 对象是表示或封装一些数据。
         * 一个类被加载后,JVM会创建一个对应该类的Class对象,类的整个结构信息会被放到对应的Class对象中去
         */

        //利用反射获取类的信息(类名、属性、方法、构造器),注意:一个类只有一个Class对象
        Class clazz = Class.forName("cn.反射机制.demo01.Student");

        /*
         *  1.获取类的名字
         */
        String clazzName = clazz.getName();//(包名+类名)
        System.out.println(clazzName);

        String clazzSimpleName = clazz.getSimpleName();//类名
        System.out.println(clazzSimpleName);
        System.out.println("----------------这是一个华丽的分割线----------------");

        /*
         * 2.获得属性信息
         */
        //获取public的属性
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获取所有的属性(不论public和private)
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("属性:"+declaredField);
        }

        //获取某个属性(不论public和private)
        Field name = clazz.getDeclaredField("name");
        System.out.println(name);
        System.out.println("----------------这是一个华丽的分割线----------------");

        /*
         *3.获取方法信息
         */
        //获得所有public的方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //获取所有的方法(不论public和private)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("方法:"+declaredMethod);
        }

        //获取指定方法,参1:方法名,参2:传递的参数类型的class对象
        Method declaredMethod = clazz.getDeclaredMethod("getAge");
        System.out.println(declaredMethod);
        Method declaredMethod1 = clazz.getDeclaredMethod("setAge", int.class);
        System.out.println(declaredMethod1);

        System.out.println("----------------这是一个华丽的分割线----------------");

        /*
         *4.获取构造方法信息
         */
        //获取所有的构造器
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("构造器:"+constructor);
        }
        //获取无参构造
        Constructor constructor = clazz.getDeclaredConstructor(null);
        System.out.println("无参构造:"+constructor);
        //获取有参构造
        Constructor constructor1 = clazz.getDeclaredConstructor(String.class,int.class,int.class);
        System.out.println("有参构造:"+constructor1);
    }
}
通过反射动态操作:构造器、方法、属性:
/**
 * 通过反射动态操作:构造器、方法、属性
 */
public class Test02 {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.反射机制.demo01.Student");

        /*
         * 1.通过反射动态操作构造方法,构造对象
         */
        //通过调用的是无参构造器构造对象
        Student student = (Student) clazz.newInstance();
        System.out.println(student);

        //通过调用的是有参构造器构造对象
        Constructor c = clazz.getDeclaredConstructor(String.class,int.class,int.class);
        Student student2 = (Student) c.newInstance("张三", 18, 02165055);
        System.out.println(student2.getName()+"==="+student2.getAge()+"==="+student2.getId());


        /*
         * 2.通过反射操作方法
         */
        //通过反射调用方法
        Student student3 = (Student) clazz.newInstance();
        Method method = clazz.getDeclaredMethod("setName", String.class);
        method.invoke(student3,"李四");

        /*
         * 3.通过反射操作属性
         */
        Student student4 = (Student) clazz.newInstance();
        Field f = clazz.getDeclaredField("name");
        //setAccessible(true)意思是:这个属性关闭安全检查,直接可以访问(就可以访问private的属性了),提高效率
        f.setAccessible(true);
        f.set(student4,"王五");//给student4的name设置值
        String sname = (String) f.get(student4);//获取student4的name值
        System.out.println(sname);
    }
}
  • 我们还需要知道,反射固然强大,但是它在执行效率上还是不如正常执行。那么我们可以适当的使用setAccessible()打开关闭访问检查用来提高效率。
反射操作泛型(Generic)(了解):

Java中的泛型是在编译器给javac使用的,确保数据的安全性和免掉强制类型转换的麻烦。但是一旦编译完成,所有的泛型都会被擦除。那么Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到class类中的类型但是又和原始类型齐名的类型。

  • ParameterizedType:表示一张参数化的类型,比如:Collection< String >
  • GenericArrayType:泛型数组类型
  • TypeVariable:是各种泛型变量的公共父接口
  • WildcardType:代表一种通配符类型表达式,比如?,?extends Number,?super Integer
反射操作注解(了解):
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {

        Class clazz = Class.forName("cn.反射机制.demo01.Student");
        //获取这个类的所有注解
        Annotation[] annotations = clazz.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获取类指定注解的值
        MyTable tb = (MyTable) clazz.getAnnotation(MyTable.class);
        System.out.println(tb.value());

        //获得类的属性的注解
        Field f = clazz.getDeclaredField("name");
        MyField myField = f.getAnnotation(MyField.class);
        System.out.println(myField.name()+"--"+myField.type()+"--"+myField.length());


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值