JAVA入门————反射机制Reflection AND JAVA内存分析

反射Reflection

动态语言
  • 定义:在运行时可以改变其结构的语言
    eg:新的函数、对象、甚至代码可以被引进
    eg:已有的函数可以被删除或是其他结构上的变化
静态语言
  • 定义:在运行时不可以改变其结构的语言
    eg:Java C C++
  • Java——准动态语言————拥有反射机制
定义

Reflection是Java被视为动态语言的关键

  • 反射机制允许程序在执行期借 助于Reflection API取得任何类的内部信息 ( eg :类名 类成员等) 并能直接操作任意对象的内部属性及方法
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(简称模板)一个类在内存中只有 一个Class对象)————包含了完整的类的结构信息
  • 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以, 我们形象的称之为:反射————通过一个对象反射出这个类
    Class 是一个类 , class 是一个关键字
功能
  1. 运行时判断任意一个对象所属的类
  2. 运行时构造任意一个类的对象
  3. 运行时判断任意一个类所具有的的成员变量和方法
  4. 运行时调用任意一个对象的成员变量和方法
  5. 运行时处理注释
优缺点
  • 优点:可以实现动态创建对象和编译 可以体现出很大的灵活性
  • 缺点:对性能有影响 总是慢于直接执行相同的操作(直接new对象)————使用反射基本上是一种解释操作 我们可以告诉JVM我们要做什么并且使它满足我们的要求
相关API
  • java.lang.Class: 代表一个
  • java.lang.reflect.Method : 代表类的方法
  • java.lang.reflect.Field : 代表类的成员变量
  • java.lang.reflect.Constructor : 代表类的构造器

需求:使用反射创建一个类的对象

public class demo1 {
    public static void main(String[] args) throws Exception {
        //正常手段new对象
        User user1 = new User(001, "Kitty", 15);
        User user2 = new User(001, "Kitty", 15);
        System.out.println("----------------------------");
        Class class1 = Class.forName("反射.User"); ————————获取类的模板
        User user = (User) class1.newInstance(); ————————获取类的对象
        user.setAge(20);
        user.setId(002);
        user.setName("Tony");
        System.out.println(user);
    }
}
class User{
    private int id;
    private String name;
    private int age;
    public User(){}
    public User(int id, String name, int age) {
        this.id = id;
        this.name = name;
        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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "id:"+id+"    name:"+name+"    age:"+age;
    }
}

类 Class

对象照镜子后可以得到的信息——某个类的属性、方法和构造器、某个类到底实现了哪些接口
对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象

注意:

  1. 一个加载的类在 JVM 中只会有一个Class实例
  2. 一个Class对象对应的是一个加载到JVM中的一个.class文件
  3. 每个类的实例都会记得自己是由哪个 Class 实例所生成
  4. Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象
  • Class 类的实例表示正在运行的 Java 应用程序中的类和接口
  • 枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
  • 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
  • 注意:Class 没有公共构造方法
  • 成员方法
forName(String className) ——返回与带有给定字符串名的类或接口相关联的 Class 对象

eg: Class class1 = Class.forName("反射.User"); ————————获取类的模板——包名+类名

newInstance() ——创建此 Class 对象所表示的类的一个新实例。

eg: User user = (User) class1.newInstance(); ————————获取类的对象———类名调用方法

getName() ——返回此 Class 对象所表示的实体名称。
getSuperclass() ——返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class
getInterfaces() ——获得此对象所表示的类或接口实现的接口。
getClassLoader() —— 返回该类的类加载器。
getConstructors() ——返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
getMethod(String name, Class… parameterTypes) ——返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
getDeclaredFields() ——返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。
getPackage() ——获取此类的包
  • 获取class对象的三种方法
    1. 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
      eg:Class clazz = Person.class; ————类名直接调用
    1. 已知某个类的实例,调用该实例的getClass()方法获取Class对象
      eg:Class clazz = person.getClass(); ————new出来的实例对象调用getclass方法
    1. 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取, 可能抛出ClassNotFoundException
      eg:Class clazz = Class.forName("demo01.Student");————forname方法
    1. 内置基本数据类型可以直接用类名.Type e) 还可以利用ClassLoader我们之后讲解
  • 练习获取class类

