当前位置: 首页 > 后端技术 > Java

Java笔记(十)

时间:2023-04-01 18:02:19 Java

类加载器、反射与模块化一、类加载器1.类加载当程序要使用一个类时,如果该类还没有被加载到内存中,系统会通过该类的三个步骤加载、类连接、类初始化都是对类进行初始化。如果没有意外情况,JVM会连续完成这三个步骤,所以有时这三个步骤统称为类加载或类初始化类加载:是指将类文件读入内存,并为其创建一个类文件.java.lang.Class对象●当任何一个类被使用时,系统都会为其建立一个java.lang.Class对象类的连接:●验证阶段:用于检查加载的类是否具有正确的内部结构,并与other类协调准备阶段:负责为类的类变量分配内存,并设置默认初始化值解析阶段:将类二进制数据中的符号引用替换为类初始化的直接引用:该阶段主要针对类变量被初始化。类初始化步骤:如果类还没有加载连接,程序先加载连接类。如果该类的直接父类还没有初始化,则先初始化它的直接父类。如果类中有初始化语句,系统会一条一条地执行这些初始化语句。注意:在执行第二步时,系统在执行初始化步骤1-3时,也遵循直接父类的初始化步骤。类的类方法●访问类或接口的类变量,或为类变量赋值●利用反射强制创建某个类或接口对应的java.lang.Class对象●初始化类的子类某个类●直接使用java.exe命令运行一个主类2.类加载器类加载器的作用:●负责将.class文件加载到内存中,并为其生成相应的java.lang.Class对象。●虽然我们不需要太在意类加载机制,但是如果了解了这个机制,我们就可以更好地理解运行程序的JVM的类加载机制:全责:当一个加载器负责加载某个类时,Otherdependentandreferencedclasses也将被这个类加载器加载,除非使用另一个类加载器来加载。父类委托:当一个类加载器负责加载某个Class时,让父类加载器先尝试加载该Class,只有当父类加载器无法加载该类时才尝试从自己的类路径加载该类.●缓存机制:保证所有加载的Class都会被缓存。当程序需要使用某个Class对象时,类加载器首先从缓存区中查找该Class。只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,转换为Class对象,存入缓冲区。ClassLoader:是负责加载类的对象Java运行时有以下内置的类加载器:●Bootstrap类加载器:是虚拟机内置的类加载器,通常表示为null,没有父级null。●平台类加载器:平台类加载器可以看到所有的平台类。平台类包括由平台类加载器或其祖先定义的JavaSE平台API、实现类和特定于JDK的运行时类。●系统类加载器:又称应用类加载器,与平台类加载器不同。系统类加载器通常用于在应用程序类路径、模块路径和JDK特定工具上定义类。●类加载器的继承关系:System的父加载器是Platform,Platform的父加载器是Bootstrap。ClassLoader中的两个方法:StaticClassLoadergetSystemClassLoader():返回系统类加载器进行委托ClassloadergetParent():返回父类加载器进行委托二、反射一、反射概述Java反射机制:指Runtime获取变量和方法一个类的信息。然后使用获得的信息创建对象并调用方法的机制。由于这种动态性,可以大大增强程序的灵活性。程序不需要在编译时确定,但在运行时仍然可以扩展。2、获取Class类的对象。如果我们要通过反射使用一个类,首先需要获取该类的字节码文件对象,即Class类型的对象。这里我们提供了三种获取Class类型对象的方法。:●使用类的class属性获取该类对应的Class对象。示例:Student.class将返回Student类对应的Class对象●调用对象的getClass()方法返回对象所属类对应的Class对象。这个方法是Object类中的一个方法,所有的Java对象都可以调用这个方法。●在Class类中使用静态方法forName(StringclassName),该方法需要传入一个字符串参数,字符串参数的值为某个类的全路径,即完整包的路径姓名。3.反射获取构造函数,使用Class类中获取构造函数的方法Constructor[]getConstructors():返回所有public构造函数对象的数组Constructor[]getDeclaredConstructors():返回所有构造函数对象数组ConstructorgetConstructor(Class...parameterTypes):返回单个公共构造函数对象ConstructorgetDeclaredConstructor(Class...parameterTypes):返回在Constructor类创建对象的方法:●Tnewlnstance(Object....initargs):根据指定的构造方法创建对象。基础数据类型可以通过.class得到对应的Class类型。publicvoidsetAccessible(booleanflag):如果值为真,则取消访问检查。4.通过反射获取成员变量,使用Class类中获取成员数量的方法Field[]getFields():返回所有public成员变量对象的数组Field[]getDeclaredFields():返回所有成员变量对象的数组FieldgetField(Stringname):返回单个公共成员变量对象FieldgetDeclaredField(Stringname):返回单个成员变量对象Field类中用于给成员赋值的方法:voidset(Objectobj,Objectvalue):给obj对象赋值为value5的成员变量。反射获取成员方法,使用Class类中用于获取成员方法的方法Method[]getMethods():返回所有public成员方法对象的数组,包括继承的Method[]getDeclaredMethods():返回一个数组所有成员方法对象,不包括继承的方法getMethod(Stringname,Class..parameterTypes):返回单个公共成员方法对象MethodgetDeclaredMethod(Stringname,Class..parameterTypes):返回用于调用单个成员方法对象的Method类中的成员方法:Objectinvoke(Objectobj,Object...args):调用obj对象的成员方法,参数为args,返回值为Object类型3.模块1.模块的基本使用模块的基本使用步骤●创建模块(创建模块、创建包、创建类、定义方法按照前面的解释)为了体现模块的使用,我们创建2个模块。一个是myOne,另一个是myTwo。●在模块的src目录下创建名为module-info.java的描述文件,具体定义了模块名称、访问权限、模块依赖等信息。模块导出和模块依赖在描述文件中配置使用。●模块内所有未导出的包都是模块私有的,模块外无法访问。在myOne模块下的描述文件中配置模块导出模块导出格式:exports包名;●一个模块需要被访问对于其他模块,必须明确指定要依赖哪些模块。无法访问未明确指定依赖项的模块。在myTwo模块下的描述文件中配置模块依赖。模块依赖格式:需要模块名;注意:写模块名报错,需要按Alt+Enter提示,然后选择moduledependency。在myTwo模块的类中使用依赖模块下的内容。2.使用模块服务模块服务使用步骤在myOne模块下创建一个包com.iheima_03,并在该包下提供一个接口,其中定义了一个抽象方法publicinterfaceMyService{voidservice();在com.itheima_03包下创建包impl,在myOne模块下提供接口的两个实现类Itheima和Czxy,在描述文件中添加如下配置:moduleexport:exportscom.itheima_03;服务提供:用Itheima提供MyService;指定MyService的服务实现类为Itheima在myTwo模块下的描述文件中添加如下配置:declareserviceInterface:usesMyService;使用myTwo模块类中MyService接口提供的服务ServiceLoader:加载服务实现的工具