注解与反射_1 - 小记

1. 自定义注解@interface

@interface MyAnno { //注解类型:参数类型参数名()defult默认值; String name() default ""; int age() default 0; int id() default -1; String[] schools(); //无默认值,那外部写这个注解时就必须带参数!}

//测试类 public class Test { @MyAnno(name = "jiaxin") public void test () { .... } }

【注解与反射_1 - 小记】2.元注解
//表示我们的注解可以用在哪些地方 @Target(value = https://www.it610.com/article/{ElementType.METHOD , ElementType.ANNOTATION_TYPE})//表示我们的注解在什么地方还有效runtime> class > sources @Retention(value = https://www.it610.com/article/RetentionPolicy.RUNTIME)//表示是否将我们的注解生成在java doc中 @Documented//子类可以继承父类的注解 @Inherited @interface MyAnno {}

3.注解种类:
内置注解+元注解+自定义注解

反射Reflection
1.反射机制是Java被视为动态语言的关键,在框架Spring、Mybatis代码中有所体现。
2.如何创建对象? new或者clone()克隆或者反射!!
3.反射与注解相结合。 反射可以获取类的内部信息,动态化(运行时刻可以查看、改变其结构的)。
4.比较:
正常方式:引入包类名-new-获取实例化对象
反射方式:实例化对象-getClass()-得到完整的包类名称
5.反射机制提供的功能:
判断任一对象所属的类 构造任一类的对象 判断任一类所具有的属性和方法 获取泛型信息 处理注解 调用任一个对象的成员变量及方法 生成动态代理 ....

6.优缺点:
优:实现动态创建对象和编译+灵活性
缺:影响性能
package com.tencent.reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Member; import java.lang.reflect.Method; public class Test8 {public static void t1() { 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"); //5-6ms }public static void t2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getDeclaredMethod("getName" , null); getName.setAccessible(false); 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"); //5-6ms }public static void t3() 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"); //5-6ms }public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { System.out.print("普通调用getName():"); Test8.t1(); System.out.print("开启安全检测,调用getName():"); Test8.t2(); System.out.print("关闭安全检测,调用getName():"); Test8.t3(); /* 普通调用getName():6ms 开启安全检测,调用getName():1917ms 关闭安全检测,调用getName():1295ms---说明反射消耗性能,费时. * */ } }

7.获取Class类的几种方法
package com.tencent.reflection; public class Test2 {public static void main(String[] args) throws ClassNotFoundException {//1.通过对象 调用getClass()获取 User user = new User("jx" , 21); Class c1 = user.getClass(); System.out.println(c1.hashCode()); //2.通过类的class属性获取 Class c2 = User.class; System.out.println(c2.hashCode()); //3.通过类路径获取 forName() Class c3 = Class.forName("com.tencent.reflection.User"); System.out.println(c3.hashCode()); //4.内置基本数据类型 包装类 Class c4 = Integer.TYPE; System.out.println(c4); //int//5.获得对象所属类的父类类型 System.out.println(c1.getSuperclass()); } }

8.哪些类型具有Class对象(or 属性)?
package com.tencent.reflection; import sun.reflect.generics.scope.ClassScope; import java.lang.annotation.ElementType; public class Test3 {public static void main(String[] args) {Class c1 = Object.class; //类Class c2 = Comparable.class; //接口Class c3 = String[].class; //数组Class c4 = Override.class; //注解Class c5 = ElementType.class; //枚举Class c6 = Integer.class; //基本数据类型Class c7 = void.class; //voidClass c8 = Class.class; //ClassSystem.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); //元素类型相同,则获取对应的Class类型都相同 int[] a = new int[10]; //1163157884 int[] b = new int[100]; //1163157884 System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } }

9.Java内存分析
栈:存放基本数据类型+引用对象的变量地址
堆:存放对象+数组,可被所有线程共享,注:存放Class对象!
方法区:被所有线程共享,存放 static静态变量
10.类加载过程
分三步
类加载Load + 类链接Link + 类初始化Initialize
a.加载: class文件字节码,加载到内存中,将静态数据转换成方法区的运行时数据结构,在堆中生成Class对象
b.链接:
验证:检查类信息符合JVM规范,有无安全问题;
准备:为类变量,即:静态变量,分配内存,设置默认初始值;
解析:虚拟机常量池,符号引用 替换为 直接引用地址 的过程。
c.初始化:
执行类构造器clinit()的过程;
初始化一个类,要检查其父类,先初始化父类;
虚拟区要确保一个类的构造器clinit()在多线程环境下,加锁及同步的进行。
11.什么情况发生类的初始化?
主动引用会发生;被动引用不会。
主动引用:略;
引言:主动引用中,当前程序执行的Main方法一定会初始化。被动引用: a. 访问静态域的话,是真正声明这个域的类才会初始化!例如: 通过子类引用父类的静态变量,则不会引起子类的初始化!只会引起父类的初始化。b. 通过数组定义类访问时,不会加载当前定义类的初始化!c. 引用常量。不会引起当前定义类的初始化! 因为常量在链接的第三步解析步骤下,就会调入常量池中了。


    推荐阅读