Annotation#
- 作用:
- 不是程序本身,可以对程序做出解释
- 可以被其他程序(比如:编译器等)读取
- 格式:
- 注解是以“@注释名”在代码中国存在的,可以添加一些参数值
- 可以附加在 package、class、method、field 等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
内置注解#
- @Override:定义在java.lang.Override 中,只适用于修饰方法,表示重写方法
- @Deprecated: 定义在 java.lang.Deprecated 中 ,可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素
- @SuppressWarnings: 定义在java.labg.SuppressWarnings 中,用来抑制编译时的警告信息,但该注释需要添加参数
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
| package com.kuang.annotation;
import java.util.ArrayList;
import java.util.List;
//什么是注解
public class Test01 extends Object {
//@Override 重写的注解
@Override
public String toString() {
return super.toString();
}
//@Deprecated 不推荐程序员使用,但可以使用,或者存在更好的方式
@Deprecated
public static void test() {
System.out.println("Deprecated");
}
//镇压警告
@SuppressWarnings("all")
public void test02() {
List list = new ArrayList();
}
public static void main(String[] args) {
test();
}
}
|
元注解#
作用:负责注解其他注解的注解
@Target:用于描述注解的使用范围
- ElementType可取值:TYPE、FIELD、METHOD、PARAMETER等
@Retention:表示需要在什么级别保存该注释信息,表示注解的生命周期
- RetentionPolicy可取值:(runtime>class>sources)
- SOURCE:在原文件中有效,被编译器丢弃。
- CLASS:在class文件有效,可能会被虚拟机忽略。
- RUNTIME: 在运行时有效。
@Documented:说明该注解将被包含在 javadoc 中
@Inherited:说明子类可以继承父类中的该注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| package com.kuang.annotation;
import java.lang.annotation.*;
//测试元注解
public class Test02 {
@MyAnnotation
public void tets(){}
}
//@Target 用于描述注解的使用范围。value 可以省略
//@Target({ElementType.METHOD,ElementType.TYPE})
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//@Retention 表示我们的注解在什么地方还有效
//runtime>class>sources
@Retention(RetentionPolicy.RUNTIME)
//@Documented 表示是否将我们的注解生成在 JAVAdoc 中
@Documented
//@Inherited 子类可以继承父类的注解
@Inherited
//定义一个注解
@interface MyAnnotation {}
|
自定义注解#
使用 @interface 自定义注解,自动继承了 java.lang.annotation.Annotation 接口
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
| package com.kuang.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
public class Test03 {
//显式赋值,无默认值时必须给注解赋值
@MyAnnotation2(age=12)
public void tets(){}
//可以不写参数名,但 value 必须有值
@MyAnnotation3("qwe")
public void tets2(){}
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {
//注解的参数:参数类型 + 参数名();
String name() default "";
int age();
//如果默认值为-1,代表不存在
int id() default -1;
String[] schools() default {"blbl"};
}
//只有一个参数时,参数名为 value
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3 {
String value();
}
|
静态语言 &动态语言#
动态语言:运行时可以改变其结构的语言。例:Object-C、C#、JavaScript、PHP、Python
静态语言:运行时结构不可变的语言。例:Java、C、C++

Java 不是动态语言,但 Java 可以称之为“准动态语言”,即 Java 有一定的动态性,我们可以利用反射机制获得类似动态语言的特性
Java Reflection#
- Reflection(反射)是 Java 被视为动态语言的关键,反射机制允许程序在执行期间借助 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个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
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
| package com.kuang.reflection;
//什么是反射
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获得类的 class 对象
Class c1 = Class.forName("com.kuang.reflection.User");
System.out.println(c1);
Class c2 = Class.forName("com.kuang.reflection.User");
Class c3 = Class.forName("com.kuang.reflection.User");
Class c4 = Class.forName("com.kuang.reflection.User");
//一个类在内存中只有一个 Class 对象
//一个类被加载后,类的整个结构都会被封装在 Class 对象中
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类:pojo,entity
class User{
private String name;
private int age;
private int id;
public User() {}
public User(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
|
得到 Class 类的方式#
Class 类#
在Object 类中定义了以下方法,此方法将被所有子类继承
1
| public final Class getClass()
|
这个方法的返回值类型是一个 Class 类,Class 类是 Java 反射的源头

Class 类的常用方法:#

获取 Class 类的方式#
1
| Class clazz = Person.class;
|
- 已知某个类的实例,调用该实例的 getClass() 方法获取 Class 对象
1
| Class clazz = person.getClass();
|
- 已知一个类的全类名,且该类在类路径下,可通过 Class 类的静态方法 forName() 获取,可能抛出 ClassNotFoundException
1
| Class clazz = Class.forName("demo01.Student");
|
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
| package com.kuang.reflection;
//测试 class 类的创建方式有哪些
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//方式二:foename 获得
Class c2 = Class.forName("com.kuang.reflection.Student");
System.out.println(c2.hashCode());
//方式三:通过类名 .class 获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本内置类型的包装类都有一个 Type 属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//获得父类类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
class Person {
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person {
public Student() {
this.name = "student";
}
}
class Teacher extends Person {
public Teacher() {
this.name = "Teacher";
}
}
|
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| package com.kuang.reflection;
import java.lang.annotation.ElementType;
//所有类型的 Class
public class Test04 {
public static void main(String[] args) {
//类
Class c1 = Object.class;
//接口
Class c2 = Comparable.class;
//一维数组
Class c3 = String[].class;
//二维数组
Class c4 = int[][].class;
//注解
Class c5 = Override.class;
//枚举
Class c6 = ElementType.class;
//基本数据类型
Class c7 = Integer.class;
//void
Class c8 = void.class;
//Class
Class c9 = 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);
//只要元素类型与维度一样,就是同一个 Class
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
}
|

Java 内存分析#

类加载过程:#
参考:https://javaguide.cn/java/jvm/class-loading-process.html


- **加载:**将类的 class 文件字节码加载到内存,并将静态数据转化为方法区的运行时数据结构,然后生成一个 java.lang.Class 对象
- **链接:**将java类二进制数据合并到 JRE中
- **验证:**确保加载的类信息符合JVM规范,没有安全方面的问题
- **准备:**正式为类变量 (static) 分配内存并设置类变量默认初始值的阶段(所以说static在初始化之前就已经有了一个值),这些内存都将在方法区中进行分配
- 解析:虚拟机将常量池内的符号引用替换为直接引用的过程
- 初始化:执行初始化方法
<font style="color:rgb(60, 60, 67);"><clinit> ()</font>方法的过程,是类加载的最后一步,这一步 JVM 才开始真正执行类中定义的 Java 程序代码(字节码)。<font style="color:rgb(60, 60, 67);"><clinit> ()</font>方法会将该类的静态变量合并。
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
| package com.kuang.reflection;
public class Test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
/*
1、加载到内存,会在堆产生一个类对应的 Class 对象
2、链接,链接结束后 m=0
3、初始化
<clinit>(){
System.out.println("A类静态代码块初始化");
m = 300;
m = 100;
}
m = 100
*/
}
}
class A{
static {
System.out.println("A类静态代码块初始化");
m = 300;
}
static int m = 100;
public A() {
System.out.println("A类的无参构造初始化");
}
}
|
类加载器:#

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
| ppackage com.kuang.reflection;
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类的加载器
ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
//获取系统类的加载器的父类加载器->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);
//获取扩展类加载器的父类加载器-->根加载器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
//测试当前类是哪个类加载器加载的
ClassLoader classLoader = Class.forName("com.kuang.reflection.Test07").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"));
/*
D:\Java\jdk1.8\jre\lib\charsets.jar;
D:\Java\jdk1.8\jre\lib\deploy.jar;
D:\Java\jdk1.8\jre\lib\ext\access-bridge-64.jar;
D:\Java\jdk1.8\jre\lib\ext\cldrdata.jar;
D:\Java\jdk1.8\jre\lib\ext\dnsns.jar;
D:\Java\jdk1.8\jre\lib\ext\jaccess.jar;
D:\Java\jdk1.8\jre\lib\ext\jfxrt.jar;
D:\Java\jdk1.8\jre\lib\ext\localedata.jar;
D:\Java\jdk1.8\jre\lib\ext\nashorn.jar;
D:\Java\jdk1.8\jre\lib\ext\sunec.jar;
D:\Java\jdk1.8\jre\lib\ext\sunjce_provider.jar;
D:\Java\jdk1.8\jre\lib\ext\sunmscapi.jar;
D:\Java\jdk1.8\jre\lib\ext\sunpkcs11.jar;
D:\Java\jdk1.8\jre\lib\ext\zipfs.jar;
D:\Java\jdk1.8\jre\lib\javaws.jar;
D:\Java\jdk1.8\jre\lib\jce.jar;
D:\Java\jdk1.8\jre\lib\jfr.jar;
D:\Java\jdk1.8\jre\lib\jfxswt.jar;
D:\Java\jdk1.8\jre\lib\jsse.jar;
D:\Java\jdk1.8\jre\lib\management-agent.jar;
D:\Java\jdk1.8\jre\lib\plugin.jar;
D:\Java\jdk1.8\jre\lib\resources.jar;
D:\Java\jdk1.8\jre\lib\rt.jar;
D:\JavaCode\study_code\annotation&reflection\annotation\target\classes;
C:\Users\SZZY\AppData\Local\Programs\IntelliJ IDEA Ultimate\lib\idea_rt.jar
*/
}
}
|

