首页 > 其他分享 >反射

反射

时间:2022-09-22 14:26:06浏览次数:54  
标签:反射 对象 class Student 方法 Class 加载

java是一门编译型语言;与之对应的称之为解释性(JavaScript,python)。编译型语言在编写完源代码后必须要编译之后才能够运行。解释性语言内置了解释器,程序一边解释,一边执行。 java语言编译之后产生.class字节码文件。字节码文件包含了对类的定义(类的名字,类的属性,类的方法,类实现的接口,继承的父类,使用了什么注解)。

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

什么是类的结构信息

.java文件经过javac指令编译后生成.class字节码文件中保存了类的结构信息;一个class文件描述了类的具体信息;(类名,父类,实现的接口,属性,构造方法,实例方法,注解等)

什么是类加载机制

java虚拟机把描述类结构信息的.class文件加载到方法区,并对数据(.class文件)进行校验,转换解析和初始化的过程称为类加载。加载到方法区的类已Class<?>类的对象存在。Class类的对象我们不能够直接实例化。

什么时候触发类的加载

遇到new,getStatic,putStatic,invokeStatic指令时,如果该类的类型还没有进行过初始化,则需要触发其初始化阶段。

 

反射提供的功能

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

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

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

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

  • 生成动态代理 

     

类加载的过程:

加载”只是“类加载”过程的一个阶段,在加载阶段,虚拟机需要完成以下3件事情:

  • 通过一个类的全限定名(包名.类名)来获取定义此类的二进制字节流(字节码文件);

  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;

  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。该Class类对象没有明确规定是在Java堆中,对于HotSpot虚拟机而言,Class对象比较特殊,它虽然是对象,但是存放在方法区里面。

对于数组类而言,数组类本身不通过类加载器创建,它是由Java虚拟机直接创建的,但是数组类的元素类型(Element Type,是指数组去掉所有维度的类型)最终要靠类加载器去创建,一个数组类(简称为C)创建过程要遵循以下规则:

  • 如果数组的组件类型(Component Type,指的是数组去掉一个维度的类型)是引用类型,则递归地加载这个组件类型,数组C将在加载该组件类型的类加载器的类名称空间上被标识。

  • 如果数组的组件类型不是引用类型(例如int[]数组),则Java虚拟机将会把数组C标记为与引导类加载器关联。

  • 数组类的可见性与它的组件类型的可见性一致,如果组件类型不是引用类型,那数组类的可见性将默认为public

双亲委派模型

双亲委派模型的目的是为了避免重复加载class文件到方法区。

/*
此方法来自于java.lang.ClassLoader的源码,负责从类加载器管理的路径下加载class文件到方法区
*/
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {//上锁,多线程章节
            // 第一步,检查name对应的class是否已经被加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) { //该class尚未被加载到方法区
                long t0 = System.nanoTime();
                try {
                    //如果存在父类加载器,则从父类加载器中查找class
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        //parent为null,则说明从启动类加载器(BootstrapClassLoader)查找class
                        //如果启动类加载器中找到了该class,则返回,否则返回null
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
​
                //检测父类加载器是否加载到class
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    //在当前的类加载器中查找class
                    c = findClass(name);
​
                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            //返回class对象,有可能是一个null
            return c;
        }
    }

Class

JVM通过ClassLoader类加载器将指定路径下的class文件加载到jvm方法区时,通过Class对象来表示具体所加载到的class文件。

举例:现有Student.class,Employee.class, Order.class, Uesr.class

当jvm加载如上这些类时,会为每一个类产生一个Class对象。通过泛型来表示其类型。

//jvm方法区中表示Student类
Class<Student> stuClass; //Class对象保存的是类的结构信息
Class<Employee> empClass;
Class<Order> orderClass;
Class<User> userClass;
​
//根据类的结构信息实例化Student对象
Student stu = new Student();
  • Class本身也是一个类

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

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

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

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

  • 通过Class可以完整地得到一个类中的完整结构

    一个类的结构:(属性,方法,构造方法,父类,接口,注解)

     

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

获取Class类对象的几种方式

 //Student位于com.hxzy.bean包中,点相当于磁盘目录的分隔符。com/hxyz/bean/Student.java
    package com.hxzy.bean;
    
    class Student{
        private String name;
        //setter and getters
        
        public Student(){}
        public Student(String name){
            this.name = name;
        }
        
        public static void main(String[] args){
            //通过类名.class得到Student在JVM中的class信息
            Class<Student> claz = Student.class;
            
            //通过对象.getClass();
            Student stu = new Student();
            Class<Student> claz2 = stu.getClass();
            
            //通过类的完整路径获取Class对象,很多框架也是利用了这种方式来实现的
            //类的完整路径=包名.类名
            String path = "com.hxzy.bean.Student";
            Class<Student> aClass1 = (Class<Student>) Class.forName(path);
        }
    }
    

