18_类加载

文章目录

  • 类加载器
    • 类加载时机
    • Java代码的3个阶段
  • 反射
    • 关于Class
    • 配置文件(.properties)
      • Properties类
      • 通过反射获取构造方法(Constructor)
      • 通过反射获取成员变量(Field)
      • 通过反射获取成员方法(Method)
  • 其他API
  • 自定义类加载器
  • 反射的应用

类加载器

分类

  • Bootstrap ClassLoader 根类加载器

    • 负责Java运行时核心类的加载,JDK中JRE的lib目录下rt.jar
  • Extension ClassLoader 扩展类加载器

    • 负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录
  • Sysetm(App) ClassLoader 系统类加载器/应用加载器

    • 负责加载自己定义的Java类

逻辑上的父子关系

在这里插入图片描述

类加载时机

  • 创建类的实例(首次创建该类对象)

  • 访问类的静态变量(首次)

  • 调用类的静态方法(首次)

  • 加载某个类的子类,会先触发父类的加载

  • 直接使用java.exe命令来运行某个主类,也就是执行了某个类的main()方法

  • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

Java代码的3个阶段

在这里插入图片描述


反射

获取运行时类信息的一种手段,反射的起点是字节码文件对象

获取字节码文件对象的几种方式

  • 对象.getClass()
  • 类名.class
  • Class.forName(String className) 全限定名
  • ClassLoader里的loadClass(String className)

无论通过什么方式获取的字节码文件对象,都是同一个

eg:


public class Demo {public static void main(String[] args) throws ClassNotFoundException {// 对象.getClass()A a = new A();Class<? extends A> c1 = a.getClass();// 类名.classClass<A> c2 = A.class;System.out.println(c1 == c2);// Class.forName(String className)  全限定名Class<?> c3 = Class.forName("com.cskaoyan.Demo0112.A");System.out.println(c1 == c3);// ClassLoader里的loadClass(String className)ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();Class<?> c4 = systemClassLoader.loadClass("com.cskaoyan.Demo0112.A");System.out.println(c1 == c4);}
}class A{}

  • 类名.class 没有执行静态代码块
  • Class.forName() 执行静态代码块

eg:


@Testpublic void test1() throws ClassNotFoundException {// 类名.class// 没有执行静态代码块Class<B> b1 = B.class;// Class.forName()// 执行静态代码块Class<?> b2 = Class.forName("com.cskaoyan.Demo0112.B");}class B{static{System.out.println("this is static");}
}

关于Class

  • Class 类的实例表示正在运行的 Java 应用程序中的类和接口

  • Class 没有公共构造方法Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

配置文件(.properties)

  • 配置文件的几种格式.properties.xml.yml

  • 配置文件的作用: 放配置信息的 (数据库的, 第三方服务的配置信息)

  • .properties的格式:

    • 键值对(key-value)
    • key=value
    • key不能重复的
    • 注释#
    • 文件里面全是String

Properties类

