反射学习贴、拓展贴
创始人
2025-06-01 12:04:55
0

1. 概述

1.1 为什么要有反射

在这里插入图片描述

Cat:

package com.hspedu;/*** @author 韩顺平* @version 1.0*/
public class Cat {private String name = "招财猫";public int age = 10; //public的public Cat() {} //无参构造器public Cat(String name) {this.name = name;}public void hi() { //常用方法//System.out.println("hi " + name);}public void cry() { //常用方法System.out.println(name + " 喵喵叫..");}}

re.properties

classfullpath=com.hspedu.Cat
method=cry

测试类

package com.hspedu.reflection.question;import com.hspedu.Cat;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;/*** 反射问题的引入*/
@SuppressWarnings({"all"})
public class ReflectionQuestion {public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {//根据配置文件 re.properties 指定信息, 创建Cat对象并调用方法hi//回忆//传统的方式 new 对象 -》 调用方法
//        Cat cat = new Cat();
//        cat.hi(); ===> cat.cry() 修改源码.//我们尝试做一做 -> 明白反射//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"System.out.println("classfullpath=" + classfullpath);System.out.println("method=" + methodName);//2. 创建对象 , 传统的方法,行不通 =》 反射机制//new classfullpath();//3. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi"  的方法对象//    即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)}
}

1.2 反射机制

在这里插入图片描述

1.3 反射机制原理示意图

在这里插入图片描述

1.4 Java 反射机制可以完成

在这里插入图片描述

1.5 反射相关的主要类

在这里插入图片描述

package com.hspedu.reflection;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;public class Reflection01 {public static void main(String[] args) throws Exception {//1. 使用Properties 类, 可以读写配置文件Properties properties = new Properties();properties.load(new FileInputStream("src\\re.properties"));String classfullpath = properties.get("classfullpath").toString();//"com.hspedu.Cat"String methodName = properties.get("method").toString();//"hi"//2. 使用反射机制解决//(1) 加载类, 返回Class类型的对象clsClass cls = Class.forName(classfullpath);//(2) 通过 cls 得到你加载的类 com.hspedu.Cat 的对象实例Object o = cls.newInstance();System.out.println("o的运行类型=" + o.getClass()); //运行类型//(3) 通过 cls 得到你加载的类 com.hspedu.Cat 的 methodName"hi"  的方法对象//    即:在反射中,可以把方法视为对象(万物皆对象)Method method1 = cls.getMethod(methodName);//(4) 通过method1 调用方法: 即通过方法对象来实现调用方法System.out.println("=============================");method1.invoke(o); //传统方法 对象.方法() , 反射机制 方法.invoke(对象)//java.lang.reflect.Field: 代表类的成员变量, Field对象表示某个类的成员变量//得到name字段//getField不能得到私有的属性Field nameField = cls.getField("age"); //System.out.println(nameField.get(o)); // 传统写法 对象.成员变量 , 反射 :  成员变量对象.get(对象)//java.lang.reflect.Constructor: 代表类的构造方法, Constructor对象表示构造器Constructor constructor = cls.getConstructor(); //()中可以指定构造器参数类型, 返回无参构造器System.out.println(constructor);//Cat()Constructor constructor2 = cls.getConstructor(String.class); //这里老师传入的 String.class 就是String类的Class对象System.out.println(constructor2);//Cat(String name)}
}

1.6 反射优点和缺点

在这里插入图片描述

1.6.1 反射调用优化-关闭访问检查

在这里插入图片描述
在这里插入图片描述

速度测试

package com.hspedu.reflection;import com.hspedu.Cat;import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** 测试反射调用的性能,和优化方案*/
public class Reflection02 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//Field//Method//Constructorm1();m2();m3();}//传统方法来调用hipublic static void m1() {Cat cat = new Cat();long start = System.currentTimeMillis();for (int i = 0; i < 90; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("m1() 耗时=" + (end - start));}//反射机制调用方法hipublic static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m2() 耗时=" + (end - start));}//反射调用优化 + 关闭访问检查public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {Class cls = Class.forName("com.hspedu.Cat");Object o = cls.newInstance();Method hi = cls.getMethod("hi");hi.setAccessible(true);//在反射调用方法时,取消访问检查long start = System.currentTimeMillis();for (int i = 0; i < 900000000; i++) {hi.invoke(o);//反射调用方法}long end = System.currentTimeMillis();System.out.println("m3() 耗时=" + (end - start));}
}

2. Class类

2.1 基本介绍

在这里插入图片描述
在这里插入图片描述

package com.hspedu.reflection.class_;import com.hspedu.Cat;
import java.util.ArrayList;/*** 对Class类特点的梳理*/
public class Class01 {public static void main(String[] args) throws ClassNotFoundException {//看看Class类图//1. Class也是类,因此也继承Object类//Class//2. Class类对象不是new出来的,而是系统创建的//(1) 传统new对象/*  ClassLoader类public Class loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*///Cat cat = new Cat();//(2) 反射方式, 刚才老师没有debug到 ClassLoader类的 loadClass, 原因是,我没有注销Cat cat = new Cat();/*ClassLoader类, 仍然是通过 ClassLoader类加载Cat类的 Class对象public Class loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);}*/Class cls1 = Class.forName("com.hspedu.Cat");//3. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次Class cls2 = Class.forName("com.hspedu.Cat");System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());Class cls3 = Class.forName("com.hspedu.Dog");System.out.println(cls3.hashCode());}
}

2.2 Class 类的常用方法

在这里插入图片描述

package com.hspedu.reflection.class_;import com.hspedu.Car;import java.lang.reflect.Field;/*** 演示Class类的常用方法*/
public class Class02 {public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {String classAllPath = "com.hspedu.Car";//1 . 获取到Car类 对应的 Class对象// 表示不确定的Java类型Class cls = Class.forName(classAllPath);//2. 输出clsSystem.out.println(cls); //显示cls对象, 是哪个类的Class对象 com.hspedu.CarSystem.out.println(cls.getClass());//输出cls运行类型 java.lang.Class//3. 得到包名System.out.println(cls.getPackage().getName());//包名//4. 得到全类名System.out.println(cls.getName());//5. 通过cls创建对象实例Car car = (Car) cls.newInstance();System.out.println(car);//car.toString()//6. 通过反射获取属性 brandField brand = cls.getField("brand");System.out.println(brand.get(car));//宝马//7. 通过反射给属性赋值brand.set(car, "奔驰");System.out.println(brand.get(car));//奔驰//8 我希望大家可以得到所有的属性(字段)System.out.println("=======所有的字段属性====");Field[] fields = cls.getFields();for (Field f : fields) {System.out.println(f.getName());//名称}}
}

2.3 获取Class类对象

在这里插入图片描述
在这里插入图片描述

package com.hspedu.reflection.class_;import com.hspedu.Car;/*** 演示得到Class对象的各种方式(6)*/
public class GetClass_ {public static void main(String[] args) throws ClassNotFoundException {//1. Class.forNameString classAllPath = "com.hspedu.Car"; //通过读取配置文件获取Class cls1 = Class.forName(classAllPath);System.out.println(cls1);//2. 类名.class , 应用场景: 用于参数传递Class cls2 = Car.class;System.out.println(cls2);//3. 对象.getClass(), 应用场景,有对象实例Car car = new Car();Class cls3 = car.getClass();System.out.println(cls3);//4. 通过类加载器【4种(后期介绍)】来获取到类的Class对象//(1)先得到类加载器 carClassLoader classLoader = car.getClass().getClassLoader();//(2)通过类加载器得到Class对象Class cls4 = classLoader.loadClass(classAllPath);System.out.println(cls4);//cls1 , cls2 , cls3 , cls4 其实是同一个对象System.out.println(cls1.hashCode());System.out.println(cls2.hashCode());System.out.println(cls3.hashCode());System.out.println(cls4.hashCode());//5. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象Class integerClass = int.class;Class characterClass = char.class;Class booleanClass = boolean.class;System.out.println(integerClass);//int//6. 基本数据类型对应的包装类,可以通过 .TYPE 得到Class类对象Class type1 = Integer.TYPE;Class type2 = Character.TYPE; //其它包装类BOOLEAN, DOUBLE, LONG,BYTE等待System.out.println(type1);System.out.println(integerClass.hashCode());//和下面一样System.out.println(type1.hashCode());//和上面一样}
}

2.4 哪些类型有 Class 对象

在这里插入图片描述

package com.hspedu.reflection.class_;import java.io.Serializable;/*** 演示哪些类型有Class对象*/
public class AllTypeClass {public static void main(String[] args) {Class cls1 = String.class;//外部类Class cls2 = Serializable.class;//接口Class cls3 = Integer[].class;//数组Class cls4 = float[][].class;//二维数组Class cls5 = Deprecated.class;//注解//枚举Class cls6 = Thread.State.class;Class cls7 = long.class;//基本数据类型Class cls8 = void.class;//void数据类型Class cls9 = Class.class;//Class本质也是一个类System.out.println(cls1);System.out.println(cls2);System.out.println(cls3);System.out.println(cls4);System.out.println(cls5);System.out.println(cls6);System.out.println(cls7);System.out.println(cls8);System.out.println(cls9);}
}

3. 类加载

3.1 基本说明

在这里插入图片描述
在这里插入图片描述

3.2 类加载时机

在这里插入图片描述

3.3 类加载过程图

在这里插入图片描述

3.3.1 类加载各阶段完成任务

在这里插入图片描述

3.3.2 加载阶段

在这里插入图片描述

3.3.3 连接阶段

3.3.3.1 连接阶段-验证

在这里插入图片描述
验证过程:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

底层调用了一个SecurityManager的类作验证

在这里插入图片描述

打开任意一个字节码文件,JVM会验证该文件是否以魔数开头

3.3.3.2 连接阶段-准备

在这里插入图片描述
案例说明:

package com.hspedu.reflection.classload_;/*** 我们说明一个类加载的链接阶段-准备*/
public class ClassLoad02 {public static void main(String[] args) {}
}
class A {//属性-成员变量-字段//分析类加载的链接阶段-准备 属性是如何处理//1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是20//3. n3 是static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30public int n1 = 10;public static  int n2 = 20;public static final  int n3 = 30;
}

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
JAVA多线程知识整理 Java多线程基础 线程的创建和启动 继承Thread类来创建并启动 自定义Thread类的子类&#...
【洛谷 P1090】[NOIP... [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G ...
国民技术LPUART介绍 低功耗通用异步接收器(LPUART) 简介 低功耗通用异步收发器...
城乡供水一体化平台-助力乡村振... 城乡供水一体化管理系统建设方案 城乡供水一体化管理系统是运用云计算、大数据等信息化手段࿰...
程序的循环结构和random库...   第三个参数就是步长     引入文件时记得指明字符格式,否则读入不了 ...
中国版ChatGPT在哪些方面... 目录 一、中国巨大的市场需求 二、中国企业加速创新 三、中国的人工智能发展 四、企业愿景的推进 五、...
报名开启 | 共赴一场 Flu... 2023 年 1 月 25 日,Flutter Forward 大会在肯尼亚首都内罗毕...
汇编00-MASM 和 Vis... Qt源码解析 索引 汇编逆向--- MASM 和 Visual Studio入门 前提知识ÿ...
【简陋Web应用3】实现人脸比... 文章目录🍉 前情提要🌷 效果演示🥝 实现过程1. u...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
windows安装JDK步骤 一、 下载JDK安装包 下载地址:https://www.oracle.com/jav...
分治法实现合并排序(归并排序)... 🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨...
在linux上安装配置node... 目录前言1,关于nodejs2,配置环境变量3,总结 前言...
Linux学习之端口、网络协议... 端口:设备与外界通讯交流的出口 网络协议:   网络协议是指计算机通信网...
Linux内核进程管理并发同步... 并发同步并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理...
opencv学习-HOG LO... 目录1. HOG(Histogram of Oriented Gradients,方向梯度直方图)1...
EEG微状态的功能意义 导读大脑的瞬时全局功能状态反映在其电场结构上。聚类分析方法一致地提取了四种头表面脑电场结构ÿ...
【Unity 手写PBR】Bu... 写在前面 前期积累: GAMES101作业7提高-实现微表面模型你需要了解的知识 【技...