注解和反射
注解和反射(缺少实例)
特注:本人跟着狂神学的
一、注解
1、什么是注解
注解叫Annotation,从JDK5.0开始引入的新技术
作用:
1.不是程序本身,但能够对程序做出解释(和注释差不多)
2.能够被其他程序(比如编译器)读取。
格式:
@注解名,还可以添加一些参数值
使用范围:包、类、方法、属性等都能使用,我们可以通过反射机制实现对于元数据的访问。
2、内置注解
@Override:定义在java.lang.Override中,此类注解只适用于修改方法,表示一个方法声明打算重写超类中的另一个方法声明。
@Deprecated:定义在java.lang.Deprecated中,此注解用于修饰方法、属性、类,表示不鼓励程序员使用这类元素,通常因为它很危险或者过时了或者有更好的选择。
@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。与前两个注解不同,需要添加一个参数才能正确使用,这些参数都是已经定义好的:all(全部警告)、unchecked、deprecation
3、元注解
元注解的作用就是负责注解其他注解,Java定义了4个标准元注解类型,都在java.lang.annotation包中。
@Target:用于描述注解的适用范围(注解可以被用在那个地方)TYPE、FIELD、METHOD、CLASS...
@Retetion:表示在什么级别保存该注解信息,描述注解的生命周期:SOURCE<CLASS<RUNTIME(运行时)
@Document:说明该注解被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解。
4、自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
特点:
1.@interface用来声明一个注解,格式:public@interface注解名{定义内容}
2.其中的每一个方法实际上是声明一个配置参数。
3.方法的名称就是参数的名称。
4.返回值类型就是参数的类型(返回值只能是基本类型、Class、String、enum)。int age() default 0;
5.可以使用default来声明参数的默认值。
6.如果只有一个参数成员,一般此参数名为value。
7.注解元素必须要有值,定义注解元素时,经常使用空字符串、0作为默认值。
二、反射机制
1、什么是反射?
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Class c = Class.forName("java.lang.String")
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,通过这个对象可以看到类的结构。这就像是一面镜子,能够看到内部的结构,所以称为反射。
2、Class类
所有的Object类中定义了以下的方法,此方法被所有的子类继承。
public final Class getClass()
以上方法返回值的类型是一个Class类,此类是java反射的源头。
通过反射能够获得的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口,对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个结构(class、interface、enum、annotation、ptimitive type、void、[])的有关信息。
注意:
1.Class本身也是一个类
2.Class对象只能由系统建立对象
3.一个加载的类在JVM中只会有一个Class实力
4.一个Class对象对应的是一个加载到JVM中的一个.class文件
5.每个类的实例都会记得自己是由哪个Class实例所生成
6.通过Class能够完整的得到一个类中的所有被加载的结构。
7.Class类是Reflection的根源,针对任何你想动态加载、运行的类唯有先获得相应的Class对象。
3、利用反射机制获得Class类对象
通过对象获得:person.getClass();
通过包路径名获得:Class.forName(String name);
通过类名获得:Class.class
反射中使用的方法:
static Class forName(String string) 返回指定类名name(包名)的Class对象
Object newInstance:调用缺省构造函数,返回Class对象的一个实例
getName():返回此Class对象所代表的实体(类,接口,数组类或void)的名称。
Class getSuperClass():返回当前Class对象的父类的Class对象
Class[] getingerfaces():返回当前Class对象的接口
ClassLoader getClassLoader():返回该类的类加载器
Constructor[] getConstructors():返回一个包含某些Constructor对象的数组
Method getMethod(String name,Class...T):返回一个Method对象,此对象的形参类型为paramType
Field[] getdeclaredFields():返回Filed对象的一个数组
哪些类型可以具有Class对象:class、interface、enum、annotation、ptimitive type、void、[]
3、类的加载
加载-链接-初始化
4、获取类的运行时结构
1.获得类名:
String c1.getName():获得包含包名的类名
String c1.getSimpleName():获得简单类名
2.获得属性
Field[] getFields:获得所有公开属性列表(public)
Field[] getDeclaredFields:获得所有属性列表
Field getField(String str):获得指定公开属性
Field getDeclaredField(String str):获得指定名称属性
3.获得方法
Method[] getMethods():获得本类及其父类全部public方法
Method[] getDeclaredMethods():获得本类所有方法
Method getMethod(String name,paramterTypes):获得指定方法(需要指定输入类型,以此避免重载情况)
4.获得构造器
Constructor[] getConstructors():获得本类公开的构造方法
Constructor[] getDeclaredConstructors():获得所有的构造方法
Constructor getConstructor(Class,Class):获得指定构造方法。
5、反射的应用
1.利用反射机制创建一个对象
利用类创建一个对象:
User user = (User)c1.**newInstance**();
调用无参构造创建,若无无参构造则失败。
利用构造器构造对象(可以有参可以无参)
Constructor con = c1.getConstructor(String.Class,int.Class);
User user2 = (User)con.newInstance("zhangsan",23);
2.利用反射机制调用普通方法
User user3 = (User)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName",String.class)
setName.invoke(user3,"zhang");
3.利用反射机制操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);//不能够直接访问私有属性,需要关闭程序安全检测
name.set(user4,"zhang");
6、性能对比
调用方法:
效率:普通方式>反射机制(关闭安全检测)>反射机制(未关闭安全检测)
7、反射操作泛型
Java采用泛型擦除的机制引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除。
为了能够通过反射机制操作这种类型,Java新增了ParameterizedType、GenericArrayType、TypeVariable和WildcardType集中了欸行来代表不能被归一到Class类中的类型但是有何原始类名齐名的类型。
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型。
TypeVariable:是各种类型变量的公共父接口
WildcardType:代表一种通配符类型表达式
使用方法:
Type[] method.getGenericParamterTypes():获得方法的泛型参数
Type[] method.getActualTypeArgument():获得泛型参数中的真实参数类型
Type[] method.getGenericReturnTypes():获得方法的泛型返回参数。
8、反射操作注解信息
使用方法:
getAnnotations:
getAnnotation:
获取注解:
Annotation[] anno = c1.getAnnotations();
获取注解的value值:
zhang zhang = (zhang)c1.getAnnotation(zhang.class)//通过强转,获得指定注解;
String value = zhang.value();
获取类指定注解:
Field field = c1.getDeclaredField("name")//获得指定属性
Fieldzhang anno = field.getAnnotation(Fielzhang.class);//获得指定属性的注解
system.out.print(anno.Name());//获得注解上的属性
system.out.print(anno.type);
system.out.print(anno.Name);