首页 > 其他分享 >注解和反射

注解和反射

时间:2024-08-13 19:39:18浏览次数:11  
标签:反射 String Class public 注解 class 加载

注解和反射

注解

1什么是注解(Annotation)

从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,

注解的作用:

  • 不是程序本身,可以对程序作出解释

  • 可以在程序编译,类加载,运行时被读取,并执行相应的处理。

注解的格式:

  • 注解是以"@注释名"在代码中存在的,还可以添加一些参数值,例如:@SuppersWarnings(valus=“unchecked”)

注解在哪里使用:

  • 可以附加在package,class,method,filed等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。

1.2、内置注解

1.限定父类重写方法:@Override
@Override //该注解标识的类,代表的覆盖的是其父类的方法
public boolean equals(Object obj) {
    return super.equals(obj);

当子类重写父类方法时,子类可以加上这个注解,那这有什么什么用?这可以确保子类确实重写了父类的方法,避免出现低级错误

2.标示已过时:@Deprecated

这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告(删除线,这个见了不少了吧)。

@Deprecated //该注解标识的类,代表该类已经过时
public static void sayHello() {
    System.out.println("hello world");
}

3.抑制编译器警告:@SuppressWarnings

被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,例如修饰一个类,那他的字段,方法都是显示警告

@SuppressWarnings("deprecation")
public static void main(String[] args) {
    //这个类是过时的,使用@SuppressWarnings来压制警告
    System.runFinalizersOnExit(true);
}

4.“堆污染”警告与@SafeVarargs

想理解这个就要明白什么是堆污染,堆污染是什么?

其实很好理解,就是把不带泛型的对象赋给一个带泛型的对象,为什么不行?很简单,因为不带泛型的话,默认会给泛型设定为object,意思就是什么类型都可以往里面塞,那你一个不带泛型的怎么可能给一个带泛型塞呢。

5.函数式接口与@Functionallnterface

什么是函数式?如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法)

接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。

接口里面不能有私有的方法或变量。

这个注解有什么用?这个注解保证这个接口只有一个抽象方法,注意这个只能修饰接口

1.3、自定义注解和元注解(meta-annotation)

定义注解:

第一步,用@interface定义注解:

 public @interface Report { } 

第二步,添加参数、默认值,如果没有默认值,就必须给参数赋值:

public @interface Report {
        //参数类型 +参数名()
    int type() default 0;
    String level() default "info";
    String value() default "万里";
}

​ 把最常用的参数定义为value(),推荐所有参数都尽量设置默认值。

第三步,用元注解配置注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

​ 其中,必须设置@Target@Retention@Retention一般设置为RUNTIME,因为我们自定义的注解通常要求在运行期读取。一般情况下,不必写@Inherited@Repeatable

在使用的时候,如果一个类用到了我们定义的注解,则它的子类也定义该注解

@Report(type=1)
public class Person {
}
public class Student extends Person {
}

元注解:

元注解的作用就是负责注解其他注解,Java定义了4个标准的元注解类型,他们被用来提供对其他注解类型作说明

这些类型和他们所支持的类在java.lang.annotation包中可以找到

1、@Target:用于描述注解的使用范围

类或接口:ElementType.TYPE;
字段:ElementType.FIELD;
方法:ElementType.METHOD;
构造方法:ElementType.CONSTRUCTOR;
方法参数:ElementType.PARAMETER。

public class Test{
    @MyAnnotation
    public void test(){       
    }
}
//定义一个注解MyAnnotation,再给注解加上一个元注解
@Target(value = ElementType.METHOD)//表示该注解只能用在方法上
//可以设置多个范围:@Target(value ={ElementType.METHOD,ElementType.type})
@interface MyAnnotation{
}

2、@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期

仅编译期:RetentionPolicy.SOURCE;

仅class文件:RetentionPolicy.CLASS;

运行期:RetentionPolicy.RUNTIME。

范围:RUNTIME>CLASS>SOURCE

如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解:

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
}

3、@Document:说明该注将被包含在javadoc中

4、@Iherited:使用@Inherited定义子类是否可继承父类定义Annotation。

​ @Inherited仅针对 @Target(ElementType.TYPE)类型的annotation有效,并且仅针对

​ class的继承,对interface的继承无效:

@Inherited
@Target(ElementType.TYPE)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

反射

1、反射和反射机制

反射(Reflection):Java的反射是指程序在运行期可以拿到一个对象的所有信息。

反射的优点和缺点:

  • 优点:可以实现动态创建对象和编译,灵活性大
  • 缺点:对性能有影响,反射操作总是慢于直接执行相同操作

反射机制:

Java的反射机制是指在程序的运行状态中,**可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用,操作任意一个对象的属性和方法。**这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言(在程序运行的时候可以改变其结构)的关键。

2、CLass类

java.lang.reflect.Class类,实现反射的核心类

  • Class类只能由系统建立对象
  • 一个加载的类在内存(JVM)中只有一个Class对象
  • 一个类被加载后,类的整个结构都会被封装在Class对象中
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • Class类是反射的根源,针对任何你想动态加载,运行的类,唯有获得相应的Class对象