public class demo2 {
    public static void main(String[] args) throws Exception {
        //获得class对象的方法1——用new出来的对象实例获取class模板
        Person person = new Student();
        Class class1 = person.getClass();
        //获得class对象的方法2
        Class class2 = Class.forName("反射.Person");
        //获得class对象的方法3——类名直接调用class
        Class class3 = Student.class;
        //获取父类的类型
        Class superclass = class1.getSuperclass();
        //获取Class对象——正对包装类,内置基本类型 ,只对包装类型有效
        Class type = Integer.TYPE;
        System.out.println(type);//——————输出:int
        // 打印
        System.out.println(person);
        System.out.println(class1);
        System.out.println(class2);
        System.out.println(class3);
        System.out.println(superclass);
    }
}
...————————此处省略类的描述
有class对象的类型
  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  • interface:接口
  • [ ]:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void

练习:各种类型的class对象

import java.lang.annotation.ElementType;
public class demo3 {
    public static void main(String[] args) {
        Class c1 = Object.class;     // Object类
        Class<Comparable> c2 = Comparable.class;// 接口
        Class<String> c3 = String.class; // 基本类型
        Class<String[]> c4 = String[].class; // 数组
        Class<ElementType> c5 = ElementType.class; // 枚举类型
        Class<Override> c6 = Override.class; // 注解
        Class c7 = int[][].class; // 基本类型
        Class<Void> c8 = void.class; // void
        Class<Class> c9 = Class.class;  // 反射对象本身
        System.out.println(c1);——————class java.lang.Object
        System.out.println(c2);——————interface java.lang.Comparable
        System.out.println(c3);——————class java.lang.String
        System.out.println(c4);——————class [Ljava.lang.String;
        System.out.println(c5);——————class java.lang.annotation.ElementType
        System.out.println(c6);——————interface java.lang.Override
        System.out.println(c7);——————class [[I
        System.out.println(c8);——————void
        System.out.println(c9);——————class java.lang.Class
        System.out.println("======================");
        // 数组中 和长度无关 类型相同就是一个class
        int[] arr = new int[10];
        int[] arr2 = new int[100];
        Class<? extends int[]> c10 = arr.getClass();
        Class<? extends int[]> c11 = arr2.getClass();
        System.out.println(c10);——————class [I
        System.out.println(c11);——————class [I
    }
}

JAVA内存分析


  • ——存放new出来的对象和数组 eg:new Student
    ——可以被所有线程共享 不会存放别的对象引用

  • ———存放基本变量类型 eg:int a = 1;
    ———存放引用对象的变量 eg:Integer b
  • 方法区
    ———可以被所有线程共享
    ———包含了所有的class和static
  • 当程序主动使用某个类时 如果该类还未被加载到内存中时 则系统会通过三个步骤对这个类进行初始化
  • 类的加载Load
  • 将类的class文件读入内存 将静态数据转换成方法区的运行时数据结构, 并为之创建一个java.lang.Class 对象
  • 类的链接
  • 将类的二进制数据合并到JRE中
    1. 验证:代码没有安全性问题 程序不会报错
    1. 准备:正式为类变量(static)分配内存 并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
    1. 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
  • 类的初始化
  • JVM负责对类进行初始化
    1. 执行类构造器==clinit()==方法的过程。

类构造器clinit()方法:由编译期自动收集类中所有类变量的赋值动作和静态 代码块中的语句合并产生的
(类构造器是构造类信息的,不是构造该类对象的构造器)。

    1. 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
    1. 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
      clinit( )——static代码块和变量合并 谁在后 谁最后赋值
  eg:	static {    
        	System.out.println("静态代码块");
       		 m = 300;
   		 }
  		static int m = 100;——————————m = 100

练习:深刻练习内存初始化

public class demo4 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.m);
        * 1. 加载——加载到内存 会产生一个类对应的class对象
        * 2. 连接——为static变量m分配内存 m=0
        * 3. 初始化——调用clinit()方法  最后m = 100;
        *       clinit()
        *           System.out.println("静态代码块");
                    m = 300;
                    m = 100;
        *       } 
    }
}
class A{
    static {      // 1.先执行静态代码块
        System.out.println("静态代码块");
        m = 300;
    }
    static int m = 100;
    public A(){  // 2.后执行构造方法
        System.out.println("构造方法");
    }
}
什么时候类初始化?
  • 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类

主动引用————一定导致类的初始化

