注解和反射

注解和反射

注解

注解:Annotation 从JDK5.0开始引入的新技术

  • Annotation的作用:

    • 不是程序本身,它可以对程序做出解释(这一点和注释(comment)没什么区别)

    • 可以被其他程序(比如:编辑器等)读取

  • Annotation的格式: 以“@注释名”在代码中存在的,还可以添加一些参数值,比如:@SuppressWarnings(value="unchecked")

  • Annotation在哪里使用? 可以附加在package、class、method、field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问

内置注解

  • @Override : 定义在java.lang.Override中,此注解只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法的声明

  • @Deprecated: 定义在java.lang.Deprecated中,此注解可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险,或者有更好的选择 (能用 只是不建议使用)

  • @SuppressWarnings: 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,它与前两个注释有所不同,需要添加一个参数才能正常使用,这些参数都是定义好了的,我们选择性的使用就好

    • @SuppressWarnings("all")

    • @SuppressWarnings("unchecked")

    • @SuppressWarnings(value={"unchecked","deprecation"})

元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明

这些类型和它们所支持的类在java.lang.annotation包中可以找到

  • @Target : 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  • @Retention : 表示需要在什么级别保存该注释信息,用于描述注解的生命周期(范围:RUNTIME > CLASS > SOURCE)

  • @Document : 说明该注释被包含在javadoc中

  • @Inherited : 说明子类可以继承父类中的该注解

 package com.annotation_reflection.annotation;
 
 import java.lang.annotation.*;
 //测试元注解
 public class Demo02 {
 }
 
 //定义一个注解
 @Target(ElementType.TYPE)     //表示注解可以用在哪些地方
 @Retention(RetentionPolicy.RUNTIME)      //表示注解在什么地方有效
 @Documented      //表示注解生成在javadoc中
 @Inherited      //子类可以继承父类的注解
 @interface MyAnnotation{
 }
 

自定义注解

使用@Interface自定义注解时,自动继承了java.long.Annotation接口

