注解和反射
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取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
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类的常用方法
③获取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、类加载分析
①类的加载过程
②类加载分析
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;
}
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对象
②类加载器类型
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 }