  • Properties 类表示了一个持久的属性集
  • Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串

文件 ---> 资源包创建可得

eg:


# 数据库的配置信息
url=jdbc:mysql://localhost:3306/test
host=localhost
port=3306
user= root
password=1234567

构造方法


Properties()    // 创建一个无默认值的空属性列表。

成员方法

在这里插入图片描述

在这里插入图片描述

eg:


public class Demo {public static void main(String[] args) throws IOException {// 1. 创建Properties对象Properties properties = new Properties();// 2. loadproperties.load(new FileInputStream("People.properties"));// 3. 获取属性值// getProperty(String key)String port = properties.getProperty("port");String user = properties.getProperty("user");String password = properties.getProperty("password");String host = properties.getProperty("host");System.out.println(port);System.out.println(password);System.out.println(user);System.out.println(host);}
}


public class Demo {public static void main(String[] args) throws IOException {// 1. 创建Properties对象Properties properties = new Properties();// 2. 通过类加载器URL systemResource = ClassLoader.getSystemResource("");System.out.println(systemResource); // "" 在这里面,把"People.properties"应该放这里输出的路径下面InputStream in = ClassLoader.getSystemResourceAsStream("People.properties");// 3. loadproperties.load(in);// 4. 获取属性值// getProperty(String key)String port = properties.getProperty("port");String user = properties.getProperty("user");String password = properties.getProperty("password");String host = properties.getProperty("host");System.out.println(port);System.out.println(password);System.out.println(user);System.out.println(host);}
}

输出中文的情况


public class Demo {public static void main(String[] args) throws IOException {// 创建Properties对象Properties properties = new Properties();// loadproperties.load(new InputStreamReader(new FileInputStream("People.properties"),"GBK"));// 获取属性String user = properties.getProperty("user");System.out.println(user);}
}

通过反射获取构造方法(Constructor)

通过反射获取所有构造方法

Constructor[] getConstructors() // 获取的是public的构造方法Constructor[] getDeclaredConstructors() // 获取所有的构造方法

获取指定构造方法

Constructor<T> getConstructor(Class<?>... parameterTypes)Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

使用Constructor创建对象

Person p = new Person("zs",20,true)newInstance(参数列表)

暴力破解

上面的方法创建不了private的对象,这里可以

setAccessible(true) // 忽略java语法检查

先定义一个Person类


public class Person {public String name;private int age;boolean gender;public Person(String name, int age, boolean gender) {this.name = name;this.age = age;this.gender = gender;}private Person(String name, int age) {this.name = name;this.age = age;}public Person(String name) {this.name = name;}public Person() {}public void eat() {System.out.println("eat food");}private void eat(String food) {System.out.println("eat" + food);}private String sleep() {return "sleep";}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender=" + gender +'}';}
}

eg:


public class Demo {public static void main(String[] args)throws ClassNotFoundException, NoSuchMethodException,InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 获取字节码文件对象Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");// 2. 获取所有的构造方法// Constructor[] getConstructors()Constructor<?>[] constructors = a1.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}// Constructor[] getDeclaredConstructors()Constructor<?>[] declaredConstructors = a1.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor);}// 3. 获取指定构造方法// Constructor<T> getConstructor(Class<?>... parameterTypes)Constructor<?> constructor = a1.getConstructor(String.class, int.class, boolean.class);System.out.println(constructor);// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)Constructor<?> declaredConstructor = a1.getDeclaredConstructor(String.class, int.class);System.out.println(declaredConstructor);// 4. 使用Constructor创建对象// 通过构造方法对象创建对象//newInstance(参数列表)Object o = constructor.newInstance("zs", 20, true);System.out.println(o);// 5. setAccessible(true)declaredConstructor.setAccessible(true);Object o1 = declaredConstructor.newInstance("ww", 18);System.out.println(o1);}
}

通过反射获取成员变量(Field)

通过反射获取所有成员变量

Field[] getFields()Field[] getDeclaredFields()

获取指定成员变量

Field getField(String name) // 获取的是public权限Field getDeclaredField(String name) // 获取的是所有权限

通过Field读写对象的成员变量(可暴力破解)

Object get(Object obj)  // 获取值,传入对象void set(Object obj, Object value)  // 赋值,传入对象

eg:


public class Demo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 拿到字节码文件对象Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");// 2. 通过反射获取所有的成员变量// Field[] getFields()Field[] fields = a1.getFields();for (Field field : fields) {System.out.println(field);}// Field[] getDeclaredFields()Field[] declaredFields = a1.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println(declaredField);}// 3. 获取指定成员变量// Field getField(String name)Field nameField = a1.getField("name");System.out.println(nameField);// Field getDeclaredField(String name)Field ageField = a1.getDeclaredField("age");System.out.println(ageField);// 4. 通过Field读写对象的成员变量(可暴力破解)// void set(Object obj, Object value):赋值,传入对象Constructor<?> declaredConstructor = a1.getDeclaredConstructor();Object o = declaredConstructor.newInstance();nameField.set(o,"zs");System.out.println(o);// Object get(Object obj):获取值,传入对象Object o1 = nameField.get(o);System.out.println(o1);}
}

通过反射获取成员方法(Method)

获取所有成员方法

Method[] getMethods()// 父类的也能获取到,只能获取public的方法Method[] getDeclaredMethods() // 能够获取所有的方法

获取指定的成员方法

Method getMethod(String name, Class<?>... parameterTypes)Method getDeclaredMethod(String name, Class<?>... parameterTypes)

利用Method调用对象的方法

Object invoke(Object obj, Object... args)

eg:


public class Demo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {// 1. 获取字节码文件对象Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");// 2. 获取所有成员方法// Method[] getMethods()// 父类的也能获取到Method[] methods = a1.getMethods();for (Method method : methods) {System.out.println(method);}// Method[] getDeclaredMethods()Method[] declaredMethods = a1.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}// 3. 获取指定的成员方法// Method getMethod(String name, Class<?>... parameterTypes)Method eatMethod = a1.getMethod("eat");System.out.println(eatMethod);// Method getDeclaredMethod(String name, Class<?>... parameterTypes)Method eatDeclaredMethod = a1.getDeclaredMethod("eat", String.class);System.out.println(eatDeclaredMethod);// 利用Method调用对象的方法// Object invoke(Object obj, Object... args)Constructor<?> declaredConstructor = a1.getDeclaredConstructor();Object o = declaredConstructor.newInstance();eatMethod.invoke(o);}
}

其他API

