首页 > 编程语言 >Java 中的反射与注解

Java 中的反射与注解

时间:2023-09-09 16:11:35浏览次数:29  
标签:反射 Java name public Method 注解 MyAnnotation Class

一、反射 Reflection 和 元类 Class

Class 元类是对普通类的抽象,是类的类。Class 包含了一个类的所有属性,包括类名、包名、父类、实现的接口、所有方法、属性等。拿到一个类的 Class 元类,就拿到了这个类所有信息,就可以通过这些信息动态做一些处理。

通过一个类的 Class 实例获取类信息的方法就称为反射(Reflection)

获取类的 Class 元类对象

方法一:直接通过静态变量class获取:

Class cls = String.class;

方法二:如果我们有一个实例变量,可以通过该实例变量提供的getClass()方法获取:

String s = "Hello";
Class cls = s.getClass();

方法三:如果知道一个类的完整类名,可以通过静态方法Class.forName()获取:

Class cls = Class.forName("java.lang.String");

操作 Field 和 Method

拿到了类的 Class 元类实例就是调用如下方法获取类的属性和方法等。

Field getField(name):根据字段名获取某个public的field(包括父类)
Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
Field[] getFields():获取所有public的field(包括父类)
Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

Method getMethod(name, Class...):获取某个public的Method(包括父类)
Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
Method[] getMethods():获取所有public的Method(包括父类)
Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

操作类的属性,实现动态改变类

得到 Field 对象或 Method 对象后,get set 值时都需要指定一个该类的实例,也就是 get set 针对哪个对象操作。

Demo d = new Demo();
d.name = "testname";
clazz.getDeclaredField("name").get(d);// 参数 d 就是指定在 d 实例上做 get name 操作
clazz.getMethod("hello").invoke(d); // 参数 d 表示在 d 实例上调用 hello 对象

通过 Class 生成类实例

方式一:Class 对象的 newInstance 方法

Person p = Person.class.newInstance();

调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。

方式二:反射获取 Constructor 对象

// 获取构造方法,getConstructor方法参数传入类型要与构造方法需要的参数类型相符合。
Constructor<Demo> constructor = clazz.getConstructor(String.class, Integer.class);

// 通过 constructor 生成实例
Demo aaa = constructor.newInstance("aaa", 123);

// clazz在aaa对象上获取 name 属性
clazz.getDeclaredField("name").get(aaa);

二、注解的使用

注解分为定义注解,使用注解,解析注解。

注解有点像 Interface,但区别是注解中定义的方法,在使用时是通过属性赋值来使用的。

public @interface MyAnnotation {
    // getValue 定义类似 Interface 的方法
    // 区别是在注解使用时,不是调用 getValue,而是给 getValue 赋值,未赋值则默认使用 default 值。
    String getValue() default "no desc";
}

public class Demo {
    // 给 getValue 赋值一个字符串
    @MyAnnotation(getValue = "annotation on field")
    public String name;
}

元注解

元注解就是给注解用的注解,常用的是 @Target 和 @Retention

Target 声明本注解可用在什么位置,如 ElementType.TYPE, ElementType.FIELD, ElementType.METHOD

Retention 表明本注解保留到什么时候,分为 RetentionPolicy.RUNTIME RetentionPolicy.SOURCE RetentionPolicy.CLASS

如果需要再运行时动态处理的注解,没有声明为 RUNTIME,则再运行时中就反射不到注解了。

解析注解

解析注解就是通过反射 Reflection 获取到一个类的全部信息,包括类上面的注解,再根据注解和其中的属性值进一步做响应的处理。

注解完整三步

定义注解:

package com.sqkb.userasset;

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

/**
 * @Author songzai
 * @Date 2021/11/12 15:10
 */
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    // value属性在使用时可以省略 key 名,即不需要写 value = xxx
    int value() default 123;

    String getValue() default "no desc";

    String aaaa() default "default aaa";
}

Demo 实体类,使用注解

package com.sqkb.userasset;

/**
 * @Author songzai
 * @Date 2021/11/12 15:10
 */
// 不写参数名,默认复制给 value()
@MyAnnotation(444)
public class Demo {
    public Demo(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @MyAnnotation(getValue = "annotation on field")
    public String name;

    public Integer age;

    @MyAnnotation(getValue = "annotation on method")
    public void hello() {
        System.out.println("hello method");
    }

    public static void staticMethod() {
        System.out.println("static method");
    }

    @MyAnnotation()
    public void defaultMethod() {
    }
}

解析注解:

package com.sqkb.userasset;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Author songzai
 * @Date 2021/11/12 15:17
 */
public class AnnotationTest {
    public static void main(String[] args) throws Exception {
        Class<Demo> clazz = Demo.class;
        MyAnnotation annotationOnClass = clazz.getAnnotation(MyAnnotation.class);
        System.out.println(annotationOnClass.getValue());
        System.out.println(annotationOnClass.aaaa());

        Field name = clazz.getField("name");
        MyAnnotation annotation = name.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.getValue());
        System.out.println(annotation.aaaa());

