Java注解与反射

Java注解与反射1 注解1.1 内置注解1.2 元注解1.3 自定义注解2 反射机制2.1 获取反射对象2.2 类加载的内存分析2.3 类初始化条件2.4 类加载器2.5 获取运行时类的信息2.6 动态创建对象2.7 反射获取泛型2.8 反射获取注解
Java注解与反射
1 注解
Annotation的作用:
- 不是程序,但是是对程序做解释(与注释相同)
- 可以被其他程序读取
Annotation的格式:
- @注解(valuse="")
1.1 内置注解
- @Override 只能用于修饰方法,表示此方法重写父类的方法
- @Deprecated 已过时,提示此方法有更好的替代方法,建议使用替代的方法
- @SuppressWarnings 镇压警告,抑制编译时产生的警告信息
xxxxxxxxxx251/*内置注解*/2public class TestAnnotation01 {3
4 /*重写注解*/5 6 public String toString() {7 return super.toString();8 }9
10 /*废弃 已过时*/11 12 public static void test(){13 System.out.println("Deprecated");14 }15
16 /*镇压警告*/17 ("all")18 public static void warn(){19 List<String> list = new ArrayList<String>();20 }21
22 public static void main(String[] args) {23 test();24 }25}1.2 元注解
元注解的作用是注解其他的注解
- @Target:表示注解的使用范围(方法,类...)
- @Retention:表示在什么级别保存注解信息(SOURCE CLASS RUNTIME)
- @Documented:表示将注解生成在JAVAdoc中
- @Inherited:表示子类可以继承父类的注解
xxxxxxxxxx241/*测试元注解*/2public class TestAnnotation02 {3
4 5 public void test(){6
7 }8}9
10/*定义一个注解*/11//Target 表示注解可以用的位置12(value = ElementType.METHOD)13
14//Retention 表示注解在什么时候有效15(value = RetentionPolicy.RUNTIME)16
17//Documented 表示将注解生成在JAVAdoc中1819
20//Inherited 表示子类可以继承父类的注解2122@interface MyAnnotation{23
24}1.3 自定义注解
参数为value可以省略参数名
xxxxxxxxxx421/*自定义注解*/2public class TestAnnotation03 {3
4 (name = "cr", age = 18, schools = {"nm","sm"})5 public void test() {6
7 }8
9 ("pl")10 public void test2() {11
12 }13}14
15/*定义一个注解*/16//Target 表示注解可以用的位置17(value = {ElementType.METHOD,ElementType.TYPE})18
19//Retention 表示注解在什么时候有效20(value = RetentionPolicy.RUNTIME)21
22//Documented 表示将注解生成在JAVA doc中2324
25//Inherited 表示子类可以继承父类的注解2627@interface AnnotationTest{28
29 //注解的参数: 参数类型 + 参数名()30 String name() default "";31 int age() default 0;32 int id() default -1;//默认值为-1,代表不存在33
34 String[] schools();35}36
37
38(value = {ElementType.METHOD,ElementType.TYPE})39(value = RetentionPolicy.RUNTIME)40@interface AnnotationTest02 {41 String value();42}2 反射机制
动态语言&静态语言
动态语言:在运行时可以改变其结构的语言
- C#,JavaScript,PHP,Python
静态语言:运行时结构不能改变
- Java,c,c++
Java是准动态语言,可以通过反射机制实现动态语言的特性
2.1 获取反射对象
Reflection
- 反射机制允许程序在执行时,获取任何类的内部信息,并能直接操作任意内部属性及方法(动态的特性)
- 加载完类后,在堆方法区中就产生了Class类的对象,Class对象包含了所有类的结构信息
获取class对象:
定义需要获取反射对象的类:
xxxxxxxxxx551/*实体类:pojo entity*/2class User{3 private String name;4 private int id;5 private int age;6
7 public User() {8 }9
10 public User(String name, int id, int age) {11 this.name = name;12 this.id = id;13 this.age = age;14 }15
16 public void setName(String name) {17 this.name = name;18 }19
20 public void setId(int id) {21 this.id = id;22 }23
24 public void setAge(int age) {25 this.age = age;26 }27
28 public String getName() {29 return name;30 }31
32 public int getId() {33 return id;34 }35
36 public int getAge() {37 return age;38 }39
40 41 public String toString() {42 return "User{" +43 "name='" + name + '\'' +44 ", id=" + id +45 ", age=" + age +46 '}';47 }48}49
50class Student extends User{51
52 public Student(int id, int age) {53 super("学生", id, age);54 }55}测试反射获取class对象:
xxxxxxxxxx371public static void main(String[] args) throws ClassNotFoundException {2 /*通过反射获取类的Class对象*/3 Class c1 = Class.forName("Demo03.User");4 System.out.println(c1);5
6 Class c2 = Class.forName("Demo03.User");7
8 /*一个类在内存中只有一个Class对象9 * 一个类被加载之后,类的整个结构都会封装在Class对象中*/10 System.out.println(c1.hashCode());11 System.out.println(c2.hashCode());12 //同一个对象13 System.out.println("----------------");14
15 User user = new Student(1,1);16 System.out.println("人名是:"+user.getName());17
18 /*1.通过对象获得Class对象*/19 Class c3 = user.getClass();20 System.out.println(c3.hashCode());21
22 /*2.通过forname获取Class*/23 Class c4 = Class.forName("Demo03.Student");24 System.out.println(c4.hashCode());25
26 /*3.通过类名.class获得*/27 Class c5 = Student.class;28 System.out.println(c5.hashCode());29
30 /*4.基本内置类的包装类都有Type属性*/31 Class c6 = Integer.TYPE;32 System.out.println(c6.hashCode());33
34 /*获得父类类型*/35 Class c7 = c3.getSuperclass();36 System.out.println(c7);37}获取各种类型的Class对象
xxxxxxxxxx91Class c1 = Object.class; //类2Class c2 = Comparable.class; //接口3Class c3 = String[].class; //一维数组4Class c4 = int[][].class; //二维数组5Class c5 = Integer.class; //基本数据类型6Class c6 = Override.class; //注解7Class c7 = ElementType.class; //枚举8Class c8 = void.class; //void9Class c9 = Class.class; //Classxxxxxxxxxx91class java.lang.Object2interface java.lang.Comparable3class [Ljava.lang.String;4class [[I5class java.lang.Integer6interface java.lang.Override7class java.lang.annotation.ElementType8void9class java.lang.Class2.2 类加载的内存分析
Java内存
堆区:
- new的对象,数组
- 可以被所有的线程共享
- 不会存放引用
栈区:
- 存放局部变量
- 引用对象的变量(引用在堆区的地址)
方法区:
- 包含所有的class
- 可以被所有的线程共享
- 特殊的堆区
类的加载过程
1.类的加载:将类的class文件读入内存,并为之创建一个Class对象,此过程由类加载器完成
2.类的链接:将类的二进制数据合并到JRE中
- 验证:确保类的信息符合JVM规范
- 准备:为static变量分配内存,并设置默认值,在方法区中
- 解析:将常量池的符号引用(常量名)替换为直接引用(地址)
3.类的初始化:JVM负责类初始化
- 执行类构造器方法,类构造器自动收集所有变量的赋值和静态代码块中的语句合并(不是对象构造器)
- 初始化一个类的时候,如果发现父类没有初始化,会先将父类进行初始化
- JVM保证每个类的类构造器方法在多线程环境正确加锁和同步
测试类的加载:
xxxxxxxxxx181class A{2 static {3 System.out.println("A类静态代码块");4 m = 300;5 }6
7 static int m = 100;8
9 public A() {10 System.out.println("A类无参构造器");11 }12}13
14 public static void main(String[] args) {15 System.out.println("创建A类的对象");16 A a = new A();17 System.out.println(A.m);18 }执行结果:
- 创建A类的对象 A类静态代码块 A类无参构造器 100
类的加载过程:
1.加载到内存,产生一个A类对应的Class对象
2.链接,链接结束后 m=0
3.初始化,类构造器方法将静态代码块合并,结果:
<clinit>(){
System.out.println("A类静态代码块"); m = 300; m = 100;
}
2.3 类初始化条件
类主动引用(发生类初始化)
- JVM启动,初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员变量或静态方法
- 使用反射方式对类进行反射调用
- 初始化一个类会先初始化它的父类
类的被动引用(不发生类的初始化)
- 访问一个静态作用域,只有声明这个域的类会被初始化(子类用父类的静态方法,子类不会初始化)
- 通过数组定义引用,不会触发类初始化
- 引用常量不会触发类初始化(链接阶段已经进入常量池)
测试类的初始化:
xxxxxxxxxx421/*测试类何时初始化*/2public class TestClassInit {3 static {4 System.out.println("Main类被加载");5 }6
7 public static void main(String[] args) throws ClassNotFoundException {8 /*主动引用*/9 /*new*/10 //Son son = new Son();11
12 /*反射*/13 //Class.forName("Demo04.Son");14
15 /*通过子类调用父类的静态不会加载子类*/16 //System.out.println(Son.b);17
18 /*通过数组定义引用,不会发生类的初始化*/19 //Son[] array = new Son[5];20
21 /*使用常量不会发生类初始化*/22 System.out.println(Son.n);23 }24}25
26class Father{27 static int b = 2;28
29 static {30 System.out.println("父类被加载");31 }32}33
34class Son extends Father{35 static {36 System.out.println("子类被加载");37 m = 300;38 }39
40 static int m = 100;41 static final int n = 1;42}2.4 类加载器
- 类加载器的作用:将class文件字节码加载到内存中,将静态数据转换成方法区的运行时数据结构,在堆区生成Java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:某个类加载到类加载器中,会维持加载一段时间,JVM垃圾回收机制会回收Class对象
类加载器种类
- 引导类加载器:JVM自带类加载器,装载核心类库,C++编写,无法直接获取
- 扩展类加载器:负责jre/lib/ext目录下的jar包或指定目录下的jar包装入工作库
- 系统类加载器:负责java -class path或指定目录jar包装入,最常用类加载器
xxxxxxxxxx281public static void main(String[] args) throws ClassNotFoundException {2
3 /*获取系统类加载器*/4 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();5 System.out.println(systemClassLoader);6
7 /*获取系统类加载器的父类加载器-->扩展类加载器*/8 ClassLoader extendClassLoader = systemClassLoader.getParent();9 System.out.println(extendClassLoader);10
11 /*获取扩展类加载器的父类加载器-->根加载器*/12 ClassLoader rootClassLoader = extendClassLoader.getParent();13 System.out.println(rootClassLoader);14
15 /*获取当前类的类加载器*/16 ClassLoader classLoader = Class.forName("Demo04.TestClassLoader").getClassLoader();17 System.out.println(classLoader);18
19 /*测试JDK内部类的类加载器*/20 classLoader = Class.forName("java.lang.Object").getClassLoader();21 System.out.println(classLoader);22
23 /*类加载器可以加载的路径*/24 System.out.println(System.getProperty("java.class.path"));25
26 /*双亲委派机制*/27 //保证用户定义的包不会影响java内部类28}2.5 获取运行时类的信息
xxxxxxxxxx631/*获取类运行时结构*/2public class GetClassInformation {3 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {4 Class c1 = Class.forName("Demo03.User");5
6 System.out.println("名字:");7 /*获得类的名字*/8 System.out.println(c1.getName());9 System.out.println(c1.getSimpleName());10
11 System.out.println("属性:");12 /*获得类的所有属性*/13 //Field[] fields = c1.getFields(); //只能找到public属性14 Field[] fields = c1.getDeclaredFields(); //找到全部属性15 for (Field field : fields) {16 System.out.println(field);17 }18
19 System.out.println("---------------");20 /*获得指定属性*/21 Field name = c1.getDeclaredField("name");22 System.out.println(name);23
24 System.out.println("方法:");25 /*获取类的方法*/26 Method[] methods = c1.getMethods();//获取本类与父类所有public方法27 for (Method method : methods) {28 System.out.println(method);29 }30
31 System.out.println("---------------");32 methods = c1.getDeclaredMethods();//获取本类的所有方法33 for (Method method : methods) {34 System.out.println(method);35 }36
37 /*获取指定方法*/38 System.out.println("---------------");39 Method getName = c1.getMethod("getName",null);40 Method setName = c1.getMethod("setName", String.class);41
42 System.out.println(getName);43 System.out.println(setName);44
45 System.out.println("构造器:");46 /*获取类的构造器*/47 Constructor[] constructors = c1.getConstructors();48 for (Constructor constructor : constructors) {49 System.out.println(constructor);50 }51
52 System.out.println("---------------");53 constructors = c1.getDeclaredConstructors();54 for (Constructor constructor : constructors) {55 System.out.println(constructor);56 }57
58 /*获取指定构造器*/59 System.out.println("---------------");60 Constructor constructor = c1.getConstructor(String.class,int.class,int.class);61 System.out.println(constructor);62 }63}2.6 动态创建对象
xxxxxxxxxx301/*动态创建对象*/2public class TestDynClassCreate {3 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {4 /*获得class对象*/5 Class class1 = Class.forName("Demo05.User");6
7 /*构造一个对象*/8 Object user = class1.newInstance();//本质调用无参构造器9 System.out.println(user);10
11 /*通过构造器创建对象*/12 Constructor constructor = class1.getDeclaredConstructor(String.class,int.class,int.class);13 Object user1 = constructor.newInstance("张三", 1, 18);14 System.out.println(user1);15
16 /*通过反射获取一个方法*/17 User user2 = (User) class1.newInstance();18 Method setName = class1.getMethod("setName", String.class);19 setName.invoke(user2,"李明");//激活 传递对象和参数20 System.out.println(user2.getName());21
22 /*通过反射操作属性*/23 User user3 = (User) class1.newInstance();24 Field name = class1.getDeclaredField("name");25
26 name.setAccessible(true);//关闭访问安全检测27 name.set(user3,"李华");28 System.out.println(user3.getName());29 }30}2.7 反射获取泛型
xxxxxxxxxx491/*测试反射获取泛型*/2public class TestGetParadigm {3
4 public void test01(Map<String,User> map, List<User> list){5 System.out.println("test 1");6 }7
8 public Map<String,User> test02(){9 System.out.println("test 2");10 return null;11 }12
13 public static void main(String[] args) throws NoSuchMethodException {14 Method test01 = TestGetParadigm.class.getMethod("test01", Map.class, List.class);15
16 /*获取泛型的参数类型*/17 Type[] genericParameterTypes = test01.getGenericParameterTypes();18
19
20 for (Type genericParameterType : genericParameterTypes) {21 System.out.println("#"+genericParameterType);22 /*泛型的参数类型是否为结构化参数类型*/23 if (genericParameterType instanceof ParameterizedType){24 /*转泛型参数类型为结构化参数类型,并调用获取真实参数信息*/25 Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();26 for (Type actualTypeArgument : actualTypeArguments) {27 System.out.println(actualTypeArgument);28 }29 }30 }31
32 System.out.println("------------");33
34 Method test02 = TestGetParadigm.class.getMethod("test02", null);35
36 /*获取泛型的参数类型*/37 Type genericReturnType = test02.getGenericReturnType();38
39 System.out.println("#"+genericReturnType);40 /*泛型的参数类型是否为结构化参数类型*/41 if (genericReturnType instanceof ParameterizedType){42 /*转泛型参数类型为结构化参数类型,并调用获取真实参数信息*/43 Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();44 for (Type actualTypeArgument : actualTypeArguments) {45 System.out.println(actualTypeArgument);46 }47 }48 }49}2.8 反射获取注解
x
1/*获取注解信息*/2public class TestGetAnnotations {3 public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {4 Class c1 = Class.forName("Demo05.Student");5
6 /*获得注解*/7 Annotation[] annotations = c1.getAnnotations();8 for (Annotation annotation : annotations) {9 System.out.println(annotation);10 }11
12 /*获得注解的值*/13 Table table = (Table) c1.getAnnotation(Table.class);14 String value = table.value();15 System.out.println(value);16
17 /*获得类指定注解值*/18 Field field = c1.getDeclaredField("name");19 FieldDb annotation = field.getAnnotation(FieldDb.class);20 System.out.println(annotation.columName());21 System.out.println(annotation.type());22 System.out.println(annotation.length());23
24 }25}26
27("student")28class Student{29 (columName = "db_id", type = "int", length = 10)30 private int id;31 (columName = "db_age", type = "int", length = 10)32 private int age;33 (columName = "db_name", type = "varchar", length = 32)34 private String name;35
36 public Student() {37 }38
39 public Student(int id, int age, String name) {40 this.id = id;41 this.age = age;42 this.name = name;43 }44
45 public int getAge() {46 return age;47 }48
49 public int getId() {50 return id;51 }52
53 public String getName() {54 return name;55 }56
57 public void setId(int id) {58 this.id = id;59 }60
61 public void setAge(int age) {62 this.age = age;63 }64
65 public void setName(String name) {66 this.name = name;67 }68}69
70/*类名的注解*/71(ElementType.TYPE)72(RetentionPolicy.RUNTIME)73@interface Table{74 String value();75}76
77/*属性的注解*/78(ElementType.FIELD)79(RetentionPolicy.RUNTIME)80@interface FieldDb{81 String columName();82 String type();83 int length();84}posted on 2021-12-02 17:48 Egoistic_Flowers 阅读(49) 评论(0) 收藏 举报
浙公网安备 33010602011771号