写点什么

不懂就看!P7 大牛珍藏的 Java 反射详解笔记,从入门到实践太香了

发布于: 2021 年 04 月 30 日
不懂就看!P7大牛珍藏的Java反射详解笔记,从入门到实践太香了

今日分享开始啦,请大家多多指教~


这篇文章给大家先简简单单地说下类的加载,以及具体实现,可以自己操作一下哦!


类的加载


在程序运行后,首次使用某个类,会把这个类的字节码文件读取到内存,并且会将这个类的所有信息存到一个 Class 对象中。


简单步骤:


1:jvm 执行代码,例如读到 new Student()


​ 2 : 读取 Student 的字节码文件


​ 3:把字节码文件的内容(读取成字节码对象)存储到方法区(以前的说法),1.8 以后叫做元空间(貌似)


​ 4:最后类加载完成以后,在堆空间创建内存空间。


类的加载时机(下面六种)


创建类的实例。(new 一个类)


类的静态变量,或者为静态变量赋值。


类的静态方法。


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


初始化某个类的子类。


直接使用 java.exe 命令来运行某个主类。(编译 javac 类名.java, 运行 java.类名)


今天的反射也属于类加载时机的一种


先上代码:


类加载时机代码演示


  1. 创建类的实例。 静态代码块随着类的加载而加载,并且只执行一次。

  2. 类的静态变量,或者为静态变量赋值。

  3. 类的静态方法。

4.反射通过 Class.forName("全类名") 进行反射

5.通过子类实例

运行结果

都证明了这个 stu 类被加载了。


类加载器(暂时先了解了解)


下面说说类加载器,类加载器是负责将实际空间中的某个 class 文件读取到内存中并且生成 Class 的对象。


Java 中有三种类加载器,它们分别用于加载不同种类的 class:


Java 中有三种类加载器,它们分别用于加载不同种类的 class:


启动类加载器(Bootstrap ClassLoader):用于加载系统类库<JAVA_HOME>\bin 目录下的 class,例如:rt.jar。


扩展类加载器(Extension ClassLoader):用于加载扩展类库<JAVA_HOME>\lib\ext 目录下的 class。


应用程序类加载器(Application ClassLoader):用于加载我们自定义类的加载器。


进去代码看看,我们是如何获得类加载器的

再点进 getClassLoader()方法看看 jdk 是怎么描述的

图中看到,一些实现可能使用 null 来表示引导类加载器,可能在此类中的实现返回 null.


举个例子。

好了,接下来该回到反射的主题


反射的概念


它一种机制,利用这个机制就可以在程序中对类进行解析,并且可以操作类中所有成员(变量,方法,构造方法)。


使用反射需要一个前提,获取需要反射的那个类的字节码对象。


Class 对象的获取方式


通过类名.class 获得

通过对象名.getClass()方法获得

通过 Class 类的静态方法获得: static Class forName(“类全名”)

Tips:每个类的 Class 对象都只有一个


Class 类常用的方法


String getSimpleName(); 获取类名字符串 String getName(); 获取全类名字符串


创建类的对象


1.T newInstance(): 创建 Class 对象关联类的对象。

2.通过 Constructor 类来创建对象


首先要获取构造器类


Class 类中与 Constructor 相关的方法


1.Constructor getConstructor(Class… parameterTypes)* 根据参数类型获得对应的 Constructor 对象。

getConstructor()的源码描述

上个使用的代码


