java 反射注解有什么用_Java注解和反射

注解和反射

1、什么是注解

①Annotation是从JDK5.0开始引入的新技术

②Annotation的作用

1.不是程序本身,可以对程序作出解释

2.可以被其他程序读取

③Annotation的格式—@注释名,例如@SuppressWarnings(value="unchecked")

④Annotation使用的地方

可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问

2、内置注解

①@Override—定义在java.lang.Override中,表示方法被重写

②@Deprecated—定义在java.lang.Deprecated中,表示不鼓励程序员使用这样的元素

③@SuppressWarnings—定义在java.lang.SupressWarnings中,用来抑制编译时的警告信息

3、元注解

①元注解的作用是负责注解其他注解,Java定义了4个标准的meta—annotation类型,他们被用来提供对其他annotation类型作说明

②这些类型和它们所支持的类在java.lang.annotation包中可以找到

1.@Target:用于描述注解的使用范围

2.@Retention:表示需要在什么级别保存该注释信息

用于描述注解的生命周期

SOURCE

3.@Document:说明该注解将被包含在javadoc中

4.@Inherited:说明子类可以继承父类中的该注解

//定义一个注解//Target 表示我们的注解可以用在哪些地方//Retention 表示我们的注解在什么地方还有效//Documented 表示是否将我们的注解生成在JavaDoc中//Inherited 子类可以继承父类的注解

@Target(value ={ElementType.METHOD,ElementType.TYPE})

@Retention(value=RetentionPolicy.RUNTIME)

@Documented

@Inherited

@interfaceMyAnnotation{

}

4、自定义注解

①使用@interface自定义注解,自动继承了java.lang.annotation.Annotation接口

1 public classTest3 {2 ​3 @MyAnnotation1(name="yq",id=1)4 public voidtest(){}5 ​6 //只有当参数只有一个,且参数名为value时,才可以省略赋值

7 @MyAnnotation2("yq")8 public voidtest1(){}9 }10 ​11 @Target({ElementType.METHOD,ElementType.TYPE})12 @Retention(RetentionPolicy.RUNTIME)13 @interfaceMyAnnotation1{14 //注解的参数:参数类型 + 参数名();

15 String name() default "";//有默认值时可以不写参数;如果没有默认值,就必须给注解赋值

16 int id() default -1;//如果默认值为-1,代表不存在

17 String[] schools() default {"北大","清华","复旦"};18 }19 ​20 @Target({ElementType.METHOD,ElementType.TYPE})21 @Retention(RetentionPolicy.RUNTIME)22 @interfaceMyAnnotation2{23 String value();24 }

5、反射

①Reflection是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

7855b7e03668978e874e21a705908cc8.png

6、获得反射对象

通过getClass()方法返回一个Class,Class类是Java反射的源头,从程序运行角度看就是通过对象反射求出类的名称

1 public classTest2 {2 public static void main(String[] args) throwsClassNotFoundException {3 //通过反射获取类的class对象

4 Class c1=Class.forName("Annotation.User");5 System.out.println(c1);6 //一个类在内存中只有一个class对象7 //一个类被加载后,类的整个结构都会被封装在class对象中

8 Class c2=Class.forName("Annotation.User");9 System.out.println(c1.hashCode());10 System.out.println(c2.hashCode());11 }12 }13 ​14 //实体类

15 classUser{16 privateString name;17 private intid;18 private intage;19 }

7、得到Class的方式

①Class类

1.Class本身也是一个类

2.Class对象只能由系统建立对象

3.一个加载的类在JVM中只会有一个Class实例

4.一个Class对象对应的是一个加载到JVM中的一个class文件

5.每个类的实例都会记得自己是由哪个Class实例所生成

6.通过Class可以完整地得到一个类中的所有被加载的结构

7.Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

②Class类的常用方法

b2696451bba16172f9c5fc30135f7fdb.png

③获取Class类的实例

//方式一:通过对象获得

Class c1=person.getClass();

​//方式二:forname获得

Class c2=Class.forName("Annotation.Student");

​//方式三:通过类名.class获得

Class c3=Student.class;

​//方式四:基本内置类型的包装类都有一个TYPE属性

Class c4=Integer.TYPE;

​//获得父类类型

Class c5=c1.getSuperclass();

8、有Class对象的类型

①class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

②interface:接口

③[]:数组

④enum:枚举

⑤annotation:注解@interface

⑥primitive type:基本数据类型

⑦void