双亲委派机制#
参考:https://javaguide.cn/java/jvm/classloader.html#%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%A8%A1%E5%9E%8B
https://www.cnblogs.com/luckforefforts/p/13642685.html
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载器都是如此,因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载。
获取运行时类的完整结构:#
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
| package com.kuang.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获得类的信息
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.kuang.reflection.User");
//获得包名 + 类名:com.kuang.reflection.User
System.out.println(c1.getName());
//获得类名:User
System.out.println(c1.getSimpleName());
System.out.println("================");
//获得类的属性
//getFields 只能找到 public 属性
Field[] fields = c1.getFields();
//getDeclaredFields 找到全部属性
fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("================");
//获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("================");
//获得类的方法
//获得本类及父类的 public 方法
Method[] methods = c1.getMethods();
for(Method method: methods){
System.out.println("正常的:"+method);
}
//获得本类的全部方法
methods=c1.getDeclaredMethods();
for(Method m: methods){
System.out.println("getDeclaredMethods:"+m);
}
//获得指定方法
//重载
Method getName = c1.getMethod("getName", null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
System.out.println("================");
//获得指定的构造器
Constructor[] constructors = c1.getConstructors();
for(Constructor constructor: constructors){
System.out.println(constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for(Constructor constructor: declaredConstructors){
System.out.println("全部:"+constructor);
}
//获得指定构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println("指定:"+declaredConstructor);
}
}
|
获取类的名称:
- clazz.getName(); //类的全限定名
- clazz.getSimpleName(); //简单类名
- clazz.getPackage(); // 包信息
- clazz.getModifiers(); // 修饰符
获得类的属性:
- getFields() :获得 public 属性
- getDeclaredFields() : 获得全部属性
- getDeclaredField(String name) :获得指定属性的值
获得类的方法:
- getMethods():获取本类及父类的所有public方法
- getDeclaredMethods(): 获取本类的所有方法
- getMethod(String name, Class… parameterTypes): 获取本类及父类的指定public方法
- getDeclaredMethod(String name, Class… parameterTypes) :获取本类的所有方法
获得构造器
- getConstructors():获得所有 public 构造器
- getDeclaredConstructors():获得所有构造器
- getConstructor():获取本类及父类的指定public构造器
- getDeclaredConstructor(Class… parameterTypes):获取本类的所有构造器
**Class<?>... parameterTypes** = 方法参数的类型列表 ,它的值根据他前面的参数所需的类型确定。
通过反射动态创建对象#
- 通过无参构造器创建对象 Class.newInstance()
- 使用 Class 对象的 newInstance() 方法调用类(该类必须有一个无参构造器且访问权限足够)的无参构造器
- Class.newInstance() Java 9 起已过时, 推荐改用
getDeclaredConstructor().newInstance() - newInstance() 返回值为 Object,需要强转类型为 User
1
2
3
4
5
6
7
| //通过反射获得 Class 对象
Class c1 = Class.forName("com.kuang.reflection.User");
//通过无参构造器创建对象
//本质是 newInstance() 调用了类的无参构造器:public User() {}
User user = (User) c1.newInstance();
System.out.println(user);
|

- 通过有参构造器创建对象
1
2
3
4
5
6
| //通过有参构造器创建对象
//获取指定参数类型的构造器
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
//调用构造器创建对象
User user2 = (User)constructor.newInstance("qwe", 1, 2);
System.out.println(user2);
|

- 通过反射调用普通方法
1
2
3
4
5
6
7
| //通过反射调用普通方法
User user3 = (User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke(对象, "方法的值") : 激活(对象, "方法的值")
setName.invoke(user3, "name1");
System.out.println(user3.getName());
|

那么在第一步已经用 (User) 强转了 user ,user 变量的真实类型便是 User,在之后的调用应属于正常的 Java 方法调用,不需要反射也可以直接调用:

而通过反射调用方法也有好处:
- 可使用 setAccessible(true); 调用 private 私有方法
- 动态调整调用的方法
- 通过反射操作属性
1
2
3
4
5
6
7
| //通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//通过 setAccessible(true) 关闭程序安全检测,可访问私有属性
name.setAccessible(true);
name.set(user4, "name2");
System.out.println(user4.getName());
|

性能对比:#
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
| package com.kuang.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析性能
public class Test10 {
//普通调用
public static void test01() {
User user = new User();
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次"+(endTime - starTime)+"ms");
}
//反射调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次"+(endTime - starTime)+"ms");
}
//反射调用 关闭检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long starTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式(关闭检测)执行10亿次"+(endTime - starTime)+"ms");
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
test01();
test02();
test03();
}
}
|

