图文详解Java的反射机制

目录

  • 1.什么是反射
  • 2.Hello,java反射
  • 3.java程序运行的三个阶段
  • 4.反射相关类
  • 5.反射的优化
  • 6.Class类分析
  • 7.获取Class对象的六种方式
  • 8.类加载机制
    • 动态加载和静态加载
    • 类加载流程概述
    • 加载阶段
    • 连接阶段
    • 初始化
  • 9.通过反射获取类的结构信息

    1.什么是反射 反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。
    加载类后,在堆中就产生了一个class类型的对象,这个对象包含了类的完整结构的信息,通过这个对象得到类的结构。这个class对象就像一面镜子,透过这个镜子可以看到类的结构,所以形象的称之为“反射”
    反射机制是框架的灵魂,一个java程序员不能不会使用反射,没有反射机制,java将一无是处

    2.Hello,java反射 使用实例:
    Cat类:
    public class Cat {private String name; private String age; public void hi() {System.out.println("喵喵喵~"); }}

    测试类:
    import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 反射入门 * 通过字符串形式的类的路径和方法信息调用类的方法 */public class reflectionTest {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {// 类的路径String classPath = "reflection.Cat"; // 要执行类的方法名称String classMethod = "hi"; // 加载类Class cls = Class.forName(classPath); // 通过cls得到你加载的类Cat的对象实例Object o = cls.newInstance(); // 查看o的运行类型,为Cat类型System.out.println(o.getClass()); // 得到加载的类的方法对象// 在反射中,可以把方法视为对象Method method = cls.getMethod(classMethod); // 通过method实例调用方法:即通过方法对象来实现调用方法method.invoke(o); }}

    输出:
    class reflection.Cat
    喵喵喵~

    3.java程序运行的三个阶段 反射的基本原理:
    图文详解Java的反射机制
    文章图片


    4.反射相关类 图文详解Java的反射机制
    文章图片

    现在我们来完善一下上面的测试类:
    import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 反射入门 * 通过字符串形式的类的路径和方法信息调用类的方法 */public class reflectionTest {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {// 类的路径String classPath = "reflection.Cat"; // 要执行类的方法名称String classMethod = "hi"; // 加载类Class cls = Class.forName(classPath); // 通过cls得到你加载的类Cat的对象实例Object o = cls.newInstance(); // 查看o的运行类型,为Cat类型System.out.println(o.getClass()); // 得到加载的类的方法对象// 在反射中,可以把方法视为对象Method method = cls.getMethod(classMethod); // 通过method实例调用方法:即通过方法对象来实现调用方法method.invoke(o); // 得到name字段的信息// 注意:getField不能得到私有的属性信息Field nameField = cls.getField("name"); System.out.println(nameField.get(o)); // 得到构造器Constructor constructor = cls.getConstructor(); System.out.println(constructor); }}

    输出:
    class reflection.Cat
    喵喵喵~
    豹猫
    public reflection.Cat()

    5.反射的优化 反射调用方法的效率比普通方法调用的效率低很多
    在使用反射调用方法时,可以关闭安全访问检测,这样会提高反射调用的效率
    例如:下面是一个实例:
    // 在反射中,可以把方法视为对象Method method = cls.getMethod(classMethod); // 在反射调用方法时,取消访问检测method.setAccessible(true); // 通过method实例调用方法:即通过方法对象来实现调用方法method.invoke(o);


    6.Class类分析 Class也是类,因此也继承Object类
    Class对象不是new出来的,而是系统创建的(通过loadClass方法)
    public Class loadClass(String name) throws ClassNotFoundException {return loadClass(name, false); }

    对于某个类的Class对象,在内存中只有一份,因为类只加载一次
    每个对象实例都会记录自己是由哪一个Class实例生成的
    通过Class对象可以完整的得到一个类的结构
    Class对象存在于堆中
    类的字节码二进制数据是放在方法区里面的,有的地方称为类的元数据
    Class对象方法演示:
    实例
    Cat类:
    public class Cat {public String name = "豹猫"; public String age; public void hi() {System.out.println("喵喵喵~"); }@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age='" + age + '\'' +'}'; }}

    ClassMethod类:
    import java.lang.reflect.Field; /** * 演示Class类的常用方法 */public class ClassMethod {public static void main(String[] args) throws Exception {String classAllPath = "reflection.Cat"; // 获取Cat类对应的Class对象Class aClass = Class.forName(classAllPath); // 显示aClass对象是哪一个类的Class对象System.out.println(aClass); // 输出aClass对象的运行类型System.out.println(aClass.getClass()); // 得到包名System.out.println(aClass.getPackage().getName()); // 得到全类名System.out.println(aClass.getName()); // 创建对象实例Cat cat = (Cat) aClass.newInstance(); System.out.println(cat); // 通过反射获取属性Field name = aClass.getField("name"); System.out.println(name.get(cat)); // 通过反射给属性设置值name.set(cat,"汤圆"); System.out.println(name.get(cat)); // 得到所有的属性Field[] fields = aClass.getFields(); for (Field field : fields) {System.out.println(field.getName()); }}}

    输出:
    class reflection.Cat
    class java.lang.Class
    reflection
    reflection.Cat
    Cat{name='豹猫', age='null'}
    豹猫
    汤圆
    name
    age

    7.获取Class对象的六种方式 获取Class对象细分可以分为六种方式:
    现在我们使用代码进行演示:
    /** * 获取Class对象的六种方式 */public class GetClass {public static void main(String[] args) throws ClassNotFoundException {String classAllPath = "reflection.Cat"; // 1.forName获取。多用于配置文件读取类的全路径,加载类// 2.类名.class。多用于参数传递System.out.println(String.class); System.out.println(Cat.class); // 3.对象.getClass。适用于已经存在对象实例的情况Cat cat = new Cat(); System.out.println(cat.getClass()); // 4.通过类加载器获取Class对象// (1)得到类加载器ClassLoader classLoader = cat.getClass().getClassLoader(); // (2)通过类加载器得到Class对象Class cls = classLoader.loadClass(classAllPath); System.out.println(cls); // 5.基本数据类型通过.class获取Class对象Class integerClass = int.class; Class characterClass = char.class; Class booleanClass = boolean.class; System.out.println(integerClass); // 6.基本数据类型的包装类可以通过.TYPE得到Class对象Class type = Integer.TYPE; System.out.println(type); }}

    输出:
    class java.lang.String
    class reflection.Cat
    class reflection.Cat
    class reflection.Cat
    int
    int
    那么,那些类型拥有Class对象呢?
    • 外部类
    • 接口
    • 数组(含二维数组)
    • 注解
    • 枚举
    • 基本数据类型
    • 包装类
    • 成员内部类

    8.类加载机制
    动态加载和静态加载
    静态加载:
    在编译时加载的类,如果没有则直接报错,依赖性太强
    动态加载:
    运行时加载相应的类,如果运行时没有用到相应的类,则不会进行加载,改善了依赖性的问题
    通过new创建实例的方式就是典型的静态加载,通过反射创建对象是典型的动态加载
    类加载时机:
    • 创建对象时
    • 子类被加载
    • 调用类中的静态成员时
    • 通过反射(动态加载)

    类加载流程概述
    类加载的三个阶段:
    图文详解Java的反射机制
    文章图片

    类加载后的内存布局:
    图文详解Java的反射机制
    文章图片

    整体布局:
    图文详解Java的反射机制
    文章图片


    加载阶段
    JVM在该阶段的主要目的是将字节码从不同的数据源转化为二进制字节流加载到内存中,并生成一个代表该类的Class对象

    连接阶段
    验证:
    目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,不会危害虚拟机自身的安全
    包括:文件格式的验证,元数据验证,字节码验证,符号引用验证
    准备:
    JVM会在该阶段对静态变量分配内存并默认初始化(分配默认值)。这些变量所使用的内存都将在方法区中进行分配
    解析:
    虚拟机将常量池内的符号引用替换为直接应用的过程

    初始化
    ()方法依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并
    虚拟机会保证一个类的()方法在多线程环境中被正确的加锁同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法。其他线程都要阻塞等待

    9.通过反射获取类的结构信息 我们使用一段程序来演示所有的常用方法:
    import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 通过反射获取类的结构信息 */public class ReflectionUtils {public static void main(String[] args) throws ClassNotFoundException {// 得到Class对象Class personCls = Class.forName("reflection.Person"); // 得到全类名System.out.println(personCls.getName()); // 得到简单类名System.out.println(personCls.getSimpleName()); // 获取所有的public修饰的属性,包含父类的Field[] fields = personCls.getFields(); for (Field field : fields) {System.out.println(field.getName()); }// 获取本类的所有属性,不包含父类Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) {// 打印属性名字和等级和类型// 默认:0,public:1,private:2,protected:4,static:8,final:16System.out.println(declaredField.getName() + "\t" +declaredField.getModifiers() + "\t" +declaredField.getType()); }// 获取所有public方法,包含父类的Method[] methods = personCls.getMethods(); for (Method method : methods) {System.out.println(method.getName()); }// 获取本类的所有方法和等级和返回类型和参数类型数组Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod.getName() + "\t" +declaredMethod.getModifiers() + "\t" +declaredMethod.getReturnType()); // 获取方法的参数类型数组Class[] parameterTypes = declaredMethod.getParameterTypes(); for (Class parameterType : parameterTypes) {System.out.println(parameterType); }}// 获取所有的public构造器,不包含父类的Constructor[] constructors = personCls.getConstructors(); for (Constructor constructor : constructors) {System.out.println(constructor.getName()); }// 获取所有的构造器,包含私有的,还有构造器的参数类型Constructor[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor.getName()); Class[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class parameterType : parameterTypes) {System.out.println(parameterType); }}// 返回包信息System.out.println(personCls.getPackage()); // 以Class形式返回父类的信息Class superclass = personCls.getSuperclass(); System.out.println(superclass); // 以Class形式返回接口信息Class[] interfaces = personCls.getInterfaces(); for (Class anInterface : interfaces) {System.out.println(anInterface.getName()); }// 返回注解信息Annotation[] annotations = personCls.getAnnotations(); for (Annotation annotation : annotations) {System.out.println(annotation); }}}interface IA {}interface IB {}@Deprecatedclass Person extends Something implements IA, IB {public String name; protected int level; private int age; String job; public Person() {}public Person(String name) {this.name = name; }private Person(String name, int level, int age, String job) {this.name = name; this.level = level; this.age = age; this.job = job; }public void show(String content, int code) {}protected void hi() {}void say() {}private void hei() {}}class Something {public String hobby; }

    【图文详解Java的反射机制】以上就是图文详解Java的反射机制的详细内容,更多关于Java反射机制的资料请关注脚本之家其它相关文章!

      推荐阅读