Java        /**         * 先用getConstructor() 获取Constructor<T>类对象         * 再通过这个对象实例T。 没有参数的用法         * @throws Exception         */        @Test        public void getPublicConstructorWithoutParameter() throws Exception {            Class<Student> studentClass = Student.class;            //先获取无参构造类对象。            Constructor<Student> constructor=studentClass.getConstructor();            //再通过这个实例方法,实例这个类            Student student = constructor.newInstance();        }        /**         * 先用getConstructor() 获取Constructor<T>类对象         * 再通过这个对象实例T。 有参数的用法         * @throws Exception         */        @Test        public void getPublicConstructor() throws Exception {            Class<Student> studentClass = Student.class;            //获取有参构造类            Constructor<Student> constructor=studentClass.getConstructor(int.class);            //输入参数实例化Student类            Student student = constructor.newInstance(1);         }
复制代码


如图所述,如果传入了没有相关参数重载的构造器,会报 NoSuchMethodException 异常


2.Constructor getDeclaredConstructor(Class… parameterTypes)


  • 根据参数类型获得对应的 Constructor 对象

  • 可以是 public、protected、(默认)、private 修饰符的构造方法。

  • 如果是被 protected、(默认)、private 修饰符修饰的构造器,需要确定本身能否访问到,如果不能访问到就要设置权限,用 setAccessible(true)。


暴力获取构造器,能获取包括 public protected default private


通过 getDeclaredConstructor()暴力获取 Student 类中除了 public 其他修饰符的构造器,但这个构造类对象需要设置权限,setAccessible(true)


具体要不要设置,得看这个修饰符本身能否访问到相关资源。


图上是个反例。


3.Constructor[] getConstructors()获得类中的所有构造方法对象,只能获得 public 的


上代码:


通过 getConstructors()获取所有 public 修饰的构造器类对象。


@Testpublic void getAllPublicConstructor(){    Class<Student> studentClass = Student.class;    Constructor<Student>[] constructors = (Constructor<Student>[]) studentClass.getConstructors();    for (Constructor<Student> constructor : constructors) {        System.out.println(constructor);    }}
复制代码

遍历打印的结果:

4.Constructor[] getDeclaredConstructors()获得类中的所有构造方法对象


可以是 public、protected、(默认)、private 修饰符的构造方法。


通过 getDeclaredConstructors()获取所有 p 修饰的构造器类对象。


@Testpublic void getAllAccessConstructor(){    Class<Student> studentClass = Student.class;    Constructor<Student>[] constructors = (Constructor<Student>[]) studentClass.getDeclaredConstructors();    for (Constructor<Student> constructor : constructors) {        System.out.println(constructor);    }}
复制代码

遍历打印的结果:

获取成员方法


接下来的部分就不放代码演示了,就提供下 api。


1 Method getMethod(String name,Class...args);


​ 方法名和参数类型获得对应的成员方法对象,只能获得 public 的


2 Method getDeclaredMethod(String name,Class...args);


​ 根据方法名和参数类型获得对应的成员方法对象,包括 public、protected、(默认)、private 的


3 Method[] getMethods();


​ 获得类中的所有成员方法对象,返回数组,只能获得 public 修饰的且包含父类的


4Method[] getDeclaredMethods();


获得类中的所有成员方法对象,返回数组,只获得本类的,包括 public、protected、(默认)、private 的


通过反射访问成员变量


Method 对象常用方法


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


  • 调用指定对象 obj 的该方法

  • args:调用方法时传递的参数


void setAccessible(true)


设置"暴力访问"——是否取消权限检查,true 取消权限检查,false 表示不取消


通过反射获取类的成员变量


Class 类中与 Field 相关的方法


Field getField(String name);


  • 根据成员变量名获得对应 Field 对象,只能获得 public 修饰


Field getDeclaredField(String name);


  • 根据成员变量名获得对应 Field 对象,包括 public、protected、(默认)、private 的


Field[] getFields();


  • 获得所有的成员变量对应的 Field 对象,只能获得 public 的


Field[] getDeclaredFields();


  • 获得所有的成员变量对应的 Field 对象,包括 public、protected、(默认)、private 的


通过反射访问成员变量


Field 对象常用方法


**void  set(Object obj, Object value)**  **void setInt(Object obj, int i)** 	 **void setLong(Object obj, long l)** **void setBoolean(Object obj, boolean z)**  **void setDouble(Object obj, double d)**  **Object get(Object obj)   int	getInt(Object obj)**  **long getLong(Object obj)**  **boolean getBoolean(Object ob)** **double getDouble(Object obj)**  **void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。** **Class getType(); 获取属性的类型,返回Class对象。**
复制代码


今日份分享已结束,请大家多多包涵和指点!

用户头像

还未添加个人签名 2021.04.20 加入

Java工具与相关资料获取等WX: pfx950924(备注来源)

评论

发布
暂无评论
不懂就看!P7大牛珍藏的Java反射详解笔记,从入门到实践太香了