注解Annotation
1、什么是注解
Annotation
是从
JDK5.0
开始引入的新技术
.
Annotation
的作用
不是程序本身
,
可以对程序作出解释
.(
这一点和注释
(comment)
没什么区别
)
可以被其他程序
(
比如
:
编译器等
)
读取
.
Annotation
的格式
注解是以
"@
注释名
"
在代码中存在的
还可以添加一些参数值
,
例如
:@SuppressWarnings(value="unchecked")
Annotation
在哪里使用
?
可以附加在
package , class , method , fifield
等上面
,
相当于给他们添加了额外的辅助信息
我们可以通过反射机制实现对这些元数据的访问
2、内置注解
@Override
定义在
java.lang.Override
中
,
此注释只适用于修辞方法
,
表示一个方法声明打算重写超类中
的另一个方法声明
.
所有的重写方法必须加这个注解
@Deprecated
定义在
java.lang.Deprecated
中
,
此注释可以用于修辞方法
,
属性
,
类
,
表示不鼓励程序员使用这样的元素
,
通常是因为它很危险或者存在更好的选择
.
@SuppressWarnings
定义在
java.lang.SuppressWarnings
中
,
用来抑制编译时的警告信息
.
与前两个注释有所不同
,
你需要添加一个参数才能正确使用
,
这些参数都是已经定义好了的
,
我们
选择性的使用就好了
.
@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings(value={"unchecked","deprecation"})
等等
3、元注解
元注解的作用就是负责注解其他注解
, Java
定义了
4
个标准的
meta-annotation
类型
,
他们被用来提供
对其他
annotation
类型作说明
.
这些类型和它们所支持的类在
java.lang.annotation
包中可以找到
.( @Target , @Retention ,
@Documented , @Inherited )
@Target :
用于描述注解的使用范围
(
即
:
被描述的注解可以用在什么地方
)
@Retention :
表示需要在什么级别保存该注释信息
,
用于描述注解的生命周期
(SOURCE < CLASS < RUNTIME)
@Document
:说明该注解将被包含在
javadoc
中
@Inherited
:说明子类可以继承父类中的该注解
反射机制Reflflection
1、静态 VS 动态语言
动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的
函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自
身结构。
主要动态语言:
Object-C
、
C#
、
JavaScript
、
PHP
、
Python
等
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。如
Java
、
C
、
C++
。
Java
不是动态语言,但
Java
可以称之为
“
准动态语言
”
。即
Java
有一定的动态性,我们可以利用
反射机制获得类似动态语言的特性。
Java
的动态性让编程的时候更加灵活!
2、Java Reflflection
Reflflection
(反射)是
Java
被视为动态语言的关键,反射机制允许程序在执行期借助于
Reflflection API
取
得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个
Class
类型的对象(一个类只有一个
Class
对象),这 个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,
透过这个镜子看到类的结构,所以,我们形象的称之为:
反射
![](https://i-blog.csdnimg.cn/blog_migrate/f6477da0d4302024d94f777338322b98.png)
3、Java反射优点和缺点
优点:可以实现动态创建对象和编译,体现出很大的灵活性
!
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉
JVM
,我们希望做什么并且它满 足我们的要求。这类操作总是慢于 直接执行相同的操作。
4、Class类
在
Object
类中定义了以下的方法,此方法将被所有子类继承
public final
Class
getClass
();
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个
类而言,
JRE
都为其保留一个不变的
Class
类型的对象。一个
Class
对象包含了特定某个结构
(class/interface/enum/annotation/primitive type/void/[])
的有关信息。
Class
本身也是一个类
Class
对象只能由系统建立对象
一个加载的类在
JVM
中只会有一个
Class
实例
一个
Class
对象对应的是一个加载到
JVM
中的一个
.class
文件
每个类的实例都会记得自己是由哪个
Class
实例所生成
通过
Class
可以完整地得到一个类中的所有被加载的结构
Class
类是
Reflflection
的根源,针对任何你想动态加载、运行的类,唯有先获得相应的
Class
对象
//获得class办法一:通过对象获得
Class clazz1 = person.getClass();
//获得class办法二:通过字符串获得(包名+类名)
Class clazz2 = Class.forName("com.reflection.Student");
//获得class办法三:通过类的静态成员class获得
Class clazz3 = Person.class;
Class类的常用方法
![](https://i-blog.csdnimg.cn/blog_migrate/03304d2944e8febaa9bad72e6c31d2fd.png)
5、Java内存分析
栈中存放地址
类的加载过程
类的加载与ClassLoader的理解
加载:
将
class
文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,
然后生成一个代表这个类的
java.lang.Class
对象
.
链接:将
Java
类的二进制代码合并到
JVM
的运行状态之中的过程。
验证:确保加载的类信息符合
JVM
规范,没有安全方面的问题
准备:正式为类变量(
static
)分配内存并设置类变量默认初始值的阶段,这些内存都将在方
法区中进行分配。
解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
初始化:
执行类构造器
()
方法的过程。类构造器
()
方法是由编译期自动收集类中所有类变量的赋值动作
和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造
器)。
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
虚拟机会保证一个类的
()
方法在多线程环境中被正确加锁和同步。
什么时候会发生类初始化?
类的主动引用(一定会发生类的初始化)
当虚拟机启动,先初始化
main
方法所在的类
new
一个类的对象
调用类的静态成员(除了
fifinal
常量)和静态方法
使用
java.lang.reflflect
包的方法对类进行反射调用
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静
态变量,不会导致子类初始化
通过数组定义类引用,不会触发此类的初始化
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
类加载器的作用
类加载的作用:将
class
文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数 据结构,然后在堆中生成一个代表这个类的java.lang.Class
对象,作为方法区中类数据的访问入
口。
类缓存:标准的
JavaSE
类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持 加载(缓存)一段时间。不过JVM
垃圾回收机制可以回收这些
Class
对象
6、创建运行时类的对象
通过反射获取运行时类的完整结构
Field
、
Method
、
Constructor
、
Superclass
、
Interface
、
Annotation
实现的全部接口
所继承的父类
全部的构造器
全部的方法
全部的
Field
注解
调用指定的方法
通过反射,调用类中的方法,通过
Method
类完成。
通过
Class
类的
getMethod(String name,Class…parameterTypes)
方法取得一个
Method
对
象,并设置此方法操作时所需要的参数类型。
之后使用
Object invoke(Object obj, Object[] args)
进行调用,并向方法中传递要设置的
obj
对
象的参数信息
8、setAccessible
Method
和
Field
、
Constructor
对象都有
setAccessible()
方法。
setAccessible
作用是启动和禁用访问安全检查的开关。
参数值为
true
则指示反射的对象在使用时应该取消
Java
语言访问检查。
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为
true
。
使得原本无法访问的私有成员也可以访问
参数值为
false
则指示反射的对象应该实施
Java
语言访问检查
9、获得类中属性相关的方法
方法 | 用途 |
---|---|
getField(String name) | 获得某个公有的属性对象 |
getFields() | 获得所有公有的属性对象 |
getDeclaredField(String name) | 获得某个属性对象 |
getDeclaredFields() | 获得所有属性对象 |
10、获得类中构造器相关的方法
方法 | 用途 |
---|---|
getConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getConstructors() | 获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
11、获得类中方法相关的方法
方法 | 用途 |
---|---|
getMethod(String name, Class...<?> parameterTypes) | 获得该类某个公有的方法 |
getMethods() | 获得该类所有公有的方法 |
getDeclaredMethod(String name, Class...<?> parameterTypes) | 获得该类某个方法 |
getDeclaredMethods() | 获得该类所有方法 |
Field类
Field代表类的成员变量(成员变量也称为类的属性)。
方法 | 用途 |
---|---|
equals(Object obj) | 属性与obj相等则返回true |
get(Object obj) | 获得obj中对应的属性值 |
set(Object obj, Object value) | 设置obj中对应属性值 |
Method类
Method代表类的方法。
方法 | 用途 |
---|---|
invoke(Object obj, Object... args) | 传递object对象及参数调用该对象对应的方法 |
Constructor类
Constructor代表类的构造方法。
方法 | 用途 |
---|---|
newInstance(Object... initargs) | 根据传递的参数创建类的对象 |