1、注解。注解分类、注解的好处; 2.、反射。反射机制、类加载、类的结构
1. 注解(Annotation) 1.1 注解的介绍 定义:Java 注解(Annotation)又称 Java 标注,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。
注解的分类:前三个为内置注解、中间四个为元注解、也可以自定义注解:
注解
解释
@Override
检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated
用来标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings
指示编译器去忽略注解中声明的警告。
@Retention
表示需要什么级别保存该注释信息,用于描述注解的生命周期。是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Target
用于描述注解的使用范围,类、方法
@Documented
标记这些注解是否包含在用户文档中。
@Inherited
说明子类可以继承父类中的注解
@interface MyAnnotation{...}
自定义注解,一般需要元注解来标注
1.2 内置注解 三个内置注解:
1 2 3 @Deprecated @Override @SuppressWarnings
SuppressWarnings的一些参数(有很多其实..)
all : 抑制所有警告
unchecked : 抑制未经检查的操作(比如强转)的警告
unused : 抑制未使用代码相关的警告
示例代码:
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 import java.util.ArrayList;import java.util.List;public class Test01 extends Object { @Override public String toString () { return super .toString(); } @Deprecated public static void test01 () { System.out.println("Deprecated" ); } @SuppressWarnings("all") public static void test02 () { List list = new ArrayList(); } public static void main (String[] args) { test01(); test02(); } }
1.3 元注解 说明:
@interface :使用 @interface 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation。定义 Annotation 时,@interface 是必须的。
@Documented : 如果使用 @Documented 修饰该 Annotation,则表示它可以出现在 javadoc 中。定义 Annotation 时,@Documented 可有可无;若没有定义,则 Annotation 不会出现在 javadoc 中。
**@Target(ElementType.TYPE)**:ElementType 是 Annotation 的类型属性。@Target(ElementType.TYPE) 的意思就是指定该 Annotation 的类型是 ElementType.TYPE。这就意味着,MyAnnotation1 是来修饰”类、接口(包括注释类型)或枚举声明”的注解。
**@Retention(RetentionPolicy.SOURCE)**:例@Retention(RetentionPolicy.RUNTIME) 的意思就是指定该 Annotation 的策略是 RetentionPolicy.RUNTIME。这就意味着,编译器会将该 Annotation 信息保留在 .class 文件中,并且能被虚拟机读取。
对Target和Retention参数的说明:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
指定 SuppressWarnings 的类型同时包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE。
TYPE 意味着,它能标注”类、接口(包括注释类型)或枚举声明”。
FIELD 意味着,它能标注”字段声明”。
METHOD 意味着,它能标注”方法”。
PARAMETER 意味着,它能标注”参数”。
CONSTRUCTOR 意味着,它能标注”构造方法”。
LOCAL_VARIABLE 意味着,它能标注”局部变量”。
@Retention(RetentionPolicy.RUNTIME)
RetentionPolicy.SOURCE //源码级别保留,编译后即丢弃。
RetentionPolicy.CLASS //编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值。
RetentionPolicy.RUNTIME // 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。(常用)
代码示意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.lang.annotation.*;@MyAnnotation public class Test02 { @MyAnnotation public static void test () { } public static void main (String[] args) { test(); } } @Inherited @Documented @Retention(value = RetentionPolicy.RUNTIME) @Target(value = {ElementType.METHOD,ElementType.TYPE}) @interface MyAnnotation{}
1.4 自定义注解 Annotation 通用定义格式
定义一个 Annotation,它的名字是 MyAnnotation1。定义了 MyAnnotation1 之后,我们可以在代码中通过 “@MyAnnotation1” 来使用它。
1 2 3 4 5 6 @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation1 { }
代码块中的内容
参数类型 参数名() 是否默认 默认值
1 2 3 4 5 String name () default "" ; int age () ; int id () default -1 ; String[] schools() default {"清华大学" ,"北京大学" };
示例代码
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 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=18) public static void test () { } @MyAnnotation3( "Java") public static void test2 () { } } @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation2{ String name () default "" ; int age () ; int id () default -1 ; String[] schools() default {"清华大学" ,"北京大学" }; } @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3{ String value () ; }
1.5注解的好处 1)编译检查 例如,@SuppressWarnings, @Deprecated 和 @Override 都具有编译检查作用。
(01) 关于 @SuppressWarnings 和 @Deprecated,已经在”第3部分”中详细介绍过了。这里就不再举例说明了。
(02) 若某个方法被 @Override 的标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被 @Override 标示,但父类中却没有”被 @Override 标注”的同名方法,则编译器会报错。示例如下:
2)在反射中使用 Annotation 在反射的 Class, Method, Field 等函数中,有许多于 Annotation 相关的接口。
这也意味着,我们可以在反射中解析并使用 Annotation。
3 ) 根据 Annotation 生成帮助文档 通过给 Annotation 注解加上 @Documented 标签,能使该 Annotation 标签出现在 javadoc 中。
4)能够帮忙查看查看代码 通过 @Override, @Deprecated 等,我们能很方便的了解程序的大致结构。
另外,我们也可以通过自定义 Annotation 来实现一些功能。
2. 反射(Reflection) 2.1 反射机制 动态语言和静态语言 1、动态语言是一类在运行时可以改变其结构的语言 :例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言: Object-C、 C#、 JavaScript、 PHP、 Python、 Erlang。这里比如一个javaScript程序:
1 2 3 4 function f ( ) { var x = "var a=3;var b=4;alert(a+b)" ; eval (x); }
2、静态语言与动态语言相对应的, 运行时结构不可变的语言就是静态语言。如Java、 C、C++。//Java不是动态语言, 但Java可以称之为“准动态语言” 。 即Java有一定的动态性, 我们可以利用反射机制、 字节码操作获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!
反射机制介绍
Reflection (反射)是Java被视为准动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类内部的信息,并能直接操作任意对象的内部属性及方法(包括private修饰的)
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
反射相关的主要API:
java.lang.Class: 代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:非标类的成员变量
java.lang.reflect.Constructor:代表类的构造器
示例代码:
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 package com.kuang.reflection;public class Test01 { public static void main (String[] args) throws ClassNotFoundException { 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" ); System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } } class user { private String name; private int id; private int age; public user () { } public user (String name, int id, int age) { this .name = name; this .id = id; this .age = age; } public String getName () { return name; } public void setName (String name) { 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; } @Override public String toString () { return "user{" + "name='" + name + '\'' + ", id=" + id + ", age=" + age + '}' ; } }
2.2 理解Class类并获取Class实例 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 package com.kuang.reflection;public class Test02 { public static void main (String[] args) throws ClassNotFoundException { Person person = new Student(); Person person1 = new Teacher(); System.out.println(person.name); Class c1 = person.getClass(); System.out.println(c1.hashCode()); Class c2 = Class.forName("com.kuang.reflection.Student" ); System.out.println(c2.hashCode()); Class c3 = Student.class; System.out.println(c3.hashCode()); Class c4 = Integer.TYPE; System.out.println(c4); Class c5 = c1.getSuperclass(); System.out.println(c5); } } class Person { public 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 = "学生" ; } } class Teacher extends Person { public Teacher () { this .name = "老师" ; } }
那些类型可以有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 package com.kuang.reflection;import java.lang.annotation.ElementType;public class Test03 { 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; Class c8 = void .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); int [] a = new int [10 ]; int [] b = new int [100 ]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode()); } }
2.3 类的加载与ClassLoader Java内存分析
堆:存放所有new出来的对象。可以被所有线程所共享
栈:存放基本类型的变量(包含这个基本类型的具体数值)、和对象的引用(存放引用在堆里面的具体地址)。栈是线程私有的,生命周期和线程相同。
方法区:存储已被虚拟机加载的类信息Class、常量、静态static变量、即时编译器编译后的代码等数据。被各个线程所共享
常量池:存放字符串常量和基本类型的常量
类加载过程
对类加载的理解:
示例代码
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 package com.kuang.reflection;public class Test04 { public static void main (String[] args) { A a = new A(); System.out.println(A.m); } } class A { static { System.out.println("A类静态代码块初始化" ); m = 300 ; } static int m = 100 ; public A () { System.out.println("A类的无参构造初始化" ); } }
类加载步骤解释
刚开始加载类时(类的数据、静态变量、静态方法、常量池、代码)
类加载完成立马产生一个Class对象(生成一个Java.lang.Class对象 代表 Test05这个类、生成一个Java.lang.Class对象 代表 A这个类),在加载的时候就形成了这两个对象,这两个Class对象就包含了这个类所有的东西
下面开始准备执行main()方法了,此时首先 m 默认为0(m = 0) (这里匹配链接阶段的准备阶段:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配 )链接阶段的 m为0(m = 0)
new A()在堆内存中,这个动作会产生一个A类新的对象(这个对象会去找它自己(A类)的那个Class类,无论创建多少个A类的对象,它的Class类只有一个 ),它会指向A类的Class,这时就能拿到A类的所有东西(它会去找A类的Class(在堆内存指向),因为 Class 拥有A类的所有数据,然后通过这些数据,就可以给A类显示赋值了,然后初始化,此时初始化时会执行一个()方法,它会把静态代码块的初始值合并了)
合并静态代码块(合并 m = 300 和 m = 100),这两句话相当于重新赋值给 m(第一次给m赋值为300第二次赋值为100,并把前面的值被覆盖了,于是上面的 A.m打印出来的为100 ,它是在初始化的时候执行的(把静态代码块合并起来),通过A类的具体对象给它赋值,赋值完通过 初始化,这次就有一个初始值,就可以打印出来了)
什么时候类会初始化
类的主动引用 :
当new一个son对象时是类的主动引用,会引发初始化。而当其直接父类没有被初始化时、会先初始化其父类再初始化自己。
当使用反射时,也会产生类的主动引用。它会把所有东西加载进来(Main类被加载、父类被加载、子类被加载 ),这样会极大的消耗资源。
类的被动动引用 :
new一个数组。只是开辟了一个空间,并给空间地址命名,不会被加载引发初始化(此时只有mian方法被加载)
通过调用常量的方式。所有的常量和类的静态变量都是在链接阶段就被赋了一个值,在链接阶段就做了,初始化的时候就已经存在了,所以不会引发子类的加载。
为什么会加载Main类呢?
因为当虚拟机启动,就会先初始化main方法所在的类,然后才执行 Son[] array = new Son[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 package com.kuang.reflection;public class Test05 { static { System.out.println("Main类被加载" ); } public static void main (String[] args) throws ClassNotFoundException { Son son = new Son(); } } class Father { static int b = 2 ; static { System.out.println("父类被加载" ); } } class Son extends Father { static { System.out.println("子类被加载" ); } static int m = 100 ; static final int M = 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 public class Test06 { 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.kuang.reflection.Test06" ).getClassLoader(); System.out.println(classLoader); ClassLoader classLoader1 = Class.forName("java.lang.Object" ).getClassLoader(); System.out.println(classLoader1); System.out.println(System.getProperty("java.class.path" )); } }
2.4运行时类的结构 获取运行时类的完整结构
Field 获得属性(成员变量)
Method 获得方法(成员方法)
Constructor 获得构造方法
示例代码
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 package com.kuang.reflection;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class Test07 { public static void main (String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException { Class c1 = Class.forName("com.kuang.reflection.user" ); System.out.println(c1.getName()); System.out.println(c1.getSimpleName()); System.out.println("--------------" ); Field[] fields = c1.getDeclaredFields(); for (Field field: fields){ System.out.println(field); } Field name = c1.getDeclaredField("name" ); System.out.println(name); System.out.println("--------------" ); Method[] methods = c1.getMethods(); for (Method method: methods){ System.out.println("公共的" +method); } Method[] declaredMethods = c1.getDeclaredMethods(); for (Method declaredMethod: declaredMethods){ System.out.println("本类所有方法" +declaredMethod); } 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 i:constructors){ System.out.println("公共的" +i); } Constructor[] declaredConstructors = c1.getDeclaredConstructors(); for (Constructor i:declaredConstructors){ System.out.println("全部" +i); } } }
有了Class对象,能做什么?
可以创建类的对象,通过无参构造器或者有参构造器两种newInstance()
可以调用执行指定的方法,通过invoke()
方法执行
还可以访问私有方法、私有变量,需要在执行前设置setAccessible(true)
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 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 Exception { Class c1 = Class.forName("com.kuang.reflection.User" ); Constructor constructor = c1.getDeclaredConstructor(String.class, int .class, int .class); User user1 = (User)constructor.newInstance("青梅" ,001 ,18 ); System.out.println(user1); User user2 = (User)c1.newInstance(); Method setName = c1.getDeclaredMethod("setName" , String.class); setName.invoke(user2,"煮酒" ); System.out.println(user2.getName()); User user3 = (User)c1.newInstance(); Method methodNow = c1.getDeclaredMethod("methodPri" ,null ); methodNow.setAccessible(true ); methodNow.invoke(user3,null ); User user4 = (User)c1.newInstance(); Field f = c1.getDeclaredField("name" ); f.setAccessible(true ); f.set(user4,"青梅2" ); System.out.println(user4.getName()); } }
性能比较(new和反射) 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;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Test09 { public static void main (String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test(); test2(); test3(); test4(); } public static void test () { User user = new User(); long start = System.currentTimeMillis(); for (int i = 0 ; i < 1000000000 ; i++) { user.getName(); } long end = System.currentTimeMillis(); System.out.println("普通方式10亿次:" + (end-start) + " ms" ); } public static void test2 () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName" , null ); long start = System.currentTimeMillis(); for (int i = 0 ; i < 1000000000 ; i++) { getName.invoke(user,null ); } long end = System.currentTimeMillis(); System.out.println("反射方式10亿次:" + (end-start) + " ms" ); } public static void test3 () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName" , null ); getName.setAccessible(true ); long start = System.currentTimeMillis(); for (int i = 0 ; i < 1000000000 ; i++) { getName.invoke(user,null ); } long end = System.currentTimeMillis(); System.out.println("关闭检测后反射方式10亿次:" + (end-start) + "ms" ); } public static void test4 () { User user1 = new User(); Class c1 = user1.getClass(); long start = System.currentTimeMillis(); for (int i = 0 ; i < 1000000000 ; i++) { c1.getName(); } long end = System.currentTimeMillis(); System.out.println("反射方式直接调用10亿次:" + (end-start) + " ms" ); } }
获取泛型信息 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 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 Test10 { public static void test01 (Map<String,User> map, List<User> list) { System.out.println("test01" ); } public static Map<String,User> test02 () { System.out.println("test01" ); return null ; } public static void main (String[] args) throws NoSuchMethodException { Method method = Test10.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); } } } System.out.println("=================" ); Method method2 = Test10.class.getMethod("test02" , null ); Type genericReturnType = method2.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType)genericReturnType ).getActualTypeArguments(); for (Type actualTypeArgument:actualTypeArguments){ System.out.println(actualTypeArgument); } } } }
获取注解信息(重要) 利用注解和反射完成类和表结构的映射关系
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 package com.kuang.reflection;import java.lang.annotation.*;import java.lang.reflect.Field;public class Test11 { 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); } TableStudent tableStudent = (TableStudent) c1.getAnnotation(TableStudent.class); String value = tableStudent.value(); System.out.println(value); System.out.println("----------------" ); Field f1 = c1.getDeclaredField("id" ); FieldStudent annotation1 = f1.getAnnotation(FieldStudent.class); System.out.println(annotation1.columnName()); System.out.println(annotation1.type()); System.out.println(annotation1.length()); System.out.println("----------------" ); Field f2 = c1.getDeclaredField("age" ); FieldStudent annotation2 = f2.getAnnotation(FieldStudent.class); System.out.println(annotation2.columnName()); System.out.println(annotation2.type()); System.out.println(annotation2.length()); System.out.println("----------------" ); Field f3 = c1.getDeclaredField("name" ); FieldStudent annotation3 = f3.getAnnotation(FieldStudent.class); System.out.println(annotation3.columnName()); System.out.println(annotation3.type()); System.out.println(annotation3.length()); } } @TableStudent("db_student") class Student2 { @FieldStudent(columnName = "db_id",type = "int",length = 10) private int id; @FieldStudent(columnName = "db_age",type = "int",length = 10) private int age; @FieldStudent(columnName = "db_name",type = "varchar",length = 3) private String 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 TableStudent{ String value () ; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldStudent{ String columnName () ; String type () ; int length () ; }