注解和反射详解(spring注解原理是反射)
一、注解
注解(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类的实例
通过类名获取 Class c = Person.class();
通过实例对象获取 Class c = person.getClass();
通过包名 Class c = Class.forName("Reflection.Person")
基本数据类型可以直接用.TYPE Class c = Integer.TYPE
哪些类型可以有Class对象
class 类
interface 接口
[] 数组
enum 枚举
annotation 注解@interface
primitive type 基本数据类型
void
类的加载过程(了解
类的加载(Load)-->类的链接(Link)-->类的初始化(Initialize) 加载:将类的class文件读入内存,并为之创建一个Class对象此过程有类加载器完成 链接:将类的二进制数据合并到JRE中 初始化:JVM负责初始化,当初始化一个类时,若发现其父类没有初始化,则先触发其父类的初始化
什么时候会发生类的初始化?
类的主动引用(一定会发生类的初始化
当虚拟机启动,先初始化main()方法所在的类
new一个类的对象
调用类的静态成员(除了final常量)和静态方法
使用java.lang.reflect包的方法对类进行反射调用
当初始化一个类,如果其父类没有被初始化,则会初始化他的父类
类的被动引动(不会发生类的初始化
当访问一个静态域时,只有真正声明这个域的类才会被初始化(子类调用父类的静态变量,不会初始化子类
通过数组定义类引用,不会触发类的初始化
引用常量不会触发此类的初始化(常量链接阶段就存入调用类的常量池中了
类加载器
作用:将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