分析:

  • @Interface用来声明一个注解,格式:public @Interface 注解名 {定义内容}

  • 其中的每一个方法实际上是声明了一个配置参数

  • 方法的名称就是参数的名称

  • 返回值类型就是参数的类型(返回值只能是基本类型、Class、String、enum)

  • 可以通过default来声明参数的默认值

  • 如果只有一个参数成员,一般参数名为value

  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值

 package com.annotation_reflection.annotation;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 //自定义注解
 @TestAnnotation01(age = 18)
 public class Demo03 {
     @TestAnnotation01(name = "郑常超",age = 18)
     public void test01(){
 
    }
     @TestAnnotation01(age = 18)
     public void test02(){
 
    }
     //定义参数为的话value不用写  
     @TestAnnotation02("123")
     public void test03(){
         
    }
 }
 
 @Target({ElementType.TYPE,ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface TestAnnotation01{
     String name() default "";  //默认是空
     int age();
     String[] school() default {"石家庄学院","南校区"};
 }
 
 @interface Testtation02{
     String value();
 }
 

 

反射

反射:Reflection

反射(Reflection)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

Class c= Class.forName("java.lang.String")

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个class对象),这个对象就包含了完整的类的结构对象。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过镜子看到类的结构,所以我们形象的称之为:反射

正常方式:

引入需要的“包类”名称——>通过new实例化——>取得实例化对象

反射方式:

实例化对象——>getClass()方法——>得到完整的“包类”名称

 补充:
 静态语言VS动态语言
 
 动态语言:是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其它结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
 主要的动态语言:Object-C、C#、JavaScript、PHP、python等
 
 静态语言:与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++
 Java不是动态语言,但Java可以被成为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程更加灵活

Java反射机制提供的功能:

  • 在运行时判断任意一个对象所属的类

  • 在运行时构造任意一个类的对象

  • 在运行时判断任意一个类型所具有的成员变量和方法

  • 在运行时获取泛型信息

  • 在运行时调用任意一个对象的成员变量和方法

  • 在运行时处理注解

  • 生成动态代理

  • ...........................

Java反射的优点和缺点:

优点:可以实现动态创建对象和编译,体现出很大的灵活性

缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

反射相关的主要API:

  • java.lang.Class :代表一个类

  • java.lang.reflect.Method :代表类的方法

  • java.lang.reflect.Field :代表类的成员变量

  • java.lang.reflect.Constructor :代表类的构造器

  • ..................

Class类

 

 

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪个接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构(class\interface\enum\annotation\primitive type\void[])的有关信息。

  • Class本身也是一个类

  • Class对象只能由系统建立对象

  • 一个加载的类在JVM中只会有一个Class实例

  • 一个Class对象对应的是一个加载到JVM中的一个class文件

  • 每个类的实例都会记得自己是由哪个Class实例所生成

  • 通过Class可以完整地得到一个类中的所有被加载的结构

  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

 

 

获得Class类的实例的几种方式:

  1. 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高:

    Class c = Person.class;

  2. 已知某个类的实例,调用该实例的getClass()方法获取Class对象:

    Class c = person.getClass;

  3. 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,要抛出“ClassNotFoundException”

    Class c = Class.forName("demo01.Student");

  4. 内置基本数据类型可以直接用类名,Type

  5. 还可以利用ClassLoader

 package com.annotation_reflection.reflection;
 
 //测试创建Class类的方式有哪些
 public class Demo02 {
     public static void main(String[] args) {
         Person person = new Student();
         System.out.println(person.name);
 
         //方式1:已知具体的类,通过类的class属性获取
         Class s1 = Student.class;
         System.out.println(s1.hashCode());
         //方式2:已知某个类的实例,调用该实例的getClass()方法获取
         Class s2 = person.getClass();
         System.out.println(s2.hashCode());
         //方式3:已知一个类的全类名,且该类在类路径下,通过Class类的静态方法forName()获取
         try {
             Class s3 = Class.forName("com.annotation_reflection.reflection.Student");
             System.out.println(s3.hashCode());
        } catch (ClassNotFoundException e) {
             e.printStackTrace();
        }
 
         //测试返回当前Class对象的父类的Class对象
         Class s1Super = s1.getSuperclass();
         System.out.println(s1Super.getName());
    }
 }
 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="student";
    }
 }
 class Teacher extends Person{
     public Teacher() {
         this.name="teacher";
    }
 }
 /* 输出结果
 student
 140435067
 140435067
 140435067
 com.annotation_reflection.reflection.Person
  */

哪些类型可以有Class对象:

  • class:外部类,成员(成员内部类、静态内部类),局部内部类、匿名内部类

  • interface : 接口

  • [] : 数组

  • enum:枚举

  • annotation:注解@interface

  • primitive type :基本数据类型

  • void

 package com.annotation_reflection.reflection;
 
 import java.lang.annotation.ElementType;
 
 public class Demo03 {
     public static void main(String[] args) {
         Class c1 = Object.class;          //类
         Class c2 = Comparable.class;      //接口
         Class c3 = String[].class;        //一维数组
         Class c4 = String[][].class;      //二维数组
         Class c5 = ElementType.class;     //枚举
         Class c6 = Override.class;        //注解
         Class c7 = int.class;             //基本数据类型
         Class c8 = void.class;            //void
         Class c9 = Class.class;           //Class本身
 
         //快捷键 复制本行到下一行 :ctrl+d   一列复制:按住alt控制鼠标
         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];
         int[][] c = new int[10][10];
         Class a1 = a.getClass();
         Class b1 = b.getClass();
         Class c11 = c.getClass();
         System.out.println(a1);
         System.out.println(b1);
         System.out.println(c11);
    }
 }
 /* 输出结果
 class java.lang.Object
 interface java.lang.Comparable
 class [Ljava.lang.String;
 class [[Ljava.lang.String;
 class java.lang.annotation.ElementType
 interface java.lang.Override
 int
 void
 class java.lang.Class
 class [I
 class [I
 class [[I
  */
 