  1. 当虚拟机启动,先初始化main方法所在的类
  2. new一个类的对象
eg: ------------主动引用:调用父类的静态变量 ——导致两者初始化
         Son son = new Son();
        System.out.println( new Son().f);
  1. 调用类的静态成员(除了final常量)和静态方法
eg:	--------调用子类的静态变量——导致两者初始化
        System.out.println(Son.s);
        --------调用子类的变量——导致两者初始化
        System.out.println(new Son().a);
  1. 使用java.lang.reflect包的方法对类进行反射调用
eg:		--------反射引用:——导致两者初始化
        Class.forName("反射.Son");

类的被动引用————不会发生类的初始化

  1. 当访问一个静态域时,只有真正声明这个域的类才会被初始化。
    eg:当通过子类引用父类的静态变量,不会导致子类初始化
eg:    --------子类调用父类的静态变量——导致父类被初始化 子类不会初始化
        System.out.println(Son.f);
  1. 通过数组定义类引用,不会触发此类的初始化
eg:	--------被动引用:创建自定义类数组——不会导致两者初始化
        Son[] sons = new Son[10];
  1. 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
eg:    --------子类调用常量 ——不会导致两者初始化
        System.out.println(Son.ss);

ClassLoader抽象类

  • 定义:类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”

类加载器

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

分类:系统提供的和java开发人员编写的

系统提供的类加载器有:引导类加载器 扩展类加载器 系统类加载器

  • 引导类加载器(bootstrap class loader)——父父——获取不了

用来加载 Java 的核心库,是用原生代码来实现的,并不继承自java.lang.ClassLoader。 无法直接获取

  • 扩展类加载器(extensions class loader)——父——ExtClassLoader

用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。

  • 系统类加载器(system class loader)——子——AppClassLoader

它据 Java 应用的类路径来加载 Java 类 Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例

  • 注意:除了父父——引导类加载器以外 所有的类加载器都有一个父类加载器
  • 一般开发人员编写的类加载器的父类加载器是系统类加载器

双亲委派模型

每个加载器都有自己的加载缓存 当一个类被加载之后会放进缓存中 等到下次加载时只需拿出之前加载好的类

  • 定义:如果一个类加载器接收到了类需要加载的请求
    1. 它会先从自己已经加载的类中查询此类是否被加载 若被加载 则直接返回加载好的类
    1. 如果自己没有加载这个类 会把这个请求委托给自己的父类加载器 父类则查看自己的缓存
    1. 若父类中没有加载 则把这个请求委托给父类的父类 它也会查看自己的缓存
    1. 当顶层父类加载器都没有加载时 再返回给最初的当前加载器进行加载
  • 优点:提高了安全性 防止程序混乱

练习获取类加载器

public class demo6 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获得系统的类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);——————sun.misc.Launcher$AppClassLoader@18b4aac2
        // 获得系统加载器的父类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);——————sun.misc.Launcher$ExtClassLoader@1b6d3586
        // 获得父类加载器的父类加载器
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);——————null
        //获取当前的类加载器
        ClassLoader classLoader = Class.forName("反射.demo6").getClassLoader();
        System.out.println(classLoader);——————sun.misc.Launcher$AppClassLoader@18b4aac2
        //获取JDK内置类的加载器——顶层加载器加载
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);——————null
        //获得系统类加载器可以加载的路径
        String property = System.getProperty("java.class.path");
        System.out.println(property);
    }
}