1 public classTest5 {2 public static voidmain(String[] args) {3 Class c1=Object.class;//类

4 Class c2=Comparable.class;//接口

5 Class c3=String[].class;//数组

6 Class c4=int[][].class;//二维数组

7 Class c5=Override.class;//注解

8 Class c6= ElementType.class;//枚举

9 Class c7=Integer.class;//基本类型

10 Class c8=void.class;//void

11 Class c9=Class.class;//Class类

12 System.out.println(c1);13 System.out.println(c2);14 System.out.println(c3);15 System.out.println(c4);16 System.out.println(c5);17 System.out.println(c6);18 System.out.println(c7);19 System.out.println(c8);20 System.out.println(c9);21 //只要元素类型和维度一样,就是同一个Class

22 int[] a=new int[10];23 int[] b=new int[100];24 System.out.println(a.getClass().hashCode());25 System.out.println(b.getClass().hashCode());26 }27 }

9、类加载分析

①类的加载过程

d9e8d3cea31b3f00c3e044105c7105fb.png

②类加载分析

1 public classTest6 {2 public static voidmain(String[] args) {3 A a=newA();4 System.out.println(a.m);5 }6 }7 ​8 classA{9 static{10 System.out.println("A类静态代码块初始化");11 m=300;12 }13 ​14 static int m=100;15 ​16 publicA(){17 System.out.println("A类的无参构造初始化");18 }19 }20 /*

21 运行结果:22 A类静态代码块初始化23 A类的无参构造初始化24 10025 */

1.加载到内存,会产生一个类对应的Class对象

2.链接,链接结束后,m=0

3.初始化,执行clinit方法

(){

System.out.println("A类静态代码块初始化");

m=300;

m=100;

}

0a0d3e63f25e7fa01df1fae394753864.png

10、分析类初始化

①类的主动引用(一定会发生类的初始化)

1.当虚拟机启动,先初始化main方法所在的类

2.new一个类的对象

3.调用类的静态成员(除了final常量)和静态方法

4.使用java.lang.reflect包的方法对类进行反射调用

5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类

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

1.当访问一个静态域时,只有真正声明这个域的类才会被初始化,例如当通过子类调用父类的静态变量,不会导致子类初始化

2.通过数组定义类引用,不会触发此类的初始化

3.引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

11、类加载器

①类加载器的作用

1.将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口

2.类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象

092ce4c46e704ed0ef9b26bfee6ddb5d.png

②类加载器类型

ae6413ae4405f9a385d6854fc1ffc5af.png

1 public classTest7 {2 public static void main(String[] args) throwsException {3 //获取系统类的加载器

4 ClassLoader classLoader=ClassLoader.getSystemClassLoader();5 System.out.println(classLoader);6 //获取系统类加载器的父类加载器-->扩展类加载器

7 ClassLoader parent=classLoader.getParent();8 System.out.println(parent);9 //获取扩展类加载器的父类加载器-->根加载器

10 ClassLoader parent1=parent.getParent();11 System.out.println(parent1);12 //测试当前类是哪个加载器加载的

13 ClassLoader classLoader1=Class.forName("Annotation.Test7").getClassLoader();14 System.out.println(classLoader1);15 //测试JDK内置的类是哪个加载器加载的

16 classLoader1=Class.forName("java.lang.Object").getClassLoader();17 System.out.println(classLoader1);18 //如何获得系统类加载器可以加载的路径

19 System.out.println(System.getProperty("java.class.path"));20 }21 }

③双亲委派机制

当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

12、获取类的运行时结构

通过相关的方法获取相关的类信息

1 public classTest8 {2 public static void main(String[] args) throwsException {3 User user=new User("yq",1,6);4 Class c1=user.getClass();5 //获得类的名字

6 System.out.println(c1.getName());//获得包名+类名

7 System.out.println(c1.getSimpleName());//获得类名8 //获得类的属性

9 Field[] fields=c1.getFields();//只能找到public属性

10 fields=c1.getDeclaredFields();//找到全部的属性

11 for(Field field:fields){12 System.out.println(field);13 }14 //获得指定属性的值

15 Field name=c1.getDeclaredField("name");16 System.out.println(name);17 //获得类的方法

18 Method[] methods=c1.getMethods();//获得本类及其父类的全部public方法

19 for(Method method:methods){20 System.out.println("getMethod---"+method);21 }22 methods=c1.getDeclaredMethods();//获得本类的所有方法

23 for(Method method:methods){24 System.out.println("getDeclaredMethods---"+method);25 }26 //获得指定的方法

27 Method getName=c1.getMethod("getName",null);28 Method setName=c1.getMethod("setName",String.class);29 System.out.println(getName);30 System.out.println(setName);31 //获得类的构造器

32 Constructor[] constructors=c1.getConstructors();//获得全部的public构造器

33 for(Constructor constructor:constructors){34 System.out.println("getConstructors---"+constructor);35 }36 constructors=c1.getDeclaredConstructors();//获得全部的构造器

37 for(Constructor constructor:constructors){38 System.out.println("getDeclaredConstructors---"+constructor);39 }40 //获得指定的构造器

41 Constructor constructor=c1.getConstructor(String.class,int.class,int.class);42 System.out.println(constructor);43 }44 }

