1、什么是注解
Java.annotation
所有框架的实现底层就是注解和反射
-
java5.0开始引入的新技术
-
annotation的作用
-
Annotation的格式
- 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:
@SuppressWarmings(values=“unchecked”)
- 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:
-
Annotation在哪里使用
- 可以在package,class,method,filed等上面,相当于给他们添加额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问
//什么是注解
public class WhatIsAnnotation {
//重写的注解
@Override
public String toString() {
return super.toString();
}
}
2、有哪些内置注解
-
@override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
-
@Deprecated:定义在java.lang.Deprecated中,此注解可以用于修饰方法、属性、类、表示不鼓励程序员使用的元素,通常是存在危险或者存在更好的选择
//不推荐使用的注解 @Deprecated public static void test01(){ } public static void main(String[] args) { test01(); }
-
@SuppressWarnings:定义在java.lang.SuppressWanings,镇压编译时的警告信息
- 这个注解需要传入一个参数才能正常使用,都是已经定义好了的
- all、unchecked、deprecation
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** * The set of warnings that are to be suppressed by the compiler in the * annotated element. * Duplicate names are permitted. The second and * successive occurrences of a name are ignored. The presence of * unrecognized warning names is <i>not</i> an error: Compilers must * ignore any warning names they do not recognize. They are, however, * free to emit a warning if an annotation contains an unrecognized * warning name. * * <p> The string {@code "unchecked"} is used to suppress * unchecked warnings. Compiler vendors should document the * additional warning names they support in conjunction with this * annotation type. They are encouraged to cooperate to ensure * that the same names work across multiple compilers. * @return the set of warnings to be suppressed */ String[] value();//这个是属性方法,类似于属性,所以需要传参数在使用的时候,不同于方法 }
//什么是注解 //镇压警告,作用于类 @SuppressWarnings("all") public class WhatIsAnnotation { //重写的注解 @Override public String toString() { return super.toString(); } //不推荐使用的注解 @Deprecated public static void test01(){ } //镇压警告,作用于方法 @SuppressWarnings("all") public static void test02(String[] args) { List list=new ArrayList(); } public static void main(String[] args) { test01(); } }
- 这个注解需要传入一个参数才能正常使用,都是已经定义好了的
3、元注解
指的是用来注解注解的注解,最基本的注解
只有四种:@Target、@Retention、@Documented、@Inherited
//元注解
//表示作用在什么上面,方法、类、属性。。。
@Target({ElementType.FIELD,ElementType.CONSTRUCTOR,ElementType.METHOD})
//表示注解在什么时候还有效 Runtime>class>sources
@Retention(RetentionPolicy.RUNTIME)
//表示是否将注解生成在doc文档中
@Documented
//表示子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
4、自定义注解
使用**@interface**自定义注解,自动继承了java.lang.annotation.Annotation接口
注意
-
@interface用来声明一个注解
public @interface AnnotationName { //content }
-
每一个方法实际上都声明了一个配置参数
-
方法的名称就是参数的名称
-
返回值类型就是参数的类型(只限于:Class、String、Enum三种类型)
-
可以通过default来设置默认值
-
如果只有一个参数成员,一般参数名为value
-
注解元素必须要有值,一般在定义时使用0或者“”来作为默认值
@Annotation01(age=21)
@Annotation02("hello")//如果属性名是value可以直接省略,不然就不行
@Annotation03(name="world")
public class AnnotationTest01 {
}
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation01{
//注解的参数: 参数类型 + 参数名 ();
String name() default "";
int age();
int id() default -1;//默认值为-1代表不存在
String[] schools() default {"默认值一","默认值二"};
}
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation02{
String value();//单个属性的时候,默认的命名,不需要指定属性名称
}
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Annotation03{
String name();//单个属性的时候,
}
5、反射概述
java是一个静态语言,通过反射机制,java变成了一个准动态语言,虽然java不是静态语言
- java反射机制
- 理解class类并获取class实例
- 类的加载与ClassLoader(双亲委派机制)
- 创建运行时类的对象(创建对象的方式,1、new关键字 2、clone()方法 3、利用反射机制)
- 获取运行时类的完整结构
- 调用运行时类的指定结构(注解就是其中之一)
什么是静态语言什么是动态语言
动态语言在运行时可以改变其结构(比如引进新的代码、函数、对象,修改已有函数的结构或删除,就是在运行的时候可以更改自己的结构),静态语言则不可以
function f(){
var x="var a=3; var b=5; alert(a+b);"
eval(x)
//可以动态的改变x的值,从而改变程序的结构
}
Reflection(反射)被视为动态语言的关键,反射机制允许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法
Class c = Class.ForName(“java.lang.String”)
加载完类之后,在堆内存的方法区中就产生了一个class类型的对象(一个类只要一个class对象),这个对象就包含了完整的类的结构信息。就像这个类的镜像。所以称为反射
创建对象的方式
-
正常方式
引入需要的“包类”名称——通过new实例化——取得实例化对象
-
反射方式
实例化对象——getClass()方法——得到完整的“包名”名称
相反的一个过程
反射机制的作用
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和成员方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
- ····
反射的优缺点
优点
可以实现动态创建对象和编译,体现出很大的灵活性
缺点
对性能有影响,使用反射操作基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作
6、获取反射对象
package com.zzl.com.zzl.reflection;
//什么是反射
public class Reflection {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的class对象
Class c1=Class.forName("com.zzl.com.zzl.reflection.User");
System.out.println(c1);
Class c2=Class.forName("com.zzl.com.zzl.reflection.User");
Class c3=Class.forName("com.zzl.com.zzl.reflection.User");
Class c4=Class.forName("com.zzl.com.zzl.reflection.User");
System.out.println(c2==c3);
System.out.println(c2==c1);
System.out.println(c4==c3);
}
}
class User{
private String name;
private int id;
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", 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;
}
}
Class类
在object类中定义了getClass方法,这个方法会被所有的子类继承,这个方法的返回值类型是一个class类,此类就是java反射的源头,反射即通过对象获得类的名称
7、得到Class类的几种方式
Class类的特点
-
Class本身也是一个类
-
Class对象只能由系统建立对象
-
每个类的实例所对应的Class是相同的
-
Class类是Reflection的根源
Class类的常用方法
方法名 | 方法描述 |
---|---|
static ClassforName(String name) | 返回指定类名name的Class对象 |
Object newlnstance() | 调用缺省构造函数,返回Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类,接口,数组类或void)的名称。 |
Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
Class[] getinterfaces() | 获取当前Class对象的接口 |
ClassLoader getClass oader() | 返回该类的类加载器 |
Constructor] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Method getMothed(String name,Class… T) | 返回一个Method对象,此对象的形参类型为 paramType |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
获得class类的方式
- Class.forName
- 类名.class
- 对象.getClass()
- 内置基本数据类型可以通过
类名.Type
- 利用ClassLoader
package com.zzl;
public class Reflection {
public static void main(String[] args) throws ClassNotFoundException {
Animal animal=new Cat();
System.out.println(animal.getName());
//方式一: 通过类名.class获得
Class c1 = Cat.class;
System.out.println(c1.hashCode());
//方式二: forName获得
Class c2 = Class.forName("com.zzl.Cat");
System.out.println(c2.hashCode());
//方式三: 通过对象获得
Class c3 = animal.getClass();
System.out.println(c3.hashCode());
//方式四: 基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
}
}
class Animal{
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
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;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Cat extends Animal{
public Cat() {
this.setName("cat");
}
}
class Dog extends Animal{
public Dog() {
this.setName("dog");
}
}
8、那些类可以有Class对象
- class:外部类、成员(成员内部类,静态内部类)、局部内部类,匿名内部类
- interface:接口
- []
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void
package com.zzl;
import java.lang.annotation.ElementType;
public class AllClass {
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; //void
Class c9 = 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);
//只要元素类型和维度一样就是同一个Class
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a);
System.out.println(b);
}
}
9、类加载内存分析
Java内存
- 堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会被别的对象引用
- 栈
- 存放基本数据类型(包括这个基本类型的具体数值)
- 存放引用类型变量(包括这个引用类型存放在堆中的地址)
- 方法区
- 可以被所有线程共享
- 包括所有的class个static变量
类的加载过程
类的加载(Load)→类的链接(Link)→类的初始化(Initialize)
-
类的加载:将类的Class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
-
类的链接:将类的二进制数据合并到JRE中
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用地址的过程
-
类的初始化:JVM负责对类进行初始化
- 执行类构造器()方法的过程。类构造器()方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
- 当初始化一个类的时候,如果发现其父类还有没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的()方法在多线程环境中被正确的加锁和同步
package com.zzl;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class Test01 {
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的无参构造函数初始化");
}
}
A类的静态代码块初始化
A的无参构造函数初始化
100
执行步骤:
1、将字节码文件读取并存放到方法区
类Test01的数据
1. 静态变量
2. 静态方法
3. 常量池
4. 代码
···
类A的数据
1. 静态变量
2. 静态方法
3. 常量池
4. 代码
···
2、将方法区中存放的类的数据生成相应的类Class对象,存放到堆中
Test01的java.lang.Class对象
A的java.lang.Class对象
3、通过new 关键字创建对象步骤
1、到方法区中找到对应的类的信息,从而也可以获得该类的Class对象(也就是类的加载过程)
2、类的链接,先确定是否符合jvm规范,在合并静态代码块,并给变量赋值默认值0/""
3、类的初始化,执行<clinit>方法,给变量赋值
<clinit>(){
System.out.println("A类的静态代码块初始化");
m=300;
m=100;
}
==> m = 100
10、分析类的初始化
类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。比如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类的引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
package com.zzl;
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException {
//new关键字会触发主动引用
//Son son = new Son();
System.out.println("--------------------------");
//通过反射也会触发主动引用
Class.forName("com.zzl.Son");
System.out.println("--------------------------");
//不会产生主动引用的方式
//System.out.println(Son.f);
System.out.println("--------------------------");
//Son[] ss = new Son[10];
System.out.println("--------------------------");
//System.out.println(Son.S);
System.out.println("--------------------------");
}
}
class Father{
static int f = 0;
static {
System.out.println("父类被加载");
}
}
class Son extends Father{
static int s = 1;
static final int S = 100;
static {
System.out.println("子类被加载");
}
}
11、类加载器
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存:标准的JavaSE类加载器可以按要求查找类,一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。
类加载器的种类
- 自定义加载器
- SystemClassLoader:系统类加载器,负责java-classpath目录下的jar包或-D java.class.path所指的目录下的类或者jar包装入工作,是最常用的类加载器
- ExtensionClassLoader:扩展类加载器,负责jre/lib/ext目录下的jar包或D java.ext.dirs指定目录下的jar包装入工作库
- BootStrapClassLoader:引导类加载器,用C/C++编写的,是jvm自带的类加载器,负责java平台核心库,用来装载核心类库。该加载器无法直接获取
package com.zzl;
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类加载器
System.out.println(ClassLoader.getSystemClassLoader());
//获取扩展类加载器
System.out.println(ClassLoader.getSystemClassLoader().getParent());
//获取引导类加载器
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
//测试当前类是哪个类加载器加载的
System.out.println(Class.forName("com.zzl.Test03").getClassLoader());
System.out.println(Class.forName("java.lang.Object").getClassLoader());
}
}
12、获取类的运行时结构
public class Test04 {
public static void main(String[] args) throws ClassNotFoundException {
//获取class对象
Class c1 = Class.forName("com.zzl.Son");
//1、获取类的名字
System.out.println(c1.getName());/*包名+类名*/
System.out.println(c1.getSimpleName());/*类名*/
/*2、获取类的属性*/
System.out.println(c1.getFields());//获取public属性
for (Field field:
c1.getFields() ) {
System.out.println(field);
}
System.out.println(c1.getDeclaredFields());//获取全部属性
for (Field field:
c1.getDeclaredFields() ) {
System.out.println(field);
}
}
}
方法名 | 方法描述 |
---|---|
getMethods() | 获取本类的public方法+父类的所有public方法 |
getDeclarMethods() | 获得本类的所有方法 |
getMethod(String name, Class<?>… parameterTypes) | Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. |
getConstructors() | Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object. |
getDeclaredConstructors() | Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. |
13、动态创建对象执行方法
创建类的对象:调用Class对象的newinstance()方法
1、类必须有一个无参构造器
2、类的构造器的访问权限要足够
如果没有无参构造器可以通过获取其他有参构造器来创建对象
1、通过Class类的getDeclarConstructor(class··· parameterType)取得本类的指定形参类型的构造器
2、向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数
3、通过Constructor实例化对象
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//get a object
//Class c1 = Class.forName("com.zzl.Son");
//instance a object
//Son son = (Son) c1.newInstance();//essentially use No-parameter construction method
//System.out.println(son);
//if this class object not have No-parameter construction method, you can get constructor with parameter
Class c2 = Class.forName("com.zzl.Son");
Constructor constructor = c2.getDeclaredConstructor(int.class);
Son son2 = (Son) constructor.newInstance(3);
System.out.println(son2);
//call common method by reflect
User user = new User();
Class c3 = user.getClass();
//get a method by reflect
Method setName = c3.getDeclaredMethod("setName", String.class);
setName.invoke(user,"tom");//invoke : active method or execute method
System.out.println(user);
//modify this fields by reflect
User user1 = new User();
Class c4 = user1.getClass();
// Field name = c4.getDeclaredField("name");
// name.set(user1,"jery");
// System.out.println(user1);
/*
Exception in thread "main" java.lang.IllegalAccessException: Class com.zzl.Test05 can not access a member of class com.zzl.User with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Field.set(Field.java:761)
at com.zzl.Test05.main(Test05.java:35)
*/
//execute error because this filed is embellished by private,so can not direct modify private filed,need remove safety check
//add this code at procedure : name.setAccessible(true);
Field name = c4.getDeclaredField("name");
name.setAccessible(true);
name.set(user1,"jery");
System.out.println(user1);
}
}
setAccessible
1)、method和filed,Constructor对象都有setAccessible()方法
2)、setAccessible作用是启动和禁止访问安全检查的开关
3)、参数值为true代表反射对象在使用的时候取消java语言的访问检查
a)、提高反射的效率,如果代码中必须使用反射,而代码需要频繁的被调用,那么设置为true,取消安全检查
b)、使得原本无法访问的私有成员也可以访问
4)、默认值是FALSE表示的是启动安全检查
14、反射性能测试
public class Test06 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
//new keyword create object
static void test01(){
//create object
User user = new User();
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime=System.currentTimeMillis();
System.out.println("new:"+(endTime-startTime)+"ms");
}
//reflect create object
static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//create object
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName");
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime=System.currentTimeMillis();
System.out.println("reflect:"+(endTime-startTime)+"ms");
}
//reflect and no safety check create object
static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//create object
User user = new User();
Class c1 = user.getClass();
Method getName = c1.getDeclaredMethod("getName");
getName.setAccessible(true);
long startTime=System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user);
}
long endTime=System.currentTimeMillis();
System.out.println("reflect + no-safety check:"+(endTime-startTime)+"ms");
}
}
15、获取泛型信息
1)、java采用泛型擦除机制来引入泛型,java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
2)、为了通过反射操作这些类型,java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到class类中的类型但是又和原始类型齐名的类型
a)、ParameterizedType:表示一种参数化类型,比如Collection
b)、GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
c)、TypeVariable:是各种类型变量的公共父接口
d)、WildcardType:代表一种通配符类型表达式
package com.zzl;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//get Generics by reflect
public class Test07 {
public void test01(Map<String,User> map, List<User> list){
System.out.println("test01");
}
public Map<String,User> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test07.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);
}
}
}
method = Test07.class.getMethod("test02",null);
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);
}
}
}
}
}
16、获取注解信息
ORM object relationship mapping→对象关系映射
class Student{
int id;
String name;
int age;
}
↓
id | name | age |
---|---|---|
001 | tom | 3 |
002 | jery | 4 |
- 类和表结构对应
- 属性和字段对应
- 对象和记录对应
练习:利用注解和反射完成类和表结构的映射关系
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.zzl.Student");
//get annotation by reflect
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//get annotation's value
MyAnnotationClass annotationClass = (MyAnnotationClass)c1.getAnnotation(MyAnnotationClass.class);
String value = annotationClass.value();
System.out.println(value);
//get the annotation specified bt the class
Field f = c1.getDeclaredField("name");
MyAnnotationFiled annotation = f.getAnnotation(MyAnnotationFiled.class);
System.out.println(annotation.column());
System.out.println(annotation.column_name());
System.out.println(annotation.length());
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotationClass{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotationFiled{
int column();
String column_name();
int length();
}
@MyAnnotationClass("db_student")
class Student{
@MyAnnotationFiled(column = 1,column_name = "st_id",length = 10)
private int id;
@MyAnnotationFiled(column = 1,column_name = "st_name",length = 100)
private String name;
@MyAnnotationFiled(column = 1,column_name = "st_pass",length = 100)
private String pass;
@MyAnnotationFiled(column = 1,column_name = "st_age",length = 10)
private int age;
public Student() {
}
public Student(int id, String name, String pass, int age) {
this.id = id;
this.name = name;
this.pass = pass;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", pass='" + pass + '\'' +
", age=" + age +
'}';
}
}
学习视频来源于B站:https://www.bilibili.com/video/BV1p4411P7V3?p=17&spm_id_from=pageDriver