创建运行时的类对象

getFields() ——获取公共字段的数组
getDeclaredFields() ——获取所有字段的数组
getDeclaredField(String name) ——获取指定字段
getMethods() ——获取公共方法的数组
getDeclaredMethods() ——获取所有方法数组
getDeclaredMethod(String name, Class… parameterTypes) ——获取指定方法

需要参数 因为方法重载之后 仅仅靠方法名无法判断

getConstructors() ——获取公共构造器的数组
getDeclaredConstructor(Class… parameterTypes) ——获取所有构造器的数组
getConstructor(Class… parameterTypes) ——获取指定构造器
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class demo7 {
    public static void main(String[] args) throws Exception {
        // 获取类的信息——模板
        Class aclass = Class.forName("反射.User");
        // 获得类名
        System.out.println(aclass.getName());// 获得全类名:包名+类名
        System.out.println(aclass.getSimpleName());//获得类名
        System.out.println("============================");
        //获得字段(成员变量)
        Field[] fields = aclass.getFields();//获得public的变量
        for (Field field : fields) {
            System.out.println(field);
        }
        Field[] declaredFields = aclass.getDeclaredFields();//获得全部变量 包括private
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        System.out.println("============================");
        //获得指定字段
        Field id = aclass.getDeclaredField("id");
        System.out.println(id);
        System.out.println("============================");
        //获得方法
        Method[] methods = aclass.getMethods();// 获得public的方法
        for (Method method : methods) {
            System.out.println("公有:"+method);
        }
        Method[] declaredMethods = aclass.getDeclaredMethods();// 获得全部方法 包括私有
        for (Method declaredMethod : declaredMethods) {
            System.out.println("全部:"+declaredMethod);
        }
        System.out.println("============================");
        //获得指定方法
        Method getName = aclass.getMethod("getName");
        Method setName = aclass.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
        System.out.println("============================");
        //获得构造器
        Constructor[] constructors = aclass.getConstructors();//获得public的构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = aclass.getDeclaredConstructors();//获得全部的构造器 包括私有
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        System.out.println("============================");
        //获得指定的构造器
        Constructor constructor = aclass.getConstructor(null);
        Constructor constructor1 = aclass.getConstructor(int.class, String.class, int.class);
        System.out.println(constructor);
        System.out.println(constructor1);
    }
}

动态创建对象执行方法

反射创建对象的方法

  1. 通过模板调用newInstance()方法
  2. 通过指定构造器
    使用invoke( ) 执行方法
  • 注意: 反射无法获取私有的字段和方法——必须通过调用setAccessible(true)才可访问

练习:使用反射创建对象 调用方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class demo8 {
    public static void main(String[] args) throws Exception {
        Class aclass = Class.forName("反射.User");
       ------创建对象方法一——通过new默认为无参对象
        User user1 = (User) aclass.newInstance();
        System.out.println(user1);
        System.out.println("==========================");
       ------创建对象方法二——通过指定构造器创建对象
        Constructor declaredConstructor = aclass.getDeclaredConstructor(int.class, String.class, int.class);
        User user2 = (User) declaredConstructor.newInstance(1, "张三", 20);
        System.out.println(user2);
        System.out.println("==========================");
        /*调用方法传参*/
        //1. 创建一个对象
        User user3 = (User) aclass.newInstance();
        // 2. 获得要使用的方法
        Method setName = aclass.getDeclaredMethod("setName", String.class);
        //3. 使用invoke( ) 执行方法
        setName.invoke(user3,"李四");
        System.out.println(user3.getName());
        System.out.println("==========================");
        /*获得字段*/
        //1.创建一个对象
        User user4 = (User) aclass.newInstance();
        //2. 获得要使用的字段(成员变量)
        Field age = aclass.getDeclaredField("age");
        //3.解决办法:调用setAccessible(true)方法 则可以访问私有
        age.setAccessible(true);
        age.set(user4,21);
        System.out.println(user4.getAge());
    }
}
setAccessible( )
  • 作用:启动和禁用访问安全检查的开关。
    • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查
    1. 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
    2. 使得原本无法访问的私有成员也可以访问
    • 参数值为false则指示反射的对象应该实施Java语言访问检查