Class类的常用方法

方法描述
forName(String) 根据类的完整名称获取其Class
newInstance() 通过类的无参构造实例化对象
getName() 返回Class对应类的完整类名
getConstructor() 根据参数列表得到具体的构造函数
getConstructors() 得到这个类所有的构造函数
getDeclaredFields() 得到这个类中所有的属性
getFields() 得到这个类中所有的公共的属性
getField(String name) 获取这个类中指定名字的公共的属性
getDeclaredField(String name) 获取这个类中任意访问修饰符的属性
getDeclaredMethods() 得到这个类中所有的方法
getMethods() 得到这个类中所有的公共的方法
getDeclaredMethod() 根据方法名获取任意方法的对象
getMethod() 根据方法名获取公共的方法

通过反射实例化对象

    Class claz = Student.class;
    //通过Student类的无参构造方法实例化Student类的对象
    Object obj = claz.newInstance();

通过反射获取构造函数

在反射中,一个类中的构造函数可以通过Constructor的对象表示。 Constructor类的常用方法:

方法描述
getModifiers() 获取访问修饰符
getName() 获取构造方法的名称
getParameterCount() 获取参数列表的个数
getParameterTypes() 获取参数列表的类型
newInstance(Object... initargs) 通过构造方法实例化对象

通过反射获取属性Field

通过反射能够得到类中任何属性,其访问修饰符,属性名,属性的类型,为属性赋值,获取属性的值;在反射中,一个属性就是一个Field的对象

方法描述
get(Object) 获取某个对象上该属性的值
getModifiers() 获取改属性的访问修饰符
getName() 获取属性名
set(Object obj, Object value) 为某个对象的该属性赋一个值
getType() 获取该属性的类型
setAccessible(boolean) 设置私有的属性可以被访问

通过反射获取方法

通过反射能够获取到类中所有的方法,方法名,方法的返回值类型,方法的参数列表,执行方法等等。在反射中,一个方法就是一个Method的对象。

方法描述
getModifiers() 获取方法的访问修饰符
getName() 获取方法名
getParameterCount() 获取参数的个数
getParameterTypes() 获取参数的类型
getReturnType() 获取返回值类型
invoke(Object obj, Object... args) 执行此方法
setAccessible(boolean) 设置私有的方法可以被访问

标签:反射,对象,class,Student,方法,Class,加载
From: https://www.cnblogs.com/huang2979127746/p/16719067.html

相关文章

  • UE反射机制
    UPROPERTY:1.EditAnywhere:在编辑中可见,且可编辑2.VisibleAnywhere:在编辑中可见,且不可编辑3.EditDefaultsOnly:只在类默认设置中可见4.BlueprintReadOnly:蓝图只读5.Bl......
  • C# Sql多字段插入(反射!)
    publicboolInsert(objectobj){Typetype=obj.GetType();PropertyInfo[]properties=type.GetProperties();st......
  • 反射(Reflection)的概念
    反射指程序可以访问、检测和修改它本身状态或行为的一种能力。程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射......
  • 手把手教你:轻松打造沉浸感十足的动态漫反射全局光照
    一个沉浸感十足的游戏,其场景中的全局光照效果一定功不可没。动态漫反射全局光照(DDGI)带来的光影变化,是细腻延展的视觉语言,让场景中每种颜色都有了“五彩斑斓”的诠释,场景布......
  • 利用注解+反射优雅的实现通用Excel导入导出
    2019/3/12更新日常在做后台系统的时候会很频繁的遇到Excel导入导出的问题,正好这次在做一个后台系统,就想着写一个公用工具来进行Excel的导入导出。一般我们在导出的时候......
  • matlab练习程序(Householder光线反射)
    已知入射光线向量X和平面方程法向量w,可以通过Householder变换求出反射向量Y。Householder变换公式如下:那么反射向量Y=H*Xmatlab代码如下:clearall;closeall;clc;%......
  • 13.1 反射 13.2selenium键盘事件13.3文件上传13.4滚动条操作 13.5鼠标事件13.6验证码
    13.1反射#什么是反射?#如果有一个变量名,是字符串的数据类型,你能获取到这个变量的值吗?#反射方法:classStudent:def__init__(self):self.name='张三'......
  • java复习随笔(十四)——类加载器、反射
    类加载器类加载当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤来对类进行初始化。如果不出现意外状况,JVM将会连续完......
  • java基础学习:java中的反射
    一、什么是java反射什么是java的反射?说到反射,写这篇文章时,我突然想到了人的”反省“,反省是什么?吾一日三省吾身,一般就是反思自身,今天做了哪些对或错的事情。java的反......
  • 反射获取参数名-设置编译器
    这是编译器参数原因:由于反射机制默认获取不到一个方法的参数名,即:反射机制通过Method获取到参数后,再得到参数名时返回的字符串为arg0,arg1,arg2....但是在编译器中添加......