注解与反射
java.lang.annotation包中有一个Annotation的接口,它是所有注解类型扩展的公共接口
@Override
@Override 注解是用来指定方法重写的,只能修饰方法并且只能用于方法重写,不能修饰其它的元素。
它可以强制一个子类必须重写父类方法或者实现接口的方法。
@Override public String toString(){ return super.toString(); }
@Deprecated(不推荐使用)
@Deprecated 可以用来注解类、接口、成员方法和成员变量等,用于表示某个元素(类、方法等)已过时。
当其他程序使用已过时的元素时,编译器将会给出警告。
@Deprecated public static void test(){ System.out.println("aa"); } public static void main(String[] args){ test(); }
@SuppressWarnings
@SuppressWarnings 注解指示被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告,且会一直作用于该程序元素的所有子元素。
注解的使用有以下三种:
- 抑制单类型的警告:@SuppressWarnings("unchecked")
- 抑制多类型的警告:@SuppressWarnings("unchecked","rawtypes")
- 抑制所有类型的警告:@SuppressWarnings("unchecked")
- 抑制所有警告:@SuppressWarnings("all")
元注解(负责注解其他注解)
@Target ---用于描述注解的使用范围(被描述的注解可以用在什么地方)---@Target({ ElementType.METHOD })
CONSTRUCTOR | 用于构造方法 |
FIELD | 用于成员变量(包括枚举常量) |
LOCAL_VARIABLE | 用于局部变量 |
METHOD | 用于方法 |
PACKAGE | 用于包 |
PARAMETER | 用于类型参数(JDK 1.8新增) |
TYPE | 用于类、接口(包括注解类型)或 enum 声明 |
@Retention ---表示需要在什么级别保存该注释信息,用于描述注解的生命周期(该注解被保留的时间长短)
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在 class 文件中有效(即 class 保留)
- RUNTIME:在运行时有效(即运行时保留)
生命周期大小排序为 SOURCE < CLASS < RUNTIME,前者能使用的地方后者一定也能使用。
@Document ---说明该注解将被包含在javadoc中(修饰的注解类会被 JavaDoc 工具提取成文档)
@Inherited ---说明子类可以继承父类中的注解
@Repeatable ---是否可重复注解
- RetentionPolicy.SOURCE : 仅存在于源代码中,编译阶段会被丢弃,不会包含于class字节码文件中。
- RetentionPolicy.CLASS : 默认策略,在class字节码文件中存在,在类加载的时被丢弃,运行时无法获取到。
- RetentionPolicy.RUNTIME : 始终不会丢弃,可以使用反射获得该注解的信息。自定义的注解最常用的使用方式。
自定义注解
自定义注解和创建一个接口相似,自定义注解的格式是以@interface为标志的
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @interface SPI { //注解的参数:注解类型——参数名();
String name() default ""; //default是设置默认值为空
int age();
}
public class test03(){
//驻俄界可以显示赋值,如果没有默认值,就必须给注解赋值
@SPI(name="aa",age=11)
public void test(){}
}
学习文档:https://blog.csdn.net/weixin_45860338/article/details/114140964
学习视频:https://www.bilibili.com/video/BV1p4411P7V3
// 什么是注解 public class Demo01_Annotation extends Object { // @Override就是一个重写注解 @Override public String toString() { return super.toString(); } // @Deprecated不推荐程序员使用,但是可以使用,或者存在更好的更新方式 @Deprecated public static void test() { System.out.println("Deprecated"); } // @SuppressWarnings 镇压警告 @SuppressWarnings("all") public void test01(){ List<String> list = new ArrayList<String>(); } public static void main(String[] args) { test(); } }
//测试元注解 @MyAnnotation public class Demo02_MetaAnnotation { @MyAnnotation public void test() { } } //定义一个注解 //@Target(目标)可以用在什么地方 //ElementType.METHOD方法上有效 ElementType.TYPE类上有效 @Target(value = {ElementType.METHOD, ElementType.TYPE}) //@Retention在什么地方有效 //RUNTIME>CLASS>SOURCES @Retention(value = RetentionPolicy.RUNTIME) //@Documented 表示是否将我们的注解生成在Javadoc中 @Documented //@Inherited 子类可以继承父类的注解 @Inherited @interface MyAnnotation { }
//自定义注解 public class Demo03_CustomAnnotation { //注解可以显示赋值,如果没有默认值,就必须给注解赋值 @MyAnnotation2(name = "张三") public void test() { } } @Target(value = {ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2 { //注解的参数:参数类型+参数名() //String name(); String name() default ""; int age() default 0; int id() default -1;//默认值为-1代表不存在 String[] schools() default {"西部开源","清华大学"};
反射
package com.xinyu.Reflection; public class Demo04_Reflection { public static void main(String[] args) throws ClassNotFoundException { // 通过反射获取类的class对象 Class<?> c = Class.forName("com.xinyu.Reflection.User"); System.out.println(c); Class<?> c1 = Class.forName("com.xinyu.Reflection.User"); Class<?> c2 = Class.forName("com.xinyu.Reflection.User"); Class<?> c3 = Class.forName("com.xinyu.Reflection.User"); Class<?> c4 = Class.forName("com.xinyu.Reflection.User"); // 一个类在内存中只有一个Class对象 // 一个类被加载后,类的整个结构都会被封装在Class对象中 /** * public native int hashCode();返回该对象的hash码值 * 注:哈希值是根据哈希算法算出来的一个值,这个值跟地址值有关,但不是实际地址值。 */ System.out.println(c1.hashCode()); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } } //实体类 class User { private String name; private int id; private int age; public User() { } public User(String name, int id, int age) { this.name = name; this.id = id; this.age = age; } 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; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
//测试class类的创建方式有哪些 public class Demo05_CreateClass { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("这个人是:"+person.name); //方式一:通过对象查询 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式二:forname获得 Class c2 = Class.forName("cn.doris.reflection.Student"); System.out.println(c2.hashCode()); //方式三:通过类名.class获得 Class c3 = Student.class; System.out.println(c3.hashCode()); //方式四,基本类型的包装类都有一个Type Class c4 = Integer.TYPE; System.out.println(c4); //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person { String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name=" + name + '}'; } } class Student extends Person { public Student() { this.name = "学生"; } } class Teacher extends Person { public Teacher() { this.name = "老师"; } }
//所有类型的Class public class Demo06_AllTypeClass { public static void main(String[] args) { Class c1 = Object.class; //类 Class c2 = Comparable.class; //接口 Class c3 = String[].class; //一维数组 Class c4 = int[][].class; //二维数组 Class c5 = Override.class; //注解 Class c6 = ElementType.class; //枚举 Class c7 = Integer.class; //基本数据类型 Class c8 = void.class; //void Class c9 = Class.class; //class System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); //只要元素类型与维度一样,就是同一个Class int[] a = new int[10]; int[] b = new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } }
//类加载 public class Demo07_ClassLoader { public static void main(String[] args) { A a = new A(); System.out.println(A.m); /** * 1. 加载到内存,会产生一个类对应Class对象 * 2. 链接,连接结束后m=0 * 3. 初始化 * <clinit>(){ * System.out.println("A类静态代码块初始化"); * m = 300; * m = 100; * } */ } } class A { static { System.out.println("A类静态代码块初始化"); m = 300; } static int m = 100; public A() { System.out.println("A类无参构造初始化"); } }
//测试类什么时候会初始化 public class Demo08_ActiveReference { static { System.out.println("Main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { // 1. 主动调用 //Son son = new Son(); // 反射也会产生主动引用 //Class.forName("cn.doris.reflection.Son"); //不会产生类的引用的方法 //System.out.println(Son.b); //Son[] array = new Son[5]; //System.out.println(Son.a); } } class Father { static final int b = 2; static { System.out.println("父类被加载"); } } class Son extends Father { static { System.out.println("子类被加载"); m = 100; } static int m = 300; static final int a = 1; }
//类加载器 public class Demo09_ClassLoader1 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类的加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //获取系统类加载器的父类加载器-->扩展类加载器 jre1.8.0_91\lib\ext ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //获取扩展类加载器父类加载器-->根加载器(c/c++) jre1.8.0_91\lib\rt.jar ClassLoader parent1 = parent.getParent(); System.out.println(parent1); //测试当前类是哪个加载器加载的 ClassLoader classLoader = Class.forName("com.xinyu.Reflection.Demo09_ClassLoader1").getClassLoader(); System.out.println(classLoader); //测试JDK内置的类是谁加载的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader); //如何获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); //双亲委派机制 检测安全性 你写的类和跟加载器一样的不会用你写的类 //java.lang.String -->往上推 } }
获得类运行时的结构:
Class c1 = Class.forName(“cn.doris.reflection.User”); //获取当前对象的Class //获得类的名字 c1.getName();// 获得包名 + 类名 c1.getSimpleName();// 获得类名 //获得类的属性 c1.getFields();//只能找到public属性 c1.getDeclaredFields();//找到全部的属性 c1.getDeclaredField(“name”); //获得指定属性的值 //获得类的方法 c1.getMethods(); //获得本类及父类的全部public方法 c1.getDeclaredMethods(); //获得本类的所有方法 c1.getMethod(“getName”, null);//获得指定的方法 //获得类的构造器 c1.getConstructors(); c1.getDeclaredConstructors(); c1.getDeclaredConstructor(String.class, int.class, int.class);//获得指定的构造器
//获得Class对象 Class c1 = Class.forName(“cn.doris.reflection.User”); //本质上调用了类的无参构造器 User user = (User) c1.newInstance(); //构造器创建对象 Constructor constructor=c1.getDeclaredConstructor(String.class, int.class, int.class); User user1 = (User) constructor.newInstance(“长歌”,001,17); //invoke:激活 // (对象,“方法值”) setName.invoke(user2, “doris”); //设置安全检测 name.setAccessible(true);
package com.xinyu.Reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //动态的创建对象,通过反射 public class Test09 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { //获取Class对象 Class c1 = Class.forName("com.xinyu.Reflection.User"); System.out.println(c1); //构造一个对象 // User user = (User)c1.newInstance(); //本质是调用类的无参构造器 // System.out.println(user); // // //通过构造器创建对象 // Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class); // User user2 = (User)constructor.newInstance("xinyu",001,18); // System.out.println(user2); //通过反射调用普通方法 // User user3 = (User)c1.newInstance(); // //通过反射获取一个方法 // Method setName = c1.getDeclaredMethod("setName", String.class); // // //invoke:激活的意思 // //(对象,"方法的值") // setName.invoke(user3,"狂神"); // System.out.println(user3.getName()); //通过反射操作属性 User user4 = (User)c1.newInstance(); Field name = c1.getDeclaredField("name"); name.setAccessible(true); //不能直接操作私有属性,需要关掉程序安全检测 name.set(user4,"xinyu"); System.out.println(user4.getName()); } }
性能分析对比
package com.xinyu.Reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //分析性能问题 public class Test10 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { test01(); test02(); test03(); } //普通方法调用 public static void test01(){ User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方式调用十亿次:"+(endTime-startTime)+"ms"); } //反射调用 不关闭安全检测 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName",null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式不关闭安全检测调用十亿次:"+(endTime-startTime)+"ms"); } //反射调用 关闭安全检测 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName",null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(user,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式关闭安全检测调用十亿次:"+(endTime-startTime)+"ms"); } }
泛型回忆:
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(int,char等)
package com.xinyu.Reflection; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.sql.Types; import java.util.List; import java.util.Map; //通过反射获取泛型 public class test11 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = test11.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); } } } method = test11.class.getMethod("test02",null); Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument:actualTypeArguments){ System.out.println(actualTypeArgument); } } } }
反射操作注解
package com.xinyu.Reflection; import java.lang.annotation.*; import java.lang.reflect.Field; //练习反射操作注解 public class Demo14_ORM { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.xinyu.Reflection.Student2"); //通过反射获取注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解value TableDoris tableDoris = (TableDoris) c1.getAnnotation(TableDoris.class); String value = tableDoris.value(); System.out.println(value); //获得类指定的注解 Field name = c1.getDeclaredField("name"); FiledDoris annotation = name.getAnnotation(FiledDoris.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @TableDoris("db_student") class Student2 { @FiledDoris(columnName = "db_id", type = "int", length = 10) private int id; @FiledDoris(columnName = "db_age", type = "int", length = 3) private int age; @FiledDoris(columnName = "db_name", type = "varchar", length = 200) private String name; public Student2() { } public Student2(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } @Override public String toString() { return "Student2{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //类名注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface TableDoris { String value(); } //属性注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FiledDoris { String columnName(); String type(); int length(); }