注解与反射

注解与反射,第1张

注解与反射

注解与反射
  • 一、类初始化
    • 类的主动引用(发生类初始化)
    • 类的被动引用(不会发生类初始化)
  • 二、类加载机制
    • 1、引导类加载器(bootstrap class loader):
    • 2、扩展类加载器(extensions class loader):
    • 3、系统类加载器(system class loader):
    • 4、自定义类加载器(custom class loader):
    • 双亲委派机制
    • 类加载过程详解
  • 三、反射
  • 四 、Annotation (注解)
    • 1、注解通过 @interface 关键字进行定义。
    • 2、元标签:
    • 3、注解通过反射获取。

一、类初始化 类的主动引用(发生类初始化)

1、虚拟机启动,先初始化main方法所在的类
2、通过new一个类对象
3、调用类的静态成员(除了final常量)和静态方法
4、通过反射对类进行引用
5、初始化子类时,如果父类未初始化,则先初始化父类

类的被动引用(不会发生类初始化)

1、当通过子类引用父类的静态变量,父类会初始化,不会发生导致子类初始化
2、数组定义类引用,不会初始化
3、引用常量不会触发此类的初始化(常量在链接阶段就存在调用类的常量池中了)

二、类加载机制

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。

1、引导类加载器(bootstrap class loader):

它用来加载 Java 的核心库(jre/lib/rt.jar),是用原生C++代码来实现的,并不继承自java.lang.ClassLoader。

加载扩展类和应用程序类加载器,并指定他们的父类加载器,在java中获取不到。

2、扩展类加载器(extensions class loader):

它用来加载 Java 的扩展库(jre/ext/*.jar)。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

3、系统类加载器(system class loader):

它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

4、自定义类加载器(custom class loader):

除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。

ClassLoader classLoader=ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());

结果

sun.misc.Launcher A p p C l a s s L o a d e r @ 18 b 4 a a c 2 s u n . m i s c . L a u n c h e r AppClassLoader@18b4aac2 sun.misc.Launcher [email protected]@1540e19d
null

可以看出ClassLoader类是由AppClassLoader加载的。他的父亲是ExtClassLoader,ExtClassLoader的父亲无法获取是因为它是用C++实现的。

双亲委派机制

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器,父类加载器又将加载任务向上委托,直到最父类加载器,如果最父类加载器可以完成类加载任务,就成功返回,如果不行就向下传递委托任务,由其子类加载器进行加载。

双亲委派机制的好处:

保证java核心库的安全性(例如:如果用户自己写了一个java.lang.String类就会因为双亲委派机制不能被加载,不会破坏原生的String类的加载)

代理模式
  与双亲委派机制相反,代理模式是先自己尝试加载,如果无法加载则向上传递。tomcat就是代理模式。

类加载过程详解

JVM将类加载过程分为三个步骤:装载(Load),链接(link)和初始化(Initialize)

  1. 装载:

查找并加载类的二进制数据;

2)链接:

验证:确保被加载类信息符合JVM规范、没有安全方面的问题。

准备:为类的静态变量分配内存,并将其初始化为默认值。

解析:把虚拟机常量池中的符号引用转换为直接引用。

3)初始化:

为类的静态变量赋予正确的初始值。

注: 解析部分需要说明一下,Java 中,虚拟机会为每个加载的类维护一个常量池【不同于字符串常量池,这个常量池只是该类的字面值(例如类名、方法名)和符号引用的有序集合。 而字符串常量池,是整个JVM共享的】这些符号(如int a = 5;中的a)就是符号引用,而解析过程就是把它转换成指向堆中的对象地址的相对地址。

三、反射

1、获取类中public修饰的
(1)、getMethods 获取公有方法
(2)、getFields 获取公有成员变量
(3)、getAnnotations 公有注解对象
(4)、getConstructors() 获得公有构造方法
2、获取类中全部
(1)、getDeclaredMethods() 获取所有的方法
(2)、getDeclaredFields 获取所有的成员变量
(3)、getDeclaredAnnotations 所有的注解对象
(4)、getDeclaredConstructors() 获得所有的构造方法

3、Method代表类
invoke(Object obj, Object… args) 传递object对象及参数调用该对象对应的方法

注: 原方法声明为private,则需要在invoke()方法前,显式调用对象的.setAccessible(true)方法,将可访问private的方法。

四 、Annotation (注解) 1、注解通过 @interface 关键字进行定义。 2、元标签:

@Retention
取值如下:
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

@documented
这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去

@Target
@Target 指定了注解运用的地方
取值:
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.ConSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited
一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Repeatable
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。

3、注解通过反射获取。

(1)、首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
(2)、通过 getAnnotation() 或 getAnnotations()方法来获取 Annotation 对象。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5678014.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存