测试:是否关闭检查测试性能

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class demo9 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        //测试性能
        test1();
        test2();
        test3();
    }
    public static void test1(){
        User user = new User();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long end = System.currentTimeMillis();
        System.out.println("普通调用:"+(end-start)+"毫秒");
    }
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class aClass = user.getClass();
        Method getName = aClass.getDeclaredMethod("getName");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user,null);
        }
        long end = System.currentTimeMillis();
        System.out.println("反射调用:"+(end-start)+"毫秒");
    }
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class aClass = user.getClass();
        Method getName = aClass.getDeclaredMethod("getName");
        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("反射关闭检查调用:"+(end-start)+"毫秒");
    }
}——————————输出:普通调用:3毫秒       电脑有些快哦哈哈哈
		   反射调用:2172毫秒
		   反射关闭检查调用:1052毫秒

反射获取泛型

  • 泛型作用:确保数据的安全性免去强制类型转换问题 ————若编译完成 所有和泛型有关的类型全部擦除
  • 为了通过反射操作这些类型 , Java新增了几种类型来代表不能被归一到Class类中的类型但是又和原 始类型齐名的类型
    1. ParameterizedType : 表示一种参数化类型,比如Collection
——getActualTypeArguments() ——返回表示此类型实际类型参数的 Type 对象的数组。
    1. GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型
    1. TypeVariable : 是各种类型变量的公共父接口
    1. WildcardType : 代表一种通配符类型表达式

Method类

getGenericParameterTypes() ——返回Type对象数组 获得方法的形参类型
getParameterTypes() ——返回Class对象数组 获得方法的形参类型
getGenericReturnType() ——返回Type对象 获得方法的返回值类型
getReturnType() ——返回Class 对象 获得方法返回值类型

练习:反射获取泛型类型

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 demo10 {
    public static void main(String[] args) throws Exception {
        //反射获取泛型信息
        Method method = demo10.class.getMethod("test1", 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 method1 = demo10.class.getMethod("test2");
        Type genericReturnType = method1.getGenericReturnType();
        if(genericReturnType instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            System.out.println("返回值:"+actualTypeArguments);
        }
    }
    public void test1(Map<String,User> map,List<User> list){
        System.out.println("1111");
    }
    public Map<Integer,User> test2(){
        System.out.println("2222");
        return null;
    }
}

反射获取注解信息

练习:反射获取注解信息

import java.lang.annotation.*;
import java.lang.reflect.Field;
public class demo11 {
    public static void main(String[] args) throws Exception {
        Class aClass = Class.forName("反射.Student2");
        //获得类的注解信息
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        // 获得类的注解的名字
        lei lei = (反射.lei) aClass.getAnnotation(lei.class);
        System.out.println(lei.value());
        //获得类中字段的注解信息
        Field name = aClass.getDeclaredField("name");
        ziduan ziduan = (ziduan)name.getAnnotation(ziduan.class);
        System.out.println(ziduan.name());
        System.out.println(ziduan.type());
        System.out.println(ziduan.length());
    }
}
@lei("db_Student")
class Student2{
    @ziduan(name = "db_id",type = "int",length = 10)
    private int id;
    @ziduan(name = "db_name",type = "String",length = 5)
    private String name;
    @ziduan(name = "db_age",type = "int",length = 5)
    private int age;

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

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//定义类的注解
@Target(ElementType.TYPE) // 定义注解起作用的范围
@Retention(RetentionPolicy.RUNTIME) // 定义注解起作用的时间
@interface lei{
    String value();
}
// 定义字段的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface ziduan{
    String name();
    String type();
    int length();
}

你可能感兴趣的:(JAVA入门————反射机制Reflection AND JAVA内存分析)