13、动态创建对象

通过反射实例化类,调用类的属性和方法

1 public classTest9 {2 public static void main(String[] args) throwsException {3 //获得Class对象

4 Class c1=Class.forName("Annotation.User");5 //构造一个对象

6 User user1=(User) c1.newInstance();//本质是调用了类的无参构造器

7 System.out.println(user1);8 //通过构造器创建对象

9 Constructor constructor=c1.getDeclaredConstructor(String.class,int.class,int.class);10 User user2=(User) constructor.newInstance("yq",1,6);11 System.out.println(user2);12 //通过反射获取一个方法

13 Method setName=c1.getDeclaredMethod("setName",String.class);14 setName.invoke(user1,"yq1");15 System.out.println(user1.getName());16 //通过反射操作属性

17 User user3=(User) c1.newInstance();18 Field field=c1.getDeclaredField("name");//不能直接操作私有属性

19 field.setAccessible(true);//关闭程序的安全监测,使private修饰的也可以被操作

20 field.set(user3,"yq2");21 System.out.println(user3.getName());22 }23 }

14、获取泛型信息

通过相应的方法可以获得参数类型和返回值类型

1 public classTest11 {2 public void test1(Map map, Listlist){3 System.out.println("test1");4 }5 public Maptest2(){6 System.out.println("test2");7 return null;8 }9 ​10 public static void main(String[] args) throwsException {11 Method method=Test11.class.getMethod("test1",Map.class,List.class);12 Type[] types=method.getGenericParameterTypes();//获得泛型参数类型

13 for(Type type : types) {14 System.out.println(type);15 if (type instanceof ParameterizedType){//获取参数类型

16 Type[] actualTypeArguments=((ParameterizedType)type).getActualTypeArguments();17 for(Type actualTypeArgument : actualTypeArguments) {18 System.out.println("---"+actualTypeArgument);19 }20 }21 }22 ​23 method=Test11.class.getMethod("test2",null);24 Type genericReturnType=method.getGenericReturnType();25 if(genericReturnType instanceofParameterizedType){26 Type[] actualTypeArguments=((ParameterizedType)genericReturnType).getActualTypeArguments();27 for(Type actualTypeArgument : actualTypeArguments) {28 System.out.println("-->"+actualTypeArgument);29 }30 }31 }32 }

15、获取注解信息

通过相应的方法可以获取注解信息

1 public classTest12 {2 public static void main(String[] args) throwsException {3 Class c1=Class.forName("Annotation.Student1");4 //通过反射获得注解

5 Annotation[] annotations=c1.getAnnotations();6 for(Annotation annotation : annotations) {7 System.out.println(annotation);8 }9 //获得注解的value值

10 TableStudent tableStudent=(TableStudent) c1.getAnnotation(TableStudent.class);11 String value=tableStudent.value();12 System.out.println(value);13 //获得类指定注解

14 Field f=c1.getDeclaredField("name");15 FieldStudent annotation=f.getAnnotation(FieldStudent.class);16 System.out.println(annotation.colName()+";"+annotation.type()+";"+annotation.length());17 }18 }19 ​20 @TableStudent("db_Student")21 classStudent1{22 @FieldStudent(colName="db_name",type = "varchar",length = 10)23 privateString name;24 @FieldStudent(colName="db_id",type = "int",length = 10)25 private intid;26 @FieldStudent(colName="db_age",type = "int",length = 6)27 private intage;28 ​29 publicStudent1() {30 }31 ​32 public Student1(String name, int id, intage) {33 this.name =name;34 this.id =id;35 this.age =age;36 }37 ​38 publicString getName() {39 returnname;40 }41 ​42 public voidsetName(String name) {43 this.name =name;44 }45 ​46 public intgetId() {47 returnid;48 }49 ​50 public void setId(intid) {51 this.id =id;52 }53 ​54 public intgetAge() {55 returnage;56 }57 ​58 public void setAge(intage) {59 this.age =age;60 }61 ​62 @Override63 publicString toString() {64 return "Student1{" +

65 "name='" + name + '\'' +

66 ", id=" + id +

67 ", age=" + age +

68 '}';69 }70 }71 ​72 //类名的注解

73 @Target(ElementType.TYPE)74 @Retention(RetentionPolicy.RUNTIME)75 @interfaceTableStudent{76 String value();77 }78 ​79 //属性的注解

80 @Target(ElementType.FIELD)81 @Retention(RetentionPolicy.RUNTIME)82 @interfaceFieldStudent{83 String colName();84 String type();85 intlength();86 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值