  • 在这里插入图片描述
    :可以通过Class直接实例化 , 但是要有一个无参构造方法

eg:


public class Demo {public static void main(String[] args)throws ClassNotFoundException, InstantiationException, IllegalAccessException {Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.A");// 通过class对象直接实例化对象Object o = a1.newInstance();System.out.println(o);}
}class A {int a;public A(int a) {this.a = a;}public A() {}
}
  • 在这里插入图片描述

eg:


public class Demo {public static void main(String[] args)throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException {// 1. 先获取字节码文件对象Class<?> a1 = Class.forName("com.cskaoyan.Demo0112.Person");Class<?> a2 = Class.forName("java.io.OutputStream");// 2. 获取类名System.out.println(a1.getName());// 3. 获取简单名System.out.println(a1.getSimpleName());// 4. 获取父类System.out.println(a1.getSuperclass());System.out.println(a1.getSuperclass().getSimpleName());// 5. 获取实现的接口Class<?>[] interfaces = a2.getInterfaces();for (Class<?> anInterface : interfaces) {System.out.println(anInterface);}// 6. 获取成员变量Field nameField = a1.getDeclaredField("name");// 获取成员变量的类型System.out.println(nameField.getType());int modifiers = nameField.getModifiers();System.out.println(modifiers); // 1 就是publicSystem.out.println(Modifier.toString(modifiers));// 7. 获取method对象Method eatMethod = a1.getDeclaredMethod("eat", String.class);// 方法的返回值类型System.out.println(eatMethod.getReturnType());// 方法的参数类型Class<?>[] parameterTypes = eatMethod.getParameterTypes();for (Class<?> parameterType : parameterTypes) {System.out.println(parameterType);}}
}

自定义类加载器

步骤

