注解与反射基础知识梳理
注解
1.什么是注解
-
不是必须的,但是可以对程序做出解释,可以被其他程序(比如:编译器)读取。
-
格式:@注释名 ,可以对其添加一些参数。
例如 :
@SuppressWarnings(value="unchecked")
-
注释可以使用在package,class,method,field等上面,给其添加辅助信息。
2.内置注解
@Override
@Deprecated
@SuppressWarnings
3.元注解
@Target
:用于描述注解的使用范围
//自定义注解的方法
@Target(value=ElementType.MEYHOD)
public @interface MyAnnotation{
}
//Target源码
@Documented //注解被包含于javadoc
@Retention(RetentionPolicy.RUNTIME)//运行时作用
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();//一个枚举类型的数组
}
//可以传入的参数
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE /* 包声明 */
}
@Retention
:表示需要在什么级别保存该注释信息,用于描述注解的生命周期- SOURCE<CLASS<RUNTIME
/**
* Indicates how long annotations with the annotated type are to
* be retained.(指示生命周期的长度) If no Retention annotation is present on
* an annotation type declaration, the retention policy defaults to
* {@code RetentionPolicy.CLASS}.(默认是CLASS)
*
* <p>A Retention meta-annotation has effect only if the
* meta-annotated type is used directly for annotation. It has no
* effect if the meta-annotated type is used as a member type in
* another annotation type.(不能用于其他注解的成员类型)
*
* @author Joshua Bloch
* @since 1.5
* @jls 9.6.4.2 @Retention
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
//参数取值的说明
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /* 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
}
@Document
:说明该注解将被包含在Javadoc中@Inherited
:说明子类可以继承父类中的注解- 假设,我们定义了某个 Annotaion,它的名称是 MyAnnotation,并且 MyAnnotation 被标注为 @Inherited。现在,某个类 Base 使用了MyAnnotation,则 Base 具有了"具有了注解 MyAnnotation";现在,Sub 继承了 Base,由于 MyAnnotation 是 @Inherited的(具有继承性),所以,Sub 也 "具有了注解 MyAnnotation"。
4.自定义注解
- 使用
@interface
,格式为:public @interface 注解名 - 每个方法实际上声明了一个配置该注解的参数
- 方法的名称就是参数的名称
- 返回值类型就配置参数的类型(参数类型只能是Class,String,enum)
- 可以通过默认default来声明参数的默认值
- 只有一个方法设置方法名称为value,在使用时可以省略参数的名称
//自定义注解
@Target({ElementType.Type,ElementType.METHOD})//可以用在类,方法上
@Retention(RetentionPolicy.RUNTIME)//运行时作用
public @interface MyAnnotation{
String name() default ""; //设置默认值为空,可以另外显示赋值
}
反射
1.动态语言与静态语言
- 动态语言:可以在运行时根据某些条件改变自身结构
- 主要动态语言:C#,JavaScript,PHP,Python,Object-C
- 静态语言:运行时结构不可变的语言就是静态语言
- 如:java,c,c++
2.反射
-
Reflection
(反射)是java被视为动态语言的关键,反射机制允许程序在 在执行期间通过反射取得任何类的内部信息,并能够直接操作任意对象。正常方式:
引入需要的"包类"名称
---->通过new实例化
---->取得实例化对象
反射方式:
实例化对象
---->getClass()方法
---->得到完整的"包类"
-
在加载完类之后,在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整类的结构信息。
Class c = Class.forName(" ")
3. Class类
-
对象照镜子后的得到的信息:某个类的属性,方法,构造器,实现的接口,对每个类而言,JRE都为其保留了一个不变的Class类型的对象。一个Class对象包含了特定某个结构的有关信息。
-
Class本身也是一个类
-
Class只能由系统建立对象
-
一个加载的类在JVM中只会有一个Class实例
-
一个Class对象对应于一个加载到JVM的一个Class文件
-
每个实例都可溯源其由哪一个Class实例所创建
-
通过Class可以完整的得到一个类中所被加载的结构
-
Class类是Reflection的根源,唯有先获取对应的Class对象才能动态的加载
-
只要元素类型和维度一样就是同一个Class
//举例 public class Demo2 { public static void main(String[] args) { //Cylinder是一个圆柱体类 Class<Cylinder> aClass = Cylinder.class; Cylinder[] cylinders = new Cylinder[10];//维度不同 Class<? extends Cylinder[]> aClass1 = cylinders.getClass(); System.out.println(aClass1.hashCode()); System.out.println(aClass.hashCode()); } } //结果: //所设置的圆柱体的体积是:3141.59 //1556595366 //985922955
-
-
Class类中常用的方法
-
static forName(String name) //返回指定类名的Class对象
-
Object newInstance() //调用缺省构造函数函数(不带参数的构造函数),返回Class对象的一个实例
-
Field[] getDeclaredFields() //返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
-
-
获取Class类的方法(Runtime阶段、Class类对象阶段、Source源代码阶段)
-
若已知某个对象的实例,调用该实例的
getClass()
方法获取Class对象Class c = person.getClass();
-
a.若已知具体的类,通过class属性获取,该方法最为安全可靠,程序性能最高
Class c = Preson.class;
-
已知一个类的全名称,且该类在类的路径下,可以通过Class类的静态方法
forName()
获取,可能抛出ClassNotFoundException
Class c = Class.forName("demo.Person");
-
基本数据类型的包装类
Inteage.TYPE
Java内存
public class Student { int score; int age; String name; Computer computer; public void study() { System.out.println("studying..."); } }
-
- 栈空间(stack),连续的存储空间,遵循后进先出的原则,用于存放局部变量、基本变量类型及其值、引用对象的变量即引用的地址。
- 堆空间(heap),不连续的空间,用于存放new出的对象,或者说是类的实例,可以被所用的线程共享,不会存放别的对象的引用。
- 方法区(method),方法区在堆空间内,用于存放①Class类的代码信息;②静态变量和方法;③常量池(字符串常量等,具有共享机制)
-
类的加载及
ClassLoder
的理解-
加载:将class文件的字节码内容加载到内存中,并将这些静态数据转换成为方法区的运行时数据结构,然后生成一个代表该类的java.lang.Class对象。(意味着不可自己创建class对象,必须由系统创建)
-
链接:将java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证:验证类的信息是否符合JVM规范及安全要求
- 准备:为类变量(static)分配内存空间并设置默认初始值的阶段,内存在方法区中被分配(static首先分配内存)
- 解析:将常量池中的符号引用替换为直接引用(地址)
-
初始化
静态代码块
---->构造方法
---->代码
- 什么时候会发生类初始化
- 当虚拟机启动时,先初始化main方法所在的类
- new一个类的对象(new 一个对象的数组不会发生初始化)
- 调用类的静态成员(除了final常量)和静态方法
- 使用
java.lang.reflect
报的方法对类进行反射调用 - 初始化一个类但是其父类没有被初始化,会先初始化其父类
- 是么时候不会被动引用
- 当访问一个静态域时只有真正声明这个域的类才会被初始化。如:通过子类引用弗雷德静态变量,子类不会被初始化。
- 通过数组定义类的引用,不会触发此类的初始化。(只是开辟了内存空间)
- 引用常量不会触发(例如final修饰的)
- 什么时候会发生类初始化
-
加载器的类型
-
引导类加载器:C++编写,JVM自带的类加载器,负责java核心库,无法直接获取,rt.jar包下。
-
扩展类加载器
-
系统类加载器
双亲委派机制:权限由上至下降低
-
-
动态创建对象执行
//获取指定类的class对象
Class<Cylinder> cylinderClass = Cylinder.class;
//获取指定的构造器方法
Constructor<Cylinder> constructor =cylinderClass.getConstructor(double.class);
//使用指定的构造器方法创建一个实例对象
Cylinder cylinder = constructor.newInstance(10); //此时已经可以以直接调用方法
//获取指定类的方法
Method volume = cylinderClass.getMethod("volume", double.class);//指定方法的名字,返回值的clss对象
System.out.println(volume.invoke(cylinder,10));//调用invoke()方法传递一个实例化对象去执行及需要执行的方法的参数列表,invoke激活。
Cylinder cylinder1 = constructor.newInstance(20);
//获取指定的字段
Field height = cylinderClass.getDeclaredField("height");
//关闭安全检测,暴力反射
height.setAccessible(true);
//设置属性
height.set(cylinder1,30);
System.out.println(cylinder1.getHeight());//输出结果为30
Object invoke(Object obj,Object... args)
//Object对应原方法的返回值,如原方法没有返回值,此时返回null
//若原方法为静态方法,此时形参Object obj可为null
//若原方法的形参列表为空,则Object[] args为null
public class Cylinder {
private double height;
public double getHeight() {
return height;
}
public Cylinder(double height) {
this.height = height;
}
public double volume(double radius){
return height*(new AreaImpl().CalculateArea(radius));
}
}
获取注解信息
-
ORM ---->对象关系映射
- 类和表结构的对应
- 属性和字段的对应
- 对象和记录对应
-
反射操作注解
//首先获取要获得的注解所对应的元素 Class c = Person.class; //举例获得的是一个类的Class对象,想要获得其注解 <A extends Annotation> A getAnnotation(Class<A> annotationClass) //如果存在该元素的指定类型的注释,则返回这些注释,否则返回 //获得注解的对象获得其信息