类加载内存分析

Java内存:

  • 堆 :存放new的对象和数组、可以被所有的线程共享,不会存放别的对象引用

  • 栈:存放基本数据类型(会包含这个基本数据类型的具体数值)、引用对象的变量(会存放这个引用在堆里面的具体地址)

  • 方法区:可以被所有的线程共享、包含了所有的class和static变量

了解类的加载过程:

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过以下三个步骤来对该类进行初始化:

  1. 类的加载(Load):将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成

  2. 类的链接(Link):将类的二进制数据合并到JRE中

  3. 类的初始化(Initialize):JVM负责对类进行初始化

 

分析类初始化

类的主动引用(一定会发生类的初始化):

  • 当虚拟机启动,先初始main方法所在的类

  • new 一个类的对象

  • 调用类的静态成员(除了final常量)和静态方法

  • 使用java.lang.reflect包的方法对类进行反射调用

  • 当初始化一个类,如果其父类没有被初始化,则会先初始化它的父类

类的被动引用(不会发生类的初始化):

  • 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类被初始化

  • 通过数组定义类引用,不会触发此类的初始化

  • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

 package com.annotation_reflection.reflection;
 
 public class Demo04 {
     static {
         System.out.println("main所在的类被初始化");
    }
     public static void main(String[] args) throws ClassNotFoundException {
         // 1. new 主动引用
         //Zi zi = new Zi();
 
         //2.调用类的静态成员   主动引用
         //System.out.println(Zi.m);
 
         //3.反射调用   主动引用
         //Class.forName("com.annotation_reflection.reflection.Zi");
 
         //不会产生类的引用的方法
         //System.out.println(Zi.b);
         //System.out.println(Zi.n);
 
 
    }
 }
 class Fu{
     static int b=2;
     static {
         System.out.println("父类被初始化");
    }
 }
 class Zi extends Fu{
 
     static {
         System.out.println("子类被初始化");
         m=300;
    }
     static int m=100;
     static final int n=10;
 }

类加载器

类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。

类缓存:标准的JavaSE类加载器可以按照要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

 

 

 

 

 package com.annotation_reflection.reflection;
 
 //测试类加载器
 public class Demo05 {
     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);
 
         System.out.println("------------------------");
         //测试当前类是哪个类加载器加载的
         ClassLoader classLoader = Class.forName("com.annotation_reflection.reflection.Demo05").getClassLoader();
         System.out.println(classLoader);  //系统加载器
         ClassLoader classLoader1 = Class.forName("java.lang.String").getClassLoader();
         System.out.println(classLoader1);  //根加载器
    }
 }
 /*
 jdk.internal.loader.ClassLoaders$AppClassLoader@6d06d69c
 jdk.internal.loader.ClassLoaders$PlatformClassLoader@7adf9f5f
 null
 ------------------------
 jdk.internal.loader.ClassLoaders$AppClassLoader@6d06d69c
 null
  */
 

获取运行时类的完整结构

