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

注解和反射

时间:2023-10-01 20:11:21浏览次数:52  
标签:反射 System Class public 注解 class 加载

注解和反射

注解Annotation

1. 什么是注解

注解是从JDK5.0开始引入的新技术,注解和注释是有一定区别的,可以把注解理解为代码中的特殊标记。

注解的作用

  • 注解不是程序本身,可以对程序作出解释
  • 注解可以在程序编译,类加载,运行时被读取,并且执行相应的处理

注解的格式

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

注解的使用场景?

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

2. 常用内置注解

  • @Override

    定义在java.lang.Override中,此注解可以确保子类确实重写了父类的方法,避免出现低级错误

  • @Deprecated

    定义在java.lang.Deprecated中,此注解可以用来修饰方法,属性,类。

    表示不鼓励程序员使用这样的元素,表明被修饰的元素类,方法等已经过时。

  • @SuupressWarnings

    定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。

3. 元注解

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

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

    • ElementType.TYPE:类或接口
    • ElementTYpe.FIELD:字段
    • ElementTYpe.METHOD:方法
    • ElementTYpe.CONSTRUCTOR:构造方法
    • ElementTYpe.PARAMETER:方法参数
  2. @Retention:表示需要什么场景下生效该注解,也就是注解的生命周期

    runtime > class > sources

  3. @Document:说明该注解将包含在javadoc

  4. @Iherited:定义子类是否可以继承父类定义Annotation

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

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

@MyAnnotation
public class Test01 {

    @MyAnnotation
    public void method1() {

    }
}

/**
 * 定义一个注解MyAnotation,再给注解加上几个元注解	
 * 
 * Target 表示这个注解可以用在什么地方
 * Retention 表示这个注解在什么时候生效 (runtime > class > sources)
 * Documented 说明该注解将包含在javadoc中
 * Inherited 说明子类可以继承父类中的该注解
 */
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation {

}

4. 自定义注解

  • 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
  • 分析:
    • @interface来声明一个注解,格式:public @interface 注解名{定义内容}
    • 其中的每个方法实际就是声明的一个配置参数
    • 方法的名称就是参数的名称
    • 返回值类型就是参数的类型
    • 可以通过default来声明参数的默认值
    • 如果只有一个参数成员,一般参数名为value
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

public class Test02 {
    @MyAnnotation(id = 1)
    public void method1() {

    }
}

@Target(value = ElementType.METHOD)
@interface MyAnnotation {
    // 参数类型+参数名()
    String name() default "root";

    int age() default 18;

    int id();
}

5. 反射读取注解

反射Reflection

1. 反射和反射机制

反射

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

反射的优缺点

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

反射机制

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

2. 动态语言和静态语言

动态语言

  • 是一类在运行的时候可以改变其结构的语言
  • 主要动态语言:JavascriptPHPPython

静态语言

  • 与动态语言相对,运行时结构不可变的语言就是静态语言。如JavaCC++
  • Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用 反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!

3. Class类

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

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

4. 获得Class类的五种方式

// 1. 调用Class类的静态方法
Class<?> c1 = Class.forName("com.entity.User");

// 2. 通过类的实例对象调用该实例的getClass方法
User user = new User();
Class<? extends User> c2 = user.getClass();

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

// 4. 通过内置类型的包装类的TYPE属性获得Class实例
Class<Integer> c4 = Integer.TYPE;

// 5. 通过当前子类的Class对象获得父类的Class对象
Class<?> c5 = c1.getSuperclass();

// 因为一个类只有一个Class对象,所有它们的hashCode相同
System.out.println(c1.hashCode() + " |" +
        c2.hashCode() + " | " +
        c3.hashCode());

5. 哪些类型可以有Class对象?

	// 类
    Class c1 = Object.class;
    // 接口
    Class c2 = Comparable.class;
    // 一维数组
    Class c3 = String[].class;
    // 二维数组
    Class c4 = int[][].class;
    // 注解
    Class c5 = Override.class;
    // 枚举
    Class c6 = ElementType.class;
    // 基本数据类型
    Class c7 = Integer.class;
    // void
    Class c8 = void.class;
    // Class
    Class c9 = Class.class;

