阅读 196

注解和反射详解(spring注解原理是反射)

一、注解

  1. 注解(Annotation)的作用:可以被其他程序(比如:编译器)读取。

@Override 重写注解 @Deprecated 表示不鼓励使用或者已经废弃,通常是因为它很危险或者存在更好的方法 @SuppressWarnings 用来抑制编译时的警告信息,传入“all”抑制所有警告

二、元注解

元注解的作用:负责注解其他注解(禁止套娃。。。

@Target 表示我们的注解可以用在哪些地方 @Retention 表示我们的注解在什么地方有效 runtime>class>sources 默认RUNTIME @Documented 表示是否将我们的注解生成在Javadoc中 @Inherited 表示子类可以继承父类的注解

三、自定义注解

使用 @interface自定义注解,自动继承Annotation接口

@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotarion{     //注解的参数:参数类型 + 参数名 ();     String value() default "";//参数名为value时,传参时可以省略value = ,不传参时,则为default默认值 } 复制代码

四、反射

正常方式:引入需要的“包类”名称-->通过new实例化-->取得实例对象

加载类完成后,在堆内存的方法区就产生了一个Class类型对象,这个对象包含了完整的类的结构信息,可以通过这个对象看到类的结构

反射方式:实例化对象-->getClass()方法-->得到完整的“包类”名称

public class Test01 {     public static void main(String[] args) throws ClassNotFoundException {         //通过反射获取类的class对象         Class c1 = Class.forName("Reflection.Person");         System.out.println(c1);         //一个类在内存中只有一个class对象         //一个类被加载后,类的整个结构都会被封装在Class对象中         Class c2 = Class.forName("Reflection.Person");         Class c3 = Class.forName("Reflection.Person");         System.out.println(c2.hashCode());         System.out.println(c3.hashCode());     } } class Person{     private String name;     private int id;     public Person() {     }     public Person(String name, int id) {         this.name = name;         this.id = id;     }     public String getName() {         return name;     }     public void setName(String name) {         this.name = name;     }     public int getId() {         return id;     }     public void setId(int id) {         this.id = id;     } } 复制代码

获取Class类的实例

  1. 通过类名获取 Class c = Person.class();

  2. 通过实例对象获取 Class c = person.getClass();

  3. 通过包名 Class c = Class.forName("Reflection.Person")

  4. 基本数据类型可以直接用.TYPE Class c = Integer.TYPE

哪些类型可以有Class对象

  1. class 类

  2. interface 接口

  3. [] 数组

  4. enum 枚举

  5. annotation 注解@interface

  6. primitive type 基本数据类型

  7. void

类的加载过程(了解

类的加载(Load)-->类的链接(Link)-->类的初始化(Initialize) 加载:将类的class文件读入内存,并为之创建一个Class对象此过程有类加载器完成 链接:将类的二进制数据合并到JRE中 初始化:JVM负责初始化,当初始化一个类时,若发现其父类没有初始化,则先触发其父类的初始化

什么时候会发生类的初始化?

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

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

  2. new一个类的对象

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

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

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

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

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

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

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

类加载器

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

获取类的运行时结构

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test02 {     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {         Class c = Class.forName("Reflection.Person");         //获取类的名字         String name = c.getName();         System.out.println(name);//获取包名 + 类名         System.out.println(c.getSimpleName());//类名         //获取类的属性         System.out.println("---");         Field[] fields = c.getFields();//只能获得public属性         for (Field field : fields) {             System.out.println(field);         }         Field[] declaredFields = c.getDeclaredFields();//找到全部的属性         for (Field declaredField : declaredFields) {             System.out.println(declaredField);         }         System.out.println(c.getDeclaredField("name"));//获得指定的属性         //获得类的方法         System.out.println("===");         Method[] methods = c.getMethods();//本类及其父类的全部方法         for (Method method : methods) {             System.out.println(method);         }         System.out.println("===");         Method[] declaredMethods = c.getDeclaredMethods();//获得本类的方法         for (Method declaredMethod : declaredMethods) {             System.out.println(declaredMethod);         }         //获得本类的指定方法         //参数考虑到重载         System.out.println(c.getMethod("setName", String.class));         //获得构造器         System.out.println("===");         Constructor[] constructors = c.getConstructors();//获得所有构造器 public         for (Constructor constructor : constructors) {             System.out.println(constructor);         }         System.out.println(c.getDeclaredConstructor(String.class,int.class));//不局限public的方法     } } 复制代码

动态创建对象

调用Class对象的newInstance()方法 1)类必须有一个无参构造器 2)类的构造器的访问权限需要足够

用构造器创建对象 调用方法、修改属性

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test03 {     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {         Class c = Class.forName("Reflection.Person");         Person person = (Person) c.newInstance();//本质调用了无参构造器         System.out.println(person);         //通过构造器创建对象         System.out.println("===");         Constructor constructor = c.getDeclaredConstructor(String.class, int.class);         Person instance = (Person)constructor.newInstance("小王", 170788);         System.out.println(instance);         //通过反射调用普通方法         System.out.println("===");         Method method = c.getMethod("setName", String.class);         //invoke 激活的意思         method.invoke(instance,"大王");//使用invoke方法来传入使用此方法的对象和value         System.out.println(instance);         //通过反射操作属性         System.out.println("===");         Field name = c.getDeclaredField("name");         //不能直接访问private的属性,需要关闭程序的安全检测,利用如下方法         name.setAccessible(true);//true 这样就是可以访问了         name.set(instance,"小王");         System.out.println(instance);         //Methord,Field,Construtor 对象都有setAccessible()开关     } } 复制代码

性能问题

当访问权限为true时,这样会提高反射的效率

import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test04 {     public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {         test01();         test02();         test03();     }     public static void test01(){         Person p = new Person();         long startTime = System.currentTimeMillis();         for (int i = 0; i < 100000000; i++) {             p.getName();         }         long endTime = System.currentTimeMillis();         System.out.println("普通方法的运行时间:" + (endTime - startTime) + "ms");     }     public static void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {        Class c = Class.forName("Reflection.Person");         Constructor constructor = c.getConstructor();         Person instance =(Person) constructor.newInstance();         Method method = c.getMethod("getName", null);         long startTime = System.currentTimeMillis();         for (int i = 0; i < 100000000; i++) {             method.invoke(instance,null);         }         long endTime = System.currentTimeMillis();         System.out.println("反射方法的运行时间:" + (endTime - startTime) + "ms");     }     public static void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {         Class c = Class.forName("Reflection.Person");         Constructor constructor = c.getConstructor();         Person instance =(Person) constructor.newInstance();         Method method = c.getMethod("getName", null);         method.setAccessible(true);         long startTime = System.currentTimeMillis();         for (int i = 0; i < 100000000; i++) {             method.invoke(instance,null);         }         long endTime = System.currentTimeMillis();         System.out.println("反射方法关闭安全检测的运行时间:" + (endTime - startTime) + "ms");     } } 复制代码

获取泛型信息

import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; public class Test05 {     public void test01(Map<String ,Person> map, List<Person> list){         System.out.println("test01");     }     public Map<String,Person> test02(){         System.out.println("test02");         return null;     }     public static void main(String[] args) throws NoSuchMethodException {         Method method = Test05.class.getMethod("test01", Map.class, List.class);         Type[] genericParameterTypes = method.getGenericParameterTypes();         for (Type genericParameterType : genericParameterTypes) {             System.out.println(genericParameterType);//打印泛型参数类型             if(genericParameterType instanceof ParameterizedType){//有参数化类型信息                 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();//把其中真实的参数拿出来                 for (Type actualTypeArgument : actualTypeArguments) {                     System.out.println(actualTypeArgument);                 }             }         }         System.out.println("===");         Method method1 = Test05.class.getMethod("test02");         Type genericReturnType = method1.getGenericReturnType();         System.out.println(genericReturnType);         if (genericReturnType instanceof ParameterizedType){             Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();             for (Type actualTypeArgument : actualTypeArguments) {                 System.out.println(actualTypeArgument);             }         }     } } 复制代码

反射操作注解(重要

import java.lang.annotation.*; import java.lang.reflect.Field; public class Test06 {     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {         Class aClass = Class.forName("Reflection.Student");         //利用反射访问类的注解         Annotation[] annotations = aClass.getAnnotations();         for (Annotation annotation : annotations) {             System.out.println(annotation);         }        Xiaowang xiaowang = (Xiaowang)aClass.getAnnotation(Xiaowang.class) ;         System.out.println(xiaowang.value());         //利用反射访问属性的注解         System.out.println("===");         Field field = aClass.getDeclaredField("name");         FieldWang annotation = field.getAnnotation(FieldWang.class);         System.out.println(annotation.columnName());         System.out.println(annotation.length());         System.out.println(annotation.type());     }     } @Xiaowang("db_student") class  Student{     @FieldWang(columnName = "db_name",type = "db_String",length = 10)     private String name;     @FieldWang(columnName = "db_id",type = "db_int",length = 10)     private int id;     public Student() {     }     public Student(String name, int id) {         this.name = name;         this.id = id;     }     public String getName() {         return name;     }     public void setName(String name) {         this.name = name;     }     public int getId() {         return id;     }     public void setId(int id) {         this.id = id;     } } //类名的注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface Xiaowang{     String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldWang{     String columnName();     String type();     int length(); }


作者:方圆想当图灵
链接:https://juejin.cn/post/7029211567908470792

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