Java-基础-注解和反射

注解和反射

1. 注解

1.1 注解的简介

1.2 常见内置注解

1.3 元注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.zhuuu.Annotation;

import java.lang.annotation.*;

//测试元注解

public class MetaAnnotation {
@MyAnnotaion

}

//定义一个注解
//定义在类上和方法上
//@Target:表示可以注解可以放在哪些上
//@Retention:表示我们的注解在什么时候有效 (runtime>class>source)
//@Documented:表示是否把注解声称在Javadoc中
//@Inherited :表示时候继承父类的注解

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotaion{

}

1.4 自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MetaAnnotation {
//注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
@MyAnnotaion(name = "Zhuuu",schools = "Njput")
public void test(){

}
}

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotaion{
//注解的参数:参数类型 + 参数名()+ 【default 值】;
String name() default "";
int age() default 0;
int id() default -1; //如果默认值为-1,代表不存在

String[] schools(); // 定义了一个数组
}



//默认值是value,可以不用显示传参数
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@interface Myannation3{
String value();
}

2. 反射

2.1 静态语言和动态语言

2.2 反射概述

通过反射来获得类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Reflection {
//通过反射获取类的class对象
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("com.zhuuu.Reflection.User");
System.out.println(c1);


//一个类在内存中只有一个class对象
//一个类被加载后,类的整个结构都会被封装在class对象中
}
}


//实体类:
class User{
private int age;
private String name;
private String Address;
}

2.3 Class类

Class类的常用方法

image-20200311175515307

2.4 所有类型的Class对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Reflection02 {
public static void main(String[] args) {
Class<Object> c1 = Object.class; //类
Class<Comparable> c2 = Comparable.class; //接口
Class<String[]> c3 = String[].class; //一维数组
Class<String> c4 = String.class; //类
Class<int[][]> c5 = int[][].class; //二维数组
Class<Override> c6 = Override.class; //注解
Class<ElementType>c7 = ElementType.class; //枚举
Class<Integer> c8 = Integer.class; //基本数据类型
Class<Void> c9 = void.class; //void
Class<Class> c10 = 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 );
System.out.println(c10);
}
}

只要元素类型和维度一样,就是同一个class

3. 类加载

  1. 加载
  2. 链接
  3. 初始化(cinit<>{})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.zhuuu.ClassLoader;

public class TestClassLoader {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
}
}


/*
* 1. 加载到内存,会在堆中产生一个对应的Class对象
* 2. 链接,链接结束后m=0
* 3. 初始化<cinit>(){
* System.out.println("A类静态代码块初始化");
m = 300;
int m = 100;
}*/


class A{
static {
System.out.println("A类静态代码块初始化");
m = 300;
}

static int m = 100;


public A() {
System.out.println("A类的无参构造初始化");
}
}

3.1 类的初始化时机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.zhuuu.ClassLoader;

public class TestWhenClassLoader {
static {
System.out.println("main类被加载");
}


public static void main(String[] args) throws ClassNotFoundException {
// //1.主动引用会产生类的初始化
// Son son = new Son();

// //2.反射也会产生主动引用
// Class.forName("com.zhuuu.ClassLoader.Son");

//不会产生类的引用的方法
// System.out.println(Son.b); //并不会加载子类
// Son[] array = new Son[5]; //数组也不会引起类初始化
System.out.println(Son.M); //常量也不会引起父类和子类的初始化

}
}

class Father {

static int b = 2;

static {
System.out.println("父类被加载");
}
}


class Son extends Father {
static {
System.out.println("子类被加载");
m = 300;
}

static int m = 100;

static final int M = 1;
}

3.2 类加载器作用

  • 类加载的作用
    • class文件字节码内容加载到内存中,并将这些静态数据转换成方法区运行时数据结构,然后在队中生成一个代表这个类的java,lang,Class对象,作为方法去中类数据的访问入口。
    • 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到其中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。

3.3 类加载器的分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class TestGetClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);


//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);


//获取扩展类加载器的父类加载器-->(根加载器)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);

//获取当前类加载器
ClassLoader classLoader = Class.forName("com.zhuuu.ClassLoader.TestGetClassLoader").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"));
}
}

输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@4554617c
null
sun.misc.Launcher$AppClassLoader@18b4aac2
null
E:\jdk1.8\jre\lib\charsets.jar;
E:\jdk1.8\jre\lib\deploy.jar;E:\jdk1.8\jre\lib\ext\access-bridge-64.jar;
E:\jdk1.8\jre\lib\ext\cldrdata.jar;
E:\jdk1.8\jre\lib\ext\dnsns.jar;
E:\jdk1.8\jre\lib\ext\jaccess.jar;
E:\jdk1.8\jre\lib\ext\jfxrt.jar;
E:\jdk1.8\jre\lib\ext\localedata.jar;
E:\jdk1.8\jre\lib\ext\nashorn.jar;
E:\jdk1.8\jre\lib\ext\sunec.jar;
E:\jdk1.8\jre\lib\ext\sunjce_provider.jar;
E:\jdk1.8\jre\lib\ext\sunmscapi.jar;
E:\jdk1.8\jre\lib\ext\sunpkcs11.jar;
E:\jdk1.8\jre\lib\ext\zipfs.jar;
E:\jdk1.8\jre\lib\javaws.jar;
E:\jdk1.8\jre\lib\jce.jar;
E:\jdk1.8\jre\lib\jfr.jar;
E:\jdk1.8\jre\lib\jfxswt.jar;
E:\jdk1.8\jre\lib\jsse.jar;
E:\jdk1.8\jre\lib\managementagent.jar;
E:\jdk1.8\jre\lib\plugin.jar;
E:\jdk1.8\jre\lib\resources.jar;
E:\jdk1.8\jre\lib\rt.jar;
E:\学习源码\AnnotationReflection\target\classes;
E:\IntelliJ IDEA 2019.1\lib\idea_rt.jar