        Method hello = clazz.getMethod("hello");
        MyAnnotation helloAnnotation = hello.getAnnotation(MyAnnotation.class);
        System.out.println(helloAnnotation.getValue());
        System.out.println(helloAnnotation.aaaa());

        Method defaultMethod = clazz.getMethod("defaultMethod");
        MyAnnotation defaultMethodAnnotation = defaultMethod.getAnnotation(MyAnnotation.class);
        System.out.println(defaultMethodAnnotation.getValue());
    }

}

本文由mdnice多平台发布

标签:反射,Java,name,public,Method,注解,MyAnnotation,Class
From: https://www.cnblogs.com/caipi/p/17689614.html

相关文章

  • java详细安装教程(供参考)一一java(jdk)安装
    一、java历史简介1991年Sun公司的JamesGosling等人开始开发名称为Oak(橡树)的语言。希望用于控制嵌入在有线电视交换盒、PDA等的微处理器,1994年将Oak语言更名为Java1998年JDK1.2时,更名为Java2Platform分为标准版J2SE,企业版J2EE,微型版J2MEJava既安全、可移植,又可跨平台,而且人......
  • JVM内存模型,JVM、JRE、JDK之间的关系,Java程序是如何执行的
    一、什么是JVMJVM是JavaVirtualMachine(Java虚拟机)的简称,是一个虚构出来的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM屏蔽了与具体操作系统平台相关的信息,Java程序只需生成在Java虚拟机上运行的字节码,就可以在多种平台上不加修改的运行。JVM在执行字节码时,实......
  • CentOS7.5报java: error while loading shared libraries: libjli.so: cannot open sh
    1.问题描述:CentOS版本:CentOS-7.5-x86_64-DVD-1804jdk版本:jdk-8u161-linux-x64.tar配置jdk时,执行java报错java:errorwhileloadingsharedlibraries:libjli.so:cannotopensharedobjectfile:Nosuchfileordirectory 2.解决方法:发现是CentOS7.5不支持jdk-8u161......
  • 无涯教程-JavaScript - IMSUM函数
    描述IMSUM函数以x+yi或x+yj文本格式返回两个或多个复数的和。当添加复数时,实数和虚数系数分别相加,即找到两个复数a+bi和c+di的和的方程为-(a+bi)+(c+in)=(a+c)+(b+d)我语法IMSUM(inumber1,[inumber2]...)争论Argument描述Required/OptionalInumb......
  • Java自学网站推荐--全网最靠谱
    简介网上有各种Java学习网站,本文推荐的这个Java网站全网最靠谱,质量远超其他所有网站。这个网站是:自学精灵,这是全网最强的Java学习网站,可以直接百度搜索自学精灵,或者访问:自学精灵-IT技术星球。我不喜欢“全网最强”这样的字眼,但本站的内容确实是全网最强!(大家可以多找几个Java网站......
  • 无涯教程-JavaScript - IMSUB函数
    描述IMSUB函数以x+yi或x+yj文本格式返回两个复数的差。减去复数时,实数和虚数系数分别相减,即从复数a+bi中减去复数c+di的方程为-(a+bi)-(c+in)=(a-c)+(b-d)我语法IMSUB(inumber1,inumber2)争论Argument描述Required/OptionalInumber1Thecomplexnumb......
  • java频繁的垃圾回收怎么处理
    频繁的垃圾回收可能是由于内存过度使用或存储管理不当引起的。以下是几种处理频繁垃圾回收的方法:1.增加内存分配:通过增加Java虚拟机的堆大小来提供更多的内存空间,可以减少垃圾回收的频率。可以使用-Xmx和-Xms参数来调整堆大小。2.优化对象的创建和销毁:避免过度频繁地创建和销毁对......
  • Java自学网站推荐--全网最靠谱
    ​简介网上有各种Java学习网站,本文推荐的这个Java网站全网最靠谱,质量远超其他所有网站。这个网站是:自学精灵,这是全网最强的Java学习网站,可以直接百度搜索自学精灵,或者访问:自学精灵-IT技术星球。​我不喜欢“全网最强”这样的字眼,但本站的内容确实是全网最强!(大家可以多找几个......
  • JavaScript-初学
            ......
  • 无涯教程-JavaScript - IMSINH函数
    描述MSINH函数以x+yi或x+yj文本格式返回复数的双曲正弦值。复数的双曲正弦通过以下公式计算-$$\sinh(x+yi)=\sinh(x)\cos(y)-\cosh(x)\sin(y)i$$语法IMSINH(inumber)争论Argument描述Required/OptionalInumberAcomplexnumberforwhichyouwantthehype......