15. Java反射和注解

news2024/11/24 6:55:25

Java —— 反射和注解

      • 1. 反射
      • 2. 注解

1. 反射

动态语言:变量的类型和属性可以在运行时动态确定,而不需要在编译时指定
常见动态语言:Python,JavaScript,Ruby,PHP,Perl;常见静态语言(C,C++,C#,Go,Java)
Java:Java并不算是严格意义上的动态语言,从反射角度来说属于半动态语言(能通过反射机制实现了部分动态编程的能力)
Java反射机制:Java编程语言提供的一种强大的特性,它允许程序在运行时动态地获取类的信息,并通过该信息操作类的成员变量、方法和构造函数

Java 的反射机制:在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法

Java反射常用API
Class 类:反射的核心类,可以获取类的属性,方法等信息
Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值
Method类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法
Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法
获取Class对象的3种方法
           调用某个对象的getClass()方法
             ❶ 类名 对象名 = new 类名();
             ❷ Class 类对象名 = 对象名.getClass();
           使用Class类中的forName()静态方法(安全且性能好)
             ❸ Class 类对象名 = Class.forName(“类的完全限定名”);
高版本Java创建:var 类对象名 = 类名(需要创建类对象的类).class;
        Class<类型(类名)> 类对象名 = 类名(需要创建类对象的类.class;

  • 对应类的常用方法
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 对应代码
package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 反射机制
 */

public class TestDemo {
    public static void main(String[] args) throws NoSuchMethodException,
            InvocationTargetException, IllegalAccessException,
            InstantiationException, NoSuchFieldException {
        // 创建类对象
        var classes = Information.class;
        System.out.println("类名:" + classes.getSimpleName());

        // 根据类获取当前类的完全限定名
        String className = classes.getName();
        System.out.println("当前类的完全限定名:" + className);

        // 根据获取当前类的包名
        String packageName = classes.getPackageName();
        System.out.println("包名:" + packageName);

        // 根据类获取当前普通方法名
        List<String> list = new ArrayList<>();
        Method[] methods = classes.getMethods();
        for (Method method : methods
        ) {
            list.add(method.getName());
        }
        System.out.println("public方法个数:" + list.size());
        System.out.println("public方法:" + list);


        // 获取构造器(无参构造器)
        Constructor<Information> constructor = classes.getConstructor();
        // 利用无参构造器创建实例
        Object obj = constructor.newInstance();

        // 获取指定的普通方法,带参数
        Method publicMethod = classes.getMethod("publicMethod", String.class, int.class);

        // 获取指定私有方法
        Method privateMethod = classes.getDeclaredMethod("privateMethod", String.class);
        System.out.println("获取指定私有方法:" + privateMethod);

        // 强行开启私有方法访问权限
        privateMethod.setAccessible(true);

        // 获取所有普通public属性
        Field[] fields = classes.getFields();
        System.out.println("普通属性:" + Arrays.toString(fields));
        // 获取所有属性
        Field[] declaredFields = classes.getDeclaredFields();
        System.out.println("所有属性:" + Arrays.toString(declaredFields));

        // 获取属性名
        for (Field field:declaredFields
             ) {
            String name = field.getName();
            System.out.print(name + ", ");
        }
        System.out.println();


        // 访问单个私有属性
        Field name = classes.getDeclaredField("name");
        // 强行打开权限
        name.setAccessible(true);
        System.out.println("访问单个私有属性:名称:" + name.getName() + "   类型:" +
                name.getType() + "  权限修饰符(二进制位标识的修饰符信息):" + name.getModifiers());


        // 私有方法调用
        privateMethod.invoke(obj, "零零");
        // 方法调用
        publicMethod.invoke(obj, "夏鸥", 22);

        System.out.println("无参构造器创建的实例:" + obj);

        // 获取有参构造器
        Constructor<Information> constructors = classes.getConstructor(String.class, int.class, String.class);
        // 有参构造器创建实例
        Object object = constructors.newInstance("王菲", 20, "2020002");

        // 获取指定的普通方法
        Method classesMethod = classes.getMethod("publicMethod");
        // 方法调用
        classesMethod.invoke(object);

        System.out.println("有参构造器创建的实例:" + object);
    }
}

class Information{
    private String name = "赫敏";
    private int age = 20;
    public String num = "2020001";

    public Information() {
    }

    public Information(String name, int age, String num) {
        this.name = name;
        this.age = age;
        this.num = num;
    }

    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 String getNum() {
        return num;
    }

    public void setNum(String num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "TestDemo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", num='" + num + '\'' +
                '}';
    }

    private void privateMethod() {
        System.out.println(name + " 私有方法");
    }

    private void privateMethod(String name) {
        this.name = name;
        System.out.println(name + "  私有方法");
    }

    public void publicMethod() {
        System.out.println(name + " 普通方法");
    }

    public void publicMethod(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println(name + age + " 普通方法");
    }
}
  • 应用实例
package reflect;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;

/**
 * 要求:实例化与当前类在统一和包中的所有类
 */
public class Instantiations {
    public static void main(String[] args) throws ClassNotFoundException, URISyntaxException, NoSuchMethodException,
            InvocationTargetException, InstantiationException, IllegalAccessException {
        /* 1. 获取当前包中的所有类名 */
        // 获取包名
        String packageName = Instantiations.class.getPackageName();
        // 获取当前绝对路径资源  ".":表示当前路径
        URL path = Instantiations.class.getResource(".");
        // 获取路径下的所有文件
        File file = new File(path.toURI());
        // 将所需文件过滤存储到数组(所有类)
        File[] files = file.listFiles(f -> f.getName().endsWith(".class"));

        // 获取到
        for (File sub:files
             ) {
            String name = sub.getName();
            // 获取类名
            String className = name.replace(".class", "");
            System.out.println("实例化类:" + packageName + "." + className);
            Class<?> classes = Class.forName(packageName + "." + className);
            // 通过无参构造器创建实例
            Object obj = classes.getConstructor().newInstance();
            System.out.println(obj);
        }
    }
}

2. 注解

注解:元数据 / 注解(注解Annotation是一个接口),一种提供程序中元素信息和数据的途径和方法
作用:在不改变程序主体逻辑的情况下,为程序员提供额外的元数据信息(标记一段代码的功能、作用范围、参数要求等信息)

4种标准元注解:元注解的作用是负责注解其他注解
       ❶ @Target 注解修饰范围 / 修饰的目标元素类型
       ❷ @Retention:注解生命周期 / 保留级别 / 被保留的时间长短
       ❸ @Documented注解是否会被包含在Java文档中生成
       ❹ @Inherited注解是否可以被继承
  @Target元素类型
       ElementType.TYPE:类、接口或枚举类型
       ElementType.FIELD:字段或属性
       ElementType.METHOD:方法
       ElementType.PARAMETER:方法参数
       ElementType.CONSTRUCTOR:构造函数
       ElementType.LOCAL_VARIABLE:局部变量
       ElementType.ANNOTATION_TYPE:注解类型
       ElementType.PACKAGE:包
  @Retention的三个值
       RetentionPolicy.SOURCE:注解仅存在于源代码中,编译时会被丢弃
       RetentionPolicy.CLASS:注解存在于源码和编译后的字节码文件中,但在运行时会被丢弃(默认值)
       RetentionPolicy.RUNTIME:注解在运行时保留在字节码文件中,可以通过反射机制读取
  @Documented和@Inherited
       一个注解被@Documented修饰,那么它的信息将会被包含在生成的文档中
       一个注解被@Inherited修饰,表示该注解可以被子类继承

  • 基本原则:不直接干扰程序代码的运行
    Java 注解是一种元数据,它可以提供对程序元素(如类、方法、字段等)的额外信息或配置,并且不会直接影响程序的运行逻辑,只是一种机制,用于存储和传递额外的信息
  • 注解分类
    在这里插入图片描述

  • 声明注解及变长参数

package reflect.annotations;

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

// 注解类型
@Target(ElementType.METHOD)
// 注解级别
@Retention(RetentionPolicy.RUNTIME)
// 声明注解
public @interface AutoRunMethod {
    // 注解的参数(当注解下的参数只有一个时,一般用value)
    int value() default 1;
    String name() default "张三";
}
  • 使用注解
package reflect;

import reflect.annotations.AutoRunClass;
import reflect.annotations.AutoRunMethod;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.Arrays;

public class Reflect {
    public static void main(String[] args) {
        // 加载包下被注解的类被注解的方法
        try {
            String packName = Reflect.class.getPackage().getName();
            File dir = new File(Reflect.class.getResource(".").toURI());
            File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
            for (File sub:subs
            ) {
                String className = sub.getName().replace(".class","");
                Class classes = Class.forName(packName + "." + className);
                if (classes.isAnnotationPresent(AutoRunClass.class)){
                    System.out.println("实例化:" + className);
                    Constructor constructor = classes.getConstructor();
                    Object obj = constructor.newInstance();
                    System.out.println(obj);

                    // 方法名获取
                    Method[] methods = classes.getDeclaredMethods();
                    for (Method method:methods
                         ) {
                        // 判断该方法是否被注解
                        if (method.isAnnotationPresent(AutoRunMethod.class)){
                            System.out.println("调用方法:" + method.getName() + "()");

                            // 获取注解参数
                            AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
                            // 获取值(定义时将其认为参数,调用时看作方法)
                            int value = arm.value();
                            String name = arm.name();
                            System.out.println("注解参数的值:" + value + name);

                            // 根据注解参数的值调用方法
                            for (int i = 0; i < value; i++) {
                                // 方法调用
                                method.invoke(obj);
                            }
                        }
                    }
                }
            }
        } catch (URISyntaxException | ClassNotFoundException |
                 NoSuchMethodException | InstantiationException |
                 IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }

    }
}

// 注解类
@AutoRunClass
class Student {
    public String address = "贵阳市花溪区";
    private String name = "赵涛";
    private char gender = '男';
    private int age = 15;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // 注解方法
    @AutoRunMethod(3)
    public void sayHi() {
        System.out.println(name + ":你好");
    }

    @AutoRunMethod(value = 2, name = "李四")
    public void sleep() {
        System.out.println(name + ":睡觉");
    }

    @AutoRunMethod(name = "王五")
    public void watchTV() {
        System.out.println(name + ":看电视");
    }

    public void playGame() {
        System.out.println(name + ":玩游戏");
    }

    public void say(String info) {
        System.out.println(name + "说:" + info);
    }

    public void say(String info, int count) {
        System.out.println(name + "说了" + count + "次," + info);
    }

    public void study() {
        System.out.println(name + "学习");
    }

    @AutoRunMethod
    public void doHomework() {
        System.out.println(name + ":做作业");
    }

    // **********************普通方法(参数变长)只是Java编译器认可(最终为数组)***************************
    // 变长参数只能在方的最后一个参数,且一个方法只能有一个变长参数
    public void doSome(String... s) {
        System.out.println("参数个数:" + s.length);
        System.out.println("参数:" + Arrays.toString(s));
    }

    private void privateMethod() {
        System.out.println("这是一个私有方法");
    }

    @Override
    public String toString() {
        return "Student{" +
                "address='" + address + '\'' +
                ", name='" + name + '\'' +
                ", gender=" + gender +
                ", age=" + age +
                '}';
    }
}
  • 变长参数只能在方的最后一个参数,且一个方法只能有一个变长参数
  • 注解格式:
          类型 参数名() [default 默认值] 注:不指定默认值时使用注解必须传递对应参数
  • 注解传参机制:
    当注解仅有一个参数,且参数名为value时,直接传入参数(不需要参数名)
    当注解仅有一个参数,且参数名不为value时,正常使用注解传参语法:参数名=参数值
    多个参数传参使用参数名进行传参,传参顺序可以与注解定义时参数顺序不一致
    有多个参数时,即使一个注解的参数名为value,在实际使用时参数名也不可以忽略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091124.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP报错CX_SY DYN CALL PARAM MISSING

DYN CALL METH PARAM MISSING CX_SY DYN CALL PARAM MISSING 在 ABAP 中&#xff0c;当你定义一个方法时&#xff0c;可以选择将方法的参数标记为可选&#xff08;可选参数&#xff09;或必需&#xff08;必需参数&#xff09;。如果你不勾选可选参数选项&#xff0c;那么该参…

【AI视野·今日Sound 声学论文速览 第二十五期】Fri, 13 Oct 2023

AI视野今日CS.Sound 声学论文速览 Fri, 13 Oct 2023 Totally 8 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers Impact of time and note duration tokenizations on deep learning symbolic music modeling Authors Nathan Fradet, Nicolas Gutowski,…

Sentinel-2 命名规则(Naming Convention)

下述命名规则是2019年12月6日颁布的&#xff0c;自此之后的L1C级别产品都按照这个规则命名&#xff08;其他级别的产品官网没说&#xff09;。 下载下来的文件是个zip&#xff0c;解压后是个与zip同名的 .SAFE 文件。 MMM_MSIXXX_YYYYMMDDHHMMSS_Nxxyy_ROOO_Tnnmab_<Produ…

Modelsim查看波形窗口内断言(SVA)消息指示器

步骤1&#xff1a;创建工程并编译完成 在相应目录下创建好工程并编译无错误后&#xff1b; 步骤二&#xff1a; 在菜单栏中选择“Simulate”—>“Start Simulation”—>“Others”,在“Others Vsim Options”中输入 -msgmode both -displaymsgmode both 步骤三&#xf…

Leetcode——数组的改变、移动练习

453. 最小操作次数使数组元素相等 本人答案超时 class Solution { public:int minMoves(vector<int>& nums) {int len nums.size();int count 0;if (len 1) {count 0;}else {while (nums[0] ! nums[1] || nums[len - 2] ! nums[len - 1]) {for (int i 0; i <…

搭建一个vscode+uni+vue的小程序项目

我们使用 vue2 创建工程作为示例&#xff0c;uni-app中Vue2版的组件库和插件也比较多&#xff0c;稳定、问题少&#xff0c;可以先参考下官方文档:uni-app官网 既然是使用vue脚手架&#xff0c;那肯定要全局安装vue/cli&#xff0c;已安装的可以跳过。 注意&#xff1a;Vue2创…

面试题-React(十二):React中不可变数据的力量

一、不可变数据的概念 不可变数据意味着数据一旦创建&#xff0c;就不能被更改。在React中&#xff0c;每次对数据的修改都会返回一个新的数据副本&#xff0c;而不会改变原始数据。这种方式确保了数据的稳定性和一致性。 二、Props中的不可变数据 在React中&#xff0c;组件…

【数据结构】:二叉树与堆排序的实现

1.树概念及结构(了解) 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合把它叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的有一个特殊的结点&#…

湖南省人才档案查询

湖南省人才档案查询 微信中查询智慧人社公众号 进入智慧人社公众号&#xff0c;点击智慧人社按钮 点击人才档案查询 查看档案信息

chapter8 Dimensionality Reduction(降维)

设置 首先&#xff0c;确保代码在python2和python3中都能正常工作&#xff0c;导入一些通用模块&#xff0c;确保MatplotLib以内联方式绘制图形&#xff0c;并准备一个函数来保存这些图形: from __future__ import division,print_function,unicode_literalsimport numpy as …

异星工场入门笔记-01

两年前玩过一点&#xff0c;不看教程&#xff0c;单纯地开放世界自己探索&#xff0c;没有同类游戏经验&#xff0c;因此很难有获得感所以放弃了。现在正版游戏涨到130&#xff0c;看在逆势上涨的份上&#xff0c;我倒想继续探索下这个游戏的价值。 玩魔方&#xff0c;记教程步…

深度学习之使用CSDN的InsCode的服务器

CSDN开启了一个InsCode的栏目&#xff0c;在里面可以部署自己的项目&#xff0c;同时可以租赁GPU服务器&#xff1a; 由于博主在CSDN有些积蓄&#xff0c;因此便来测评一下&#xff0c;博主购买了3090这个型号 接下来便是登录使用了&#xff0c;博主使用的是Mobaxterm这个软件&…

彻底解决Qt中文乱码以及汉字编码的问题(UTF-8/GBK)

彻底解决Qt中文乱码以及汉字编码的问题&#xff08;UTF-8/GBK&#xff09; Chapter1 (彻底解决Qt中文乱码以及汉字编码的问题&#xff08;UTF-8/GBK&#xff09;一、Qt Creator环境设置二、编码知识科普Qt常见的两种编码是:UTF-8和GBK 三、编码转换四、QString显示中文乱码的原…

铜死亡+多组机器学习+WGCNA+分型

今天给同学们分享一篇铜死亡多组机器学习WGCNA分型的生信文章“Machine learning screening for Parkinsons disease-related cuproptosis-related typing development and validation and exploration of personalized drugs for cuproptosis genes”&#xff0c;这篇文章于20…

3.3 封装性

思维导图&#xff1a; 3.3.1 为什么要封装 ### 3.3.1 为什么要封装 **封装**&#xff0c;在Java的面向对象编程中&#xff0c;是一个核心的思想。它主要是为了保护对象的状态不被外部随意修改&#xff0c;确保数据的完整性和安全性。 #### **核心思想&#xff1a;** - 保护…

TSINGSEE青犀智能分析网关如何助力别墅区域监控智能化信息化发展?

谈到别墅&#xff0c;大家一般都会想到花园、草坪、泳池等等&#xff0c;联想到的都是舒适放松的环境。别墅优美环境是不可否认的&#xff0c;但是别墅占地大、空间广、人员稀少也使得常常被盗贼“光顾”&#xff0c;即使别墅一般都会配备保安进行巡逻检查&#xff0c;但传统人…

【python编程】python无法import模块的一种原因分析

python系统路径添加错误 报错原因原因分析解决办法补充 最近写代码的时候遇到一个问题&#xff0c;就是想添加工程下fu_convert文件夹下自己编写的convert_fw.py模块&#xff0c;但是出现报错&#xff0c;是个比较低级的问题&#xff0c;但还是简单记录一下 报错原因 无法找到…

PHP遇见错误了看不懂?这些错误提示你必须搞懂

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《速学数据结构》 《C语言进阶篇》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 一、错误分类二、系统错误&#xff1a;2.1 编译错误2.2 致命错误2.3 警告错误2.4 通知错误 三、用户错误3.1 错…

GitLab使用步骤

GitLab使用步骤 1 注册用户 1 访问&#xff1a;http://10.0.0.203/users/sign_up地址 2 填入注册信息&#xff0c;注册成功&#xff0c;需要管理员审核 3 用root登录&#xff0c;地址&#xff1a;http://10.0.0.203/users/sign_in账号&#xff1a;root密码&#xff1a;xxxx…