3.4 双亲委派机制

  • 保证安全性
  • 一步一步向上委托加载
  • (具体内容见JVM笔记)

3.5 获取类的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class TestClassInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class<?> c1 = Class.forName("com.zhuuu.Reflection.User");

//获得类的名字
System.out.println(c1.getName()); // 获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名


//获得类的属性
Field[] fields = c1.getFields(); //只能找到public属性
System.out.println("==================");
fields = c1.getDeclaredFields(); //找到全部的属性
for (Field field : fields) {
System.out.println(field);
}

Field name = c1.getDeclaredField(("name")); //获取指定的属性
System.out.println(name);

//获得类的方法
Method[] methods = c1.getMethods(); //获取得本类及父类的所有方法
for (Method method : methods) {
System.out.println("正常的:"+method);
}

methods = c1.getDeclaredMethods(); //只能获取本类的方法
for (Method method : methods) {
System.out.println("getDeclaredMethods" + method);
}

Method getName = c1.getMethod("getName",null); //获得指定的方法
Method setName = c1.getMethod("setName", String.class); //参数的作用是因为有方法的重载
System.out.println(getName);
System.out.println(setName);

//获得类的构造器
Constructor<?>[] constructors = c1.getConstructors(); //获取public构造器
for (Constructor<?> constructor : constructors) {
System.out.println("正常的"+constructor);
}
constructors = c1.getDeclaredConstructors(); //获取全部的构造器
for (Constructor<?> constructor : constructors) {
System.out.println("#" + constructor);
}


Constructor<?> declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, String.class); //获得指定的构造器
System.out.println("指定构造器"+declaredConstructor);
}
}

4. 反射高级操作

4.1 调用指定的方法

invoke方法

setAccessible方法

4.2 动态的创建对象

反射创建对象的方法:newInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//动态的创建对象,通过反射
public class Reflection03 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得class对象
Class<?> c1 = Class.forName("com.zhuuu.Reflection.User");

//构造一个对象
// User user = (User) c1.newInstance(); //本质上是调用了无参构造器
// System.out.println(user);

//通过构造器创建对象
// Constructor<?> constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
// User user1 = (User) constructor.newInstance("zhuuu", 001, 19);
// System.out.println(user1);


//通过反射调用方法
// User user2 = (User) c1.newInstance();
// //通过反射获取一个方法
// Method setName = c1.getDeclaredMethod("setName", String.class);
// setName.invoke(user2,"朱酱酱"); //invoke(对象,"方法的值")
// System.out.println(user2.getName());


//通过反射操作属性
User user3 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");

name.setAccessible(true); //private权限报错,不能直接操作私有属性,关掉权限检查
name.set(user3,"朱酱酱2");
System.out.println(user3.getName());

}
}

4.3 反射性能分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//分析性能问题
public class Reflection04 {

//普通方式调用
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("普通方式执行10亿次时间" + (endTime-startTime)+"ms");
}


//反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<? extends User> c1 = user.getClass();

//通过反射操作
Method getName = c1.getMethod("getName", null);

long startTime = System.currentTimeMillis();

for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);

}

long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次时间" + (endTime-startTime)+"ms");

}


//反射调用(关闭权限检测)
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<? extends User> c1 = user.getClass();

//通过反射操作
Method getName = c1.getMethod("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("关闭检测执行10亿次时间" + (endTime-startTime)+"ms");

}

//主方法调用
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}

}

输出结果如下:

4.4 反射操作泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//通过反射获取泛型
public class Reflection05 {

public void test01(Map<String,User> map, List<User> list){

}


public Map<String,User> test02(){
System.out.println("test02");
return null;
}

public static void main(String[] args) throws NoSuchMethodException {
//test01
Method method = Reflection05.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);
}
}
}


//test 02
method = Reflection05.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);
}
}
}

}

4.5 反射操作注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//反射操作注解
import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Reflection06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class<?> c1 = Class.forName("com.zhuuu.Reflection.Reflection06.Student2");


//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation); //@table("db_student")
}

//获得注解value的值
table annotation = c1.getAnnotation(table.class);
String value = annotation.value(); //"db_student"
System.out.println(value);

//获得类指定的注解
Field name = c1.getField("name");
field annotation1 = name.getAnnotation(field.class);
System.out.println(annotation1.columnNName()); //"db_name"
System.out.println(annotation1.length()); //"varchar"
System.out.println(annotation1.type()); //3
}
}



@table("db_student")
class Student2{

@field(columnNName = "db_id",type = "int",length = 10)
private int id;
@field(columnNName = "db_age",type = "int",length = 10)
private int age;
@field(columnNName = "db_name",type = "varchar",length = 3)
private String name;

@Override
public String toString() {
return "Studeng2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}

public Student2() {
}

public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
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;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}



//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface table{
String value();
}


//属性的注解
@Target(ElementType.FIELD)
@interface field{
String columnNName();
String type();
int length();
}

5. 总结

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信