6. 类加载器

类加载器:完成类的加载

类加载器的作用:将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 -classpathDjava.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);

7. 通过反射动态的创建对象

通过构造器创建对象

// 通过构造器创建对象
Class<?> userClass = Class.forName("com.entity.User");
Constructor<?> userConstructor = userClass.getDeclaredConstructor(String.class, String.class);
User u1 = (User) userConstructor.newInstance("root", "root");

System.out.println(u1);  // User{username='root', password='root'}

调用指定方法

Class c1 = Class.forName("com.entity.User");
User user = (User) c1.newInstance();
Method setName = c1.getDeclaredMethod("setUsername", String.class);
//invoke激活
setName.invoke(user, "root");
System.out.println(user);  // User{username='root', password='null'}

8. 通过反射操作注解

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());
    }
}
class Student(){
    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 + '\'' +
                '}';
    }
}

标签:反射,System,Class,public,注解,class,加载
From: https://www.cnblogs.com/sroot/p/17739204.html

相关文章

  • @LoadBalanced注解实现负载均衡功能过程
     基本流程如下:拦截我们的RestTemplate请求http://userservice/user/1RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-serviceDynamicServerListLoadBalancer根据user-service到eureka拉取服务列表eureka返回列表,localhost:8081、localhost:8082I......
  • 反射容斥
    故事的起因是模拟赛遇到了一道题:\(N,M\le1e7\)赛时想到了其实可以去枚举原地不动的步数,然后catalan去计算方案数,但是有一个问题,就是这个限制:这个过程不能走出格子这就相当于说我有一个栈,大小为m,要放入i个数,2*i次操作每次选择放入和拿出的方案数,但是栈不能取空,同时也不能爆栈......
  • 2.反射
    反射概述:反射允许对成员变量,成员方法和构造方法的信息进行编程访问;是从class字节码文件中获取的;获取Class对象Class.forName("全类名");类名.class;对象.getClass();利用反射获取构造方法:Class类中用于获取构造方法的方法:Constructor<?>[]getConstructors() ......
  • SSM注解记录
    属性自动注入@Autowired该注解在实体类属性上使用,首先通过ByType注入,若存在多个bean有相同属性,再通过ByName注入,若此时id也不唯一或者与实体类set方法不一致的情况下,需配合@Qualifier注解指定对应bean的id@Resource首先通过ByName注入,若id相同,通过ByType注入区别@Autowired......
  • 3、SpringMVC之RequestMapping注解
    3.1、环境搭建创建名为spring_mvc_demo的新module,过程参考2.1节3.1.1、创建SpringMVC的配置文件<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/......
  • jsp 之反射型 xss 示例
    jsp代码如下:<%@pagecontentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><html><body><formaction=""method="get">姓名:<inputname="name"type......
  • lombok注解:@Builder
    带有注释的方法@Builder(从现在起称为target)会导致生成以下7个内容:名为的内部静态类FooBuilder,具有与静态方法相同的类型参数(称为builder)。在构建器中:目标的每个参数都有一个私有非静态非最终字段。在构建器中:包私有无参数空构造函数。在构建器中:目标的每个参数都有一个类......
  • golang 反射
    参考https://www.cnblogs.com/jiujuan/p/17142703.htmlfloat反射示例packagemainimport( "fmt" "reflect")funcmain(){ varxfloat64=1.2345 fmt.Println("==TypeOf==") t:=reflect.TypeOf(x) fmt.Println("type:&quo......
  • 反射 内置方法
    如何实现反射:classPeople:def__inti__(self,name,age):self.name=nameself.age=agedefsay(self):print('<%s;%s>'%(self.name,self.age))obj=People('猪猪同学',18)  classFtp:defput(self):print('正在执行上传功......
  • 反射
    反射是指对一个程序集中的元数据进行检查的过程。说明白一点,就是可以访问和使用一个dll里面所有的东西,并且是运行动态时的调用,而不是普通编译时的绑定,这样使程序更加的自由和灵活,但是性能较低。反射一般可以用于:插件的开发、特性和程序的动态调用等等。1.首先我们写一个类,实现他......