1.1、什么是注解(Annotation)
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,
注解的作用:
- 不是程序本身,可以对程序作出解释
- 可以在程序编译,类加载,运行时被读取,并执行相应的处理。
注解的格式:
- 注解是以"@注释名"在代码中存在的,还可以添加一些参数值,例如:@SuppersWarnings(valus=“unchecked”)
注解在哪里使用:
- 可以附加在package,class,method,filed等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。
1.2、内置注解
- 1.限定父类重写方法:@Override
当子类重写父类方法时,子类可以加上这个注解,那这有什么什么用?这可以确保子类确实重写了父类的方法,避免出现低级错误
- 2.标示已过时:@Deprecated
这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类,方法时编译器会给出警告(删除线,这个见了不少了吧)。
- 3.抑制编译器警告:@SuppressWarnings
被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,例如修饰一个类,那他的字段,方法都是显示警告
- 4.“堆污染”警告与@SafeVarargs
想理解这个就要明白什么是堆污染,堆污染是什么?
其实很好理解,就是把不带泛型的对象赋给一个带泛型的对象,为什么不行?很简单,因为不带泛型的话,默认会给泛型设定为object,意思就是什么类型都可以往里面塞,那你一个不带泛型的怎么可能给一个带泛型塞呢。
例如运行如下代码:
List list = new ArrayList(); list.add(20); List ls = list; System.out.println(ls.get(0));则会抛出堆污染异常Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at Test.Test1.main(Test1.java:29)
1.@SafeVarargs修饰引发该警告的方法或构造器
2.使用@suppressWarnings(“unchecked”)
3.编译时使用-Xlint:varargs
- 5.函数式接口与@Functionallnterface
什么是函数式?如果接口中只有一个抽象方法(可以包含多个默认方法或多个static方法)
接口体内只能声明常量字段和抽象方法,并且被隐式声明为public,static,final。
接口里面不能有私有的方法或变量。
这个注解有什么用?这个注解保证这个接口只有一个抽象方法,注意这个只能修饰接口
1.3、自定义注解和元注解(meta-annotation)
定义注解:
- 第一步,用定义注解:
- 第二步,添加参数、默认值,如果没有默认值,就必须给参数赋值:
把最常用的参数定义为,推荐所有参数都尽量设置默认值。
- 第三步,用元注解配置注解:
其中,必须设置和,一般设置为,因为我
们自定义的注解通常要求在运行期读取。一般情况下,不必写和。
在使用的时候,如果一个类用到了我们定义的注解,则它的子类也定义该注解
元注解:
- 元注解的作用就是负责注解其他注解,Java定义了4个标准的元注解类型,他们被用来提供对其他注解类型作说明
- 这些类型和他们所支持的类在java.lang.annotation包中可以找到
1、@Target:用于描述注解的使用范围
- 类或接口:;
- 字段:;
- 方法:;
- 构造方法:;
- 方法参数:。
2、@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期
- 仅编译期:;
- 仅class文件:;
- 运行期:。
范围:RUNTIME>CLASS>SOURCE
如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上这个元注解:
3、@Document:说明该注将被包含在javadoc中
4、@Iherited:使用@Inherited定义子类是否可继承父类定义Annotation。
@Inherited仅针对 类型的annotation有效,并且仅针对
class的继承,对interface的继承无效:
1、反射和反射机制
反射(Reflection):
Java的反射是指程序在运行期可以拿到一个对象的所有信息。
反射的优点和缺点:
- 优点:可以实现动态创建对象和编译,灵活性大
- 缺点:对性能有影响,反射操作总是慢于直接执行相同操作
反射机制:
Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用,操作任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言(在程序运行的时候可以改变其结构)的关键。
2、CLass类
java.lang.reflect.Class类,实现反射的核心类
- Class类只能由系统建立对象
- 一个加载的类在内存(JVM)中只有一个Class对象
- 一个类被加载后,类的整个结构都会被封装在Class对象中
- 每个类的实例都会记得自己是由哪个Class实例所生成
- Class类是反射的根源,针对任何你想动态加载,运行的类,唯有获得相应的Class对象
其它API
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的属性
java.lang.reflect.Constructor:代表类的构造器
获得Class类实例的五种方式:
Class类的常用方法:
3、哪些类型可以有Class对象
- class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
- interface:接口
- []:数组
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void
4、类加载理解
- 加载:将class字节码文件内容加载到内存中,并将这些数据装换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法去中进行分配
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
- 初始化:
- 执行类构造器方法的过程。类构造器方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
- 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的在多线程环境中被正确加锁和同步。
什么时候会发生类初始化:
- 类的主动引用(一定会发生类初始化)
- 当虚拟机启动,先初始化mian方法所在的类
- new一个类的对象
- 调用类的静态成员(处理final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类的时候,如果发现其父类还没有进行初始化,则先初始化其父类
- 类的被动引用(不会发生类初始化)
- 当访问一个静态域时,只有正真声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会发生类初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
5、类加载器
类加载器:完成类的加载
类加载器的作用:将class字节码文件内容加载到内存中,并将这些数据装换成方法区的运行时 数据结构,然后生 成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
JVM三种预定义类型类加载器,当JVM启动的时候,Java开始使用如下三种类型的类加载器:
- :根类加载器是用本地代码实现的类加载器,它负责将JAVA_HOME/lib下面的核心类库或-Xbootclasspath选项指定的jar包等虚拟机识别的类库加载到内存中。由于根类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到根类加载器的引用。
- :扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的,它负责将JAVA_HOME /lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
- :系统类加载器是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的,它负责将用户类路径(java -classpath或-Djava.class.path变量所指的目录,即当前类所在路径及其引用的第三方类库的路径,如第四节中的问题6所述)下的类库加载到内存中。开发者可以直接使用系统类加载器。
类加载三种机制:
- 全盘负责机制:就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
- 双亲委派机制:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。
- 缓存机制机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
获取三种预定义类型类加载器:
类加载的简单使用
6、通过反射动态的创建对象
通过构造器创建对象
调用指定方法
7、反射操作注解
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/2217.html