通过反射获取运行时类的完整结构:Field、Method、Constructor、Superclass、Interface、Annotation

  • 实现的全部接口

  • 所继承的父类

  • 全部的构造器

  • 全部的方法

  • 全部的Filed

  • 注解

  • .............

 package com.annotation_reflection.reflection;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 public class Demo06 {
     public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
         Class c1 = Class.forName("com.annotation_reflection.reflection.User");
 
         //获得类的名字
         System.out.println(c1.getName());  //包名+类名
         System.out.println(c1.getSimpleName());  //类名
 
         System.out.println("------------------");
         //获得其父类
         System.out.println(c1.getSuperclass());
 
         System.out.println("------------------");
         //获得类的属性
         Field[] fields = c1.getFields();    //只能获得public属性
         for (Field field : fields) {
             System.out.println(field);
        }
         System.out.println("------------------");
         Field[] declaredFields = c1.getDeclaredFields();  //获得全部属性
         for (Field declaredField : declaredFields) {
             System.out.println(declaredField);
        }
         System.out.println("------------------");
         Field name = c1.getDeclaredField("name");
         System.out.println(name);
 
         System.out.println("------------------");
         //获得类的方法
         Method[] declaredMethods = c1.getDeclaredMethods();
         for (Method declaredMethod : declaredMethods) {
             System.out.println(declaredMethod);
        }
 
         System.out.println("------------------");
         //获得指定的构造器
         Constructor[] constructors = c1.getConstructors();
         for (Constructor constructor : constructors) {
             System.out.println(constructor);
        }
         Constructor[] declaredConstructors = c1.getDeclaredConstructors();
         for (Constructor declaredConstructor : declaredConstructors) {
             System.out.println(declaredConstructor);
        }
    }
 }
 /*
 com.annotation_reflection.reflection.User
 User
 ------------------
 class java.lang.Object
 ------------------
 ------------------
 private int com.annotation_reflection.reflection.User.id
 private int com.annotation_reflection.reflection.User.age
 private java.lang.String com.annotation_reflection.reflection.User.name
 ------------------
 private java.lang.String com.annotation_reflection.reflection.User.name
 ------------------
 public java.lang.String com.annotation_reflection.reflection.User.getName()
 public java.lang.String com.annotation_reflection.reflection.User.toString()
 public void com.annotation_reflection.reflection.User.setName(java.lang.String)
 public int com.annotation_reflection.reflection.User.getId()
 public void com.annotation_reflection.reflection.User.setAge(int)
 public int com.annotation_reflection.reflection.User.getAge()
 public void com.annotation_reflection.reflection.User.setId(int)
 ------------------
 public com.annotation_reflection.reflection.User()
 public com.annotation_reflection.reflection.User(int,int,java.lang.String)
 public com.annotation_reflection.reflection.User()
 public com.annotation_reflection.reflection.User(int,int,java.lang.String)
  */
 

动态创建对象执行方法

 

 package com.annotation_reflection.reflection;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 //动态的创建对象 通过反射
 public class Demo07 {
     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
         //获得Class对象
         Class c1 = User.class;
 
         //构造一个对象
         //User user = (User) c1.newInstance(); //本质上是调用了类的无参构造器
         //System.out.println(user);
 
         //通过有参构造器创建对象
         //Constructor declaredConstructor = c1.getDeclaredConstructor(int.class, int.class, String.class);
         //User user1 = (User) declaredConstructor.newInstance( 1, 16,"超超");
         //System.out.println(user1);
 
         //通过反射调用普通方法
         User user02 = (User) c1.newInstance();
         //通过反射获取一个方法
         Method setName = c1.getDeclaredMethod("setName", String.class);
         setName.invoke(user02,"常超");   //invoke 激活的意思
         System.out.println(user02.getName());
 
         System.out.println("----------------");
         //通过反射操作属性
         User user03 = (User) c1.newInstance();
         Field name = c1.getDeclaredField("name");
 
         //不能直接操作私有属性,需要先关闭程序的安全检测
         name.setAccessible(true);
 
         name.set(user03,"超哥");
         System.out.println(user03.getName());
 
    }
 }
 

setAccessible:

  • Method和Field、Constructor对象都有setAccessible()方法

  • setAccessible()作用是启动和禁止访问安全检查的开关

  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查

    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true

    • 使得原本无法访问的私有成员也可以访问

  • 参数值为flase则只是反射的对象应该被实施Java语言访问检查(默认是flase)