java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的属性
java.lang.reflect.Constructor:代表类的构造器

获得Class类实例的五种方式:

//方式一:调用Class类的静态方法 forName(String className)
Class c1 = Class.forName("com.cheng.reflection.User");

//方式二 已知某个类的实例,调用该实例的getClass()方法,getClass是Object类中的方法、因为所有类都继承Object类。
Class c2 = user.getClass();

//方式三 已知具体类,通过类的class属性获取,该方法最安全可靠,程序性能最高
Class c3 = User.class;

//方式四:通过基本内置类型的包装类的TYPE属性获得CLass实例
//以int的包装类Intege类为例   源码:public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
Class<Integer> c4 = Integer.TYPE;

//方式五:通过当前子类的Class对象获得父类的Class对象
Class c5 = c1.getSuperclass();//c1为子类的CLass对象

Class类的常用方法:

方法名 功能说明
static ClssforName(String name) 返回指定类名namedeClass对象
Obiect newInstance() 调用无参构造函数,返回Class对象的一个实例
getName() 返回此Class对象所表示的实体(类,接口,数组类或void)的名称
Class getSuperclass() 返回当前Class对象的父类的Class对象
Class[] getinterfaces() 返回当前Class对象的接口
ClassLoader getClassLoader() 返回该类的类加载器
Method getMethod(name,String .class) 返回对象Method一个数组,此对象的形参类型为paramType
Field getDeclaredFields() 返回对象的Field(属性)一个数组
Constructor[] getConstructors() 返回一个包含某些Constructor(构造器)对象的数组

3、哪些类型可以有Class对象

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。

 Class c1 = Object.class; 

interface:接口

 Class c2 = Comparable.class; 

[]:数组

 Class c3 = String[].class; Class c4 = int[][].class; 

enum:枚举

 Class c5 = ElementType.class; 

annotation:注解@interface

 Class c6 = Override.class; 

primitive type:基本数据类型

 Class c7 = Interger.class; 

void

Class c8 = void.class;
Class c9 = Class.class;

4、类加载理解

  • 加载:将class字节码文件内容加载到内存中,并将这些数据装换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
    • 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
    • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法去中进行分配
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过
  • 初始化:
    • 执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
    • 虚拟机会保证一个类的在多线程环境中被正确加锁和同步。

什么时候会发生类初始化:

  • 类的主动引用(一定会发生类初始化)
    • 当虚拟机启动,先初始化mian方法所在的类
    • new一个类的对象
    • 调用类的静态成员(处理final常量)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则先初始化其父类
  • 类的被动引用(不会发生类初始化)
    • 当访问一个静态域时,只有正真声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
    • 通过数组定义类引用,不会发生类初始化
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

5、类加载器

类加载器:完成类的加载

类加载器的作用:将class字节码文件内容加载到内存中,并将这些数据装换成方法区的运行时 数据结构,然后生 成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口

JVM三种预定义类型类加载器,当JVM启动的时候,Java开始使用如下三种类型的类加载器:

  • 根/启动(Bootstrap)类加载器:根类加载器是用本地代码实现的类加载器,它负责将JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中。由于根类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到根类加载器的引用。

  • 扩展(Extension)类加载器:扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的,它负责将JAVA_HOME /lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。

  • 系统(System)类加载器:系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的,它负责将用户类路径(java -classpath或-Djava.class.path变量所指的目录,即当前类所在路径及其引用的第三方类库的路径,如第四节中的问题6所述)下的类库加载到内存中。开发者可以直接使用系统类加载器。

类加载三种机制:

  • 全盘负责机制:就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
  • 双亲委派机制:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。

  • 缓存机制机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。

获取三种预定义类型类加载器:

       //获取系统类加载器
       ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
       System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2

       //获取系统类加载器的父类加载器-->扩展类加载器
       ClassLoader parent = systemClassLoader.getParent();
       System.out.println(parent);//sun.misc.Launcher$AppClassLoader@18b4aac2

       //获取扩展类加载器的父类加载器-->根类加载器
       ClassLoader parent1 = parent.getParent();
       System.out.println(parent1);//null

类加载的简单使用

        //测试当前类是由哪个类加载器加载的
        ClassLoader classLoader = Class.forName("com.cheng.annotation.Test01").getClassLoader();                     System.out.println(classLoader);
        //sun.misc.Launcher$AppClassLoader@18b4aac2 统类加载器

        //测试JDK内置类是由哪个类加载器加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);//null 根类加载器

        //获得系统类加载器可以加载的路径
        String property = System.getProperty("java.class.path");
        System.out.println(property);

6、通过反射动态的创建对象

通过构造器创建对象

//通过构造器创建对象
Class c1 = class.forName("com.cheng.User");
Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
User user = (User)constructor.newInstance("万里",1,18);
System.out.println(user);//USer{name='万里',id=1,age=18}

调用指定方法

Class c1 = class.forName("com.cheng.User");
User user = (USer)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName",String.class);
//invoke激活
setName.invoke(user,"万里");
System.out.println(user,getName());//万里

 

7、反射操作注解

package com.cheng.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;

