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 镇压警告,抑制编译时产生的警告信息
xxxxxxxxxx
251/*内置注解*/
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:表示子类可以继承父类的注解
xxxxxxxxxx
241/*测试元注解*/
2public class TestAnnotation02 {
3
4
5 public void test(){
6
7 }
8}
9
10/*定义一个注解*/
11//Target 表示注解可以用的位置
12value = ElementType.METHOD) (
13
14//Retention 表示注解在什么时候有效
15value = RetentionPolicy.RUNTIME) (
16
17//Documented 表示将注解生成在JAVAdoc中
18
19
20//Inherited 表示子类可以继承父类的注解
21
22@interface MyAnnotation{
23
24}
1.3 自定义注解
参数为value可以省略参数名
xxxxxxxxxx
421/*自定义注解*/
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 表示注解可以用的位置
17value = {ElementType.METHOD,ElementType.TYPE}) (
18
19//Retention 表示注解在什么时候有效
20value = RetentionPolicy.RUNTIME) (
21
22//Documented 表示将注解生成在JAVA doc中
23
24
25//Inherited 表示子类可以继承父类的注解
26
27@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
38value = {ElementType.METHOD,ElementType.TYPE}) (
39value = RetentionPolicy.RUNTIME) (
40@interface AnnotationTest02 {
41 String value();
42}
2 反射机制
动态语言&静态语言
动态语言:在运行时可以改变其结构的语言
- C#,JavaScript,PHP,Python
静态语言:运行时结构不能改变
- Java,c,c++
Java是准动态语言,可以通过反射机制实现动态语言的特性
2.1 获取反射对象
Reflection
- 反射机制允许程序在执行时,获取任何类的内部信息,并能直接操作任意内部属性及方法(动态的特性)
- 加载完类后,在堆方法区中就产生了Class类的对象,Class对象包含了所有类的结构信息
获取class对象:
定义需要获取反射对象的类:
xxxxxxxxxx
551/*实体类: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对象:
xxxxxxxxxx
371public 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对象
xxxxxxxxxx
91Class 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; //void
9Class c9 = Class.class; //Class
xxxxxxxxxx
91class java.lang.Object
2interface java.lang.Comparable
3class [Ljava.lang.String;
4class [[I
5class java.lang.Integer
6interface java.lang.Override
7class java.lang.annotation.ElementType
8void
9class java.lang.Class
2.2 类加载的内存分析
Java内存
堆区:
- new的对象,数组
- 可以被所有的线程共享
- 不会存放引用
栈区:
- 存放局部变量
- 引用对象的变量(引用在堆区的地址)
方法区:
- 包含所有的class
- 可以被所有的线程共享
- 特殊的堆区
类的加载过程
1.类的加载:将类的class文件读入内存,并为之创建一个Class对象,此过程由类加载器完成
2.类的链接:将类的二进制数据合并到JRE中
- 验证:确保类的信息符合JVM规范
- 准备:为static变量分配内存,并设置默认值,在方法区中
- 解析:将常量池的符号引用(常量名)替换为直接引用(地址)
3.类的初始化:JVM负责类初始化
- 执行类构造器方法,类构造器自动收集所有变量的赋值和静态代码块中的语句合并(不是对象构造器)
- 初始化一个类的时候,如果发现父类没有初始化,会先将父类进行初始化
- JVM保证每个类的类构造器方法在多线程环境正确加锁和同步
测试类的加载:
xxxxxxxxxx
181class 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一个类的对象
- 调用类的静态成员变量或静态方法
- 使用反射方式对类进行反射调用
- 初始化一个类会先初始化它的父类
类的被动引用(不发生类的初始化)
- 访问一个静态作用域,只有声明这个域的类会被初始化(子类用父类的静态方法,子类不会初始化)
- 通过数组定义引用,不会触发类初始化
- 引用常量不会触发类初始化(链接阶段已经进入常量池)
测试类的初始化:
xxxxxxxxxx
421/*测试类何时初始化*/
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包装入,最常用类加载器
xxxxxxxxxx
281public 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 获取运行时类的信息
xxxxxxxxxx
631/*获取类运行时结构*/
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 动态创建对象
xxxxxxxxxx
301/*动态创建对象*/
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 反射获取泛型
xxxxxxxxxx
491/*测试反射获取泛型*/
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/*类名的注解*/
71ElementType.TYPE) (
72RetentionPolicy.RUNTIME) (
73@interface Table{
74 String value();
75}
76
77/*属性的注解*/
78ElementType.FIELD) (
79RetentionPolicy.RUNTIME) (
80@interface FieldDb{
81 String columName();
82 String type();
83 int length();
84}
posted on 2021-12-02 17:48 Egoistic_Flowers 阅读(37) 评论(0) 编辑 收藏 举报