  • 继承ClassLoader
  • 重写findClass方法

eg:


MyClassLoader自定义类加载器:
public class MyClassLoader extends ClassLoader {// 成员String classPath;public MyClassLoader(String classPath) {this.classPath = classPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {Class<?> aClass = null;// 读取.class文件try {byte[] data = getData();// defineClass(String name, byte[] b, int off, int len)// 将一个 byte 数组转换为 Class 类的实例。aClass = defineClass(name, data, 0, data.length);} catch (IOException e) {e.printStackTrace();}// 最终要返回一个Class对象return aClass;}private byte[] getData() throws IOException {// 读取字节码文件// 创建FileInputStreamFileInputStream in = new FileInputStream(classPath);// 使用ByteArrayOutputStreamByteArrayOutputStream outputStream = new ByteArrayOutputStream();int readCount;byte[] bytes = new byte[1024];while ((readCount = in.read(bytes)) != -1 ){outputStream.write(bytes,0,readCount);}/*byte[] toByteArray()创建一个新分配的byte数组*/byte[] bytes1 = outputStream.toByteArray();// 返回字节码文件里的数据return bytes1;}
}-----------------------------------------------------public class Demo {public static void main(String[] args) throws ClassNotFoundException,NoSuchMethodException, InstantiationException,IllegalAccessException, InvocationTargetException {// 定义加载路径String classPath ="D:\\Test.class";// 创建自定义类加载器MyClassLoader myClassLoader = new MyClassLoader(classPath);// 通过loadClass方法加载类Class<?> testLc = myClassLoader.loadClass("Test");// 得到字节码文件对象// 拿到Method对象Method funcMethod = testLc.getDeclaredMethod("func");// invokeObject o = testLc.newInstance();funcMethod.invoke(o);}
}

反射的应用

  • 通过反射获取注解信息

  • 动态代理

  • ORM(Object Relational Mapping)框架, 数据库框架

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/616009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于gcc版本问题导致找不到filesystem以及GCC多版本切换

fatal error: filesystem: 没有那个文件或目录 问题&#xff1a; #include 包含上述头文件出错&#xff0c;未找到该文件。 解决方法一&#xff1a; 修改头文件 #include <experimental/filesystem>添加依赖 在编译时&#xff0c;后面添加&#xff1a;-lstdcfs编译通…

java中浮点数如何进行等值比较

浮点数之间的等值判断&#xff0c;基本数据类型不能用来比较&#xff0c;包装数据类型不能用 equals来判断。 说明&#xff1a;浮点数采用“尾数阶码”的编码方式&#xff0c;类似于科学计数法的“有效数字指数”的表示方式。二进制无法精确表示大部分的十进制小数&#xff0c;…

C#,入门教程(14)——字符串与其他数据类型的转换

上一篇&#xff1a; C#&#xff0c;入门教程(13)——字符&#xff08;char&#xff09;及字符串&#xff08;string&#xff09;的基础知识https://blog.csdn.net/beijinghorn/article/details/123928151 数据只有可视化才能更好地体现其价值&#xff0c;因而 string 与 image…

Java循环语句

1&#xff1a;for循环结构 循环结构有三种语句&#xff0c;分别是&#xff1a; for循环 while循环 do…while循环 这三种循环可以做相同的事情&#xff0c;当然它们也有小的区别 1.1 for循环结构 这段代码的作用&#xff0c;是用来展示手机信息1000次。 还提到了这里的几…

能见度监测站在交通中有哪些作用

【TH-NJD10】能见度监测站在交通中的作用主要体现在以下几个方面&#xff1a; 提高交通安全&#xff1a;能见度是影响交通安全的重要因素之一。能见度监测站可以实时监测并发布路面或空中的能见度数据&#xff0c;帮助驾驶员和交通管理部门做出安全决策。在低能见度情况下&…

组合和聚合

不是c的语法要求&#xff0c;是一种建模思想 目录 1.组合 1. 使用 -- 在一个类中创建另外一个类的对象 代码中的解释: 代码结果&#xff1a; 组合&#xff1a; 2. 使用 -- 在一个类中创建另外一个类的指针 2.使用类定义一个指针 -- 不是创建一个对象 3.聚合 1. 使…

Python自动化测试数据驱动解决数据错误

数据驱动将测试数据和测试行为完全分离&#xff0c;实施数据驱动测试步骤如下&#xff1a; A、编写测试脚本&#xff0c;脚本需要支持从程序对象、文件或者数据库读入测试数据&#xff1b; B、将测试脚本使用的测试数据存入程序对象、文件或者数据库等外部介质中&#xff1b;…

密码输入检测 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 给定用户密码输入流input,输入流中字符 ‘<’ 表示退格,可以清除前一个输入的字符,请你编写程序,输出最终得到的密码字符,并判断密码是否满足如下的密码安全要求。 密码安全要求如下: 密码长度&…

浅研究下 DHCP 和 chrony

服务程序&#xff1a; 1.如果有默认配置&#xff0c;请先备份&#xff0c;再进行修改 2.修改完配置文件&#xff0c;请重启服务或重新加载配置文件&#xff0c;否则不生效 有些软件&#xff0c;安装包的名字和系统里服务程序的名字不一样&#xff08;安装包名字&#xff1a;…

【Spring Cloud】Sentinel流量限流和熔断降级的讲解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Spring Cloud》。&#x1f3af;&#x1f3af; &am…

golang 反序列化出现json: cannot unmarshal string into Go value of type model.Phone

项目场景&#xff1a; 今天在项目公关的过程中&#xff0c;需要对interface{}类型进行转换为具体结构体 问题描述 很自然的用到了resultBytes, _ : json.Marshal(result)&#xff0c;然后对resultBytes进行反序列化转换为对应的结构体err : json.Unmarshal(resultBytes, &…

OpenCV-Python(35):BRIEF算法

算法介绍 BRIEF&#xff08;Binary Robust Independent Elementary Features&#xff09;是一种用于计算机视觉中特征点描述子的算法。它是一种二进制描述子&#xff0c;通过比较图像上不同位置的像素值来生成特征点的描述子。 BRIEF算法的基本思想是选取一组固定的像素对&…

12GoF之代理模式

解决问题的思维&#xff1a;AOP 解决问题技术&#xff1a;代理技术 代理技术太麻烦&#xff0c;因此使用框架 Spring AOP框架&#xff08;底层是代理技术&#xff1a;jdk动态daili&#xff0c;cglib&#xff09; 代理模式是GoF23种设计模式之一。属于结构型设计模式。 代理…

做一个个人博客第一步该怎么做?

做一个个人博客第一步该怎么做&#xff1f; 好多零基础的同学们不知道怎么迈出第一步。 那么&#xff0c;就找一个现成的模板学一学呗&#xff0c;毕竟我们是高贵的Ctrl c v 工程师。 但是这样也有个问题&#xff0c;那就是&#xff0c;那些模板都&#xff0c;太&#xff01;…

C 语言每日一题——旋转数组的最小数字

一、题目内容 提供一下该OJ题的链接&#xff1a;旋转数组的最小数字_牛客题霸_牛客网 (nowcoder.com) 二、题目分析 通过示例1可知&#xff0c;我们写代码的目的是在数组中找到一个最大值&#xff0c;并且返回来&#xff1b; 我们很容易的会想到创建一个变量&#xff1a;int…

【Linux】 nohup命令使用

nohup命令 nohup是Linux和Unix系统中的一个命令&#xff0c;其作用是在终端退出时&#xff0c;让进程在后台继续运行。它的全称为“no hang up”&#xff0c;意为“不挂起”。nohup命令可以让你在退出终端或关闭SSH连接后继续运行命令。 nohup 命令&#xff0c;在默认情况下&…

pyx文件编译为pyd/so文件(分别在windows/linux系统下)

Python有以下几种类型的文件&#xff1a; py&#xff1a;Python控制台程序的源代码文件pyx&#xff1a;是Python语言的一个编译扩展&#xff0c;它实际上是Cython语言的源代码文件&#xff08;可以理解为既支持Python语言也支持C/C&#xff09;。pyc&#xff1a;Python字节码文…

DevOps搭建(十六)-Jenkins+K8s部署详细步骤

​ 1、整体部署架构图 2、编写脚本 vi pipeline.yml apiVersion: apps/v1 kind: Deployment metadata:namespace: testname: pipelinelabels:app: pipeline spec:replicas: 2selector:matchLabels:app: pipelinetemplate:metadata:labels:app: pipelinespec:containers:- nam…

深入了解鸿鹄电子招投标系统:Java版企业电子招标采购系统的核心功能

随着市场竞争的加剧和企业规模的扩大&#xff0c;招采管理逐渐成为企业核心竞争力的重要组成部分。为了提高招采工作的效率和质量&#xff0c;我们提出了一种基于电子化平台的解决方案。该方案旨在通过电子化招投标&#xff0c;使得招标采购的质量更高、速度更快&#xff0c;同…

基于JAVA的数据可视化的智慧河南大屏 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 数据模块 A4.2 数据模块 B4.3 数据模块 C4.4 数据模块 D4.5 数据模块 E 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数据可视化的智慧河南大屏&#xff0c;包含了GDP、…