//练习反射操作注解
public class Test {
    
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.cheng.reflection.student2");

        //1.通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //2.获得注解的value值
        Cheng cheng = (cheng) c1.getAnnotation(cheng.class);
        System.out.println(cheng.value());

        //3.获得类指定字段的注解
        Field f = c1.getDeclaredField("id");
        Fieldhaha annotation = f.getAnnotation(Fieldcheng.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}

@Cheng("db_student")
class student2{
    @Fieldcheng(columnName = "db_id",type = "int",length = 10)
    private int id;
    @Fieldcheng(columnName = "db_age",type = "int",length = 10)
    private int age;
    @Fieldcheng(columnName = "db_name",type = "varchar",length = 3)
    private String name;
  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface cheng{
    String value();
}

//定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldcheng{
    String columnName();
    String type();
    int length();
}   
        
    public student2() {
    }
    public student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

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

 

标签:反射,String,Class,public,注解,class,加载
From: https://www.cnblogs.com/zhao-ke-ming/p/18353643

相关文章

  • Java注解详解:@Async异步
    使用@Async进行异步方法调用@Async是Spring框架里的一个小工具,能让你的方法在后台偷偷跑起来,不影响主线程的工作。这个方法特别适合用来处理那些不需要立即给用户反馈的任务,比如发个邮件啊,处理个大文件啥的。1.配置异步支持首先,你得在Spring配置类里开个绿灯,让......
  • 注解
    注解1.什么是注解注解(Annonation)就是对Java代码中类、属性和方法进行标注和解释,但并不影响代码的执行Java代码中大量使用注解(特别是框架)2.注解的定义Java中使用@interface关键字定义一个注解public@interfaceTestAnnotation{}定义注解与定义接口很类似,不过前......
  • BGP反射器(四)
    解决IBGP全互联问题带来的问题:路由器需维护大量的TCP和BGP连接,尤其在路由器数量较多时AS内BGP网络的可扩展性较差角色RR:路由反射器Client:RR的客户端Non-Client:非客户机关系Client只与RR之间建立IBGP会话RR与RR之间建立IBGP全互联Non-Client与Non-Client之间建立IBGP全互联......
  • 科普文:Java基础系列之【你必须知道的框架基础-反射/代理】
    前言科普文:Java基础系列之【Java动态代理的应用场景和基本原理】-CSDN博客科普文:Java基础系列之【字节码增强技术探索】-CSDN博客科普文:Java基础系列之【字节码应用案例Fastjson原理和实操说明】-CSDN博客科普文:Java基础系列之【JVM字节码操作ASM框架概叙】-CSDN博客......
  • 一些实用Lombok注解
    @Delegate@Delegate可以让你的类使用其他类的方法,而不需要自己写代码。比如,你有一个类叫做A,它有一个方法叫做sayHello(),你想让另一个类B也能用这个方法,那就可以在B类中加上一个A类型的字段,并在这个字段上加上@Delegate注解,这样,B类就可以直接调用sayHello()方法,就像它是自己的方......
  • Spring框架中的@Bean注解详解
    Spring框架中的@Bean注解详解在Java的Spring框架中,@Bean是一个非常重要的注解,它允许开发者在注解方法中创建和配置对象,这些对象随后会被Spring容器管理。本文将通过一个简单的实例来详细解释@Bean注解的使用方法和它在Spring框架中的作用。什么是@Bean注解?@Bean注解是一......
  • 深入解析@JsonValue注解在Java序列化中的应用
    深入解析@JsonValue注解在Java序列化中的应用在Java开发中,对象序列化是一个常见的需求,尤其是在进行网络通信或者数据持久化时。Jackson库作为Java领域内一个非常流行的JSON处理库,提供了强大的序列化和反序列化功能。在Jackson2.9版本之后,@JsonValue注解的引入,为开发者提供......
  • Spring Boot配置类的注解
    SpringBoot中,若某类只用@ConfigurationProperties注解,然后该类:没有在扫描路径下或没用@Component等注解就会导致无法被扫描为bean,须在配置类用@EnableConfigurationProperties注解去指定这个类,才能使@ConfigurationProperties生效,并作为一个bean添加进Spring......
  • 节假日配置初始化 redis缓存方案及@PostConstruct注解,Cache方案GuavaUtils.java工具类
    节假日配置初始化redis缓存方案及@PostConstruct注解,Cache方案GuavaUtils.java工具类启动报错:本机,在jenkins上面没有报错?包括嵌套的注入Beanjava静态代码块和spring@value等注解注入顺序https://www.cnblogs.com/oktokeep/p/15530697.html/***节假日配置初始化redis缓存......
  • 雷达气象学(9)——反射率因子图分析(强对流篇)
    目录9.0对流性天气的分类9.1钩状回波9.2云顶上冲9.3悬垂状回波9.4弱回波区(WER)和有界弱回波区(BWER)9.5回波墙9.6V型缺口9.7旁瓣回波9.8下击暴流和阵风锋9.9三体散射回波(TBSS)9.10弓形回波9.0对流性天气的分类按照对流风暴的强度分类有两种:\[对流风暴\begin{cases}普......