反射操作泛型#
泛型(Generics)就是 参数化类型 —— 把数据类型当作参数传递。
它让类、接口、方法能在 编写时不指定具体类型,而是在 使用时再确定类型。
- 类型安全:编译时就能发现类型错误。
- 避免强制类型转换:减少
ClassCastException。 - 提高代码复用性:写一次逻辑,支持多种数据类型。
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
| package com.kuang.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通过反射获得泛型
public class Test11 {
//参数类型为泛型:<String,User>,<User>
public void test01(Map<String,User> map, List<User> list) {
System.out.println("test01");
}
//返回值为泛型:Map<String,User>
public Map<String,User> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//通过反射获取 test01 方法对象
Method method = Test11.class.getMethod("test01", Map.class, List.class);
//获取该方法的所有参数的泛型类型,返回 Type[] 数组
Type[] genericParameterTypes = method.getGenericParameterTypes();
//遍历参数类型
for (Type genericParameterType : genericParameterTypes) {
System.out.println("!"+genericParameterType);
//判断参数类型是否为泛型
if (genericParameterType instanceof ParameterizedType) {
//如果是,强转为 ParameterizedType(参数化类型),调用 getActualTypeArguments() 获取泛型里的真实类型:对 Map<String,User> 来说,结果是 [String, User];对 List<User> 来说,结果是 [User]。
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("#"+actualTypeArgument);
}
}
}
//获取 test02 方法对象
method = Test11.class.getMethod("test02", null);
//获取 test02 方法的返回类型,结果是 Map<String, User>
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("&"+actualTypeArgument);
}
}
}
}
|

反射操作注解#
ORM (Object relationship Mapping) 对象关系映射

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
| package com.kuang.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//练习反射操作注解
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.kuang.reflection.Student2");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的 value 值
Table table = (Table) c1.getAnnotation(Table.class);
String value = table.value();
System.out.println(value);
//获得类指定的注解
Field field = c1.getDeclaredField("name");
Filed annotation = field.getAnnotation(Filed.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Table("db_student")
class Student2 {
@Filed(columnName = "db_id", type = "int", length = 10)
private int id;
@Filed(columnName = "db_age", type = "int", length = 10)
private int age;
@Filed(columnName = "db_name", type = "varchar", length = 3)
private String name;
public Student2() {}
public Student2(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Filed{
String columnName();
String type();
int length();
}
|