性能检测分析

 package com.annotation_reflection.reflection;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 public class Demo08 {
     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
 
         Demo08 demo08 = new Demo08();
         demo08.test01();
         demo08.test02();
         demo08.test03();
    }
 
     //普通方法调用
     public 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 void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         User user = new User();
         Class 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 void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
         User user = new User();
         Class 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");
    }
 }
 /*
 正常方式执行10亿次:5ms
 反射方式执行10亿次:2449ms
 反射方式关闭检测执行10亿次:1069ms
  */

反射操作类型

 

 

 package com.annotation_reflection.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 Demo09 {
     public static void main(String[] args) throws NoSuchMethodException {
         Method method = Demo09.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 method02 = Demo09.class.getMethod("test02",null);
         Type genericParameterTypes1 = method02.getGenericReturnType();
             if (genericParameterTypes1 instanceof ParameterizedType){
                 Type[] actualTypeArguments = ((ParameterizedType) genericParameterTypes1).getActualTypeArguments();
                 for (Type actualTypeArgument : actualTypeArguments) {
                     System.out.println("111"+actualTypeArgument);
                }
            }
    }
 
     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;
    }
 }
 /*
 *java.util.Map<java.lang.String, com.annotation_reflection.reflection.User>
 --class java.lang.String
 --class com.annotation_reflection.reflection.User
 *java.util.List<com.annotation_reflection.reflection.User>
 --class com.annotation_reflection.reflection.User
 111class java.lang.String
 111class com.annotation_reflection.reflection.User
  */
 

 

获得注解信息

 

 

要求:利用注解和反射完成类和表结构的映射关系

 

 package com.annotation_reflection.reflection;
 
 import java.lang.annotation.*;
 import java.lang.reflect.Field;
 
 public class Demo11 {
     public static void main(String[] args) throws NoSuchFieldException {
         Book book = new Book();
         Class bookClass = book.getClass();
 
         //通过反射获得注解
         Annotation[] annotations = bookClass.getAnnotations();
         for (Annotation annotation : annotations) {
             System.out.println(annotation);
        }
 
         //获得注解的value值
         TableChao tableChao = (TableChao) bookClass.getAnnotation(TableChao.class);
         String value = tableChao.value();
         System.out.println(value);
 
         //获得属性的注解
         Field bookName = bookClass.getDeclaredField("bookName");   //先确定哪个属性
         FiledChao annotation = bookName.getAnnotation(FiledChao.class);
         System.out.println(annotation.columnName());
         System.out.println(annotation.type());
         System.out.println(annotation.length());
    }
 }
 
 @TableChao(value = "db_book")
 class Book{
     @FiledChao(columnName = "db_id",type = "int",length = 10)
     private int id;
     @FiledChao(columnName = "db_bookName",type = "Varchar",length = 10)
     private String bookName;
     @FiledChao(columnName = "db_price",type = "double",length = 10)
     private double price;
 
     public Book() {
    }
 
     public Book(int id, String bookName, double price) {
         this.id = id;
         this.bookName = bookName;
         this.price = price;
    }
 
     public int getId() {
         return id;
    }
 
     public void setId(int id) {
         this.id = id;
    }
 
     public String getBookName() {
         return bookName;
    }
 
     public void setBookName(String bookName) {
         this.bookName = bookName;
    }
 
     public double getPrice() {
         return price;
    }
 
     public void setPrice(double price) {
         this.price = price;
    }
 
     @Override
     public String toString() {
         return "Book{" +
                 "id=" + id +
                 ", bookName='" + bookName + '\'' +
                 ", price=" + price +
                 '}';
    }
 }
 
 //类名的注解
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @interface TableChao{
     String value();
 }
 
 //属性的注解
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
 @interface FiledChao{
     String columnName();
     String type();
     int length();
 }
 /*
 @com.annotation_reflection.reflection.TableChao("db_book")
 db_book
 db_bookName
 Varchar
 10
  */
 

 

 

 

 

 

 

posted @ 2022-04-09 12:26  超、自律即自由  阅读(30)  评论(0编辑  收藏  举报