【Java】学习路径63-反射、类的加载-附思维导图(完结)
这一章的知识在实际开发也没有那么重要,主要是了解即可,另外掌握如何使用反射机制。
类的使用:
在虚拟机中:
类的加载->类的连接->类的初始化
类的加载
只会加载需要用到的类,加载到内存中,并创建对应的一个class文件,
类加载到内存中,会创建一个class对象,
class对象中保存了这个类中的方法、数据成员
一个类加载一次
类加载器(JVM中)
将.class文件加载到内存中,生成java.lang.Class类
分为三种:
Bootstrap ClassLoader 根类加载器
核心类,比如java.lang.String
Extension ClassLoader 拓展类加载器
ext之类的
System ClassLoader 系统类加载器
自己写的类
反射
自己画了个思维导图,帮助大家理解。。

这个翻译不太好理解。
我们之前写的所有代码都没有涉及到反射
理解角度一:只有用到java.lang.class对象的时候,才叫使用反射
角度二:只有程序运行的时候,查看一个类有什么信息(数据成员、方法成员),这个过程叫反射。
角度三:在以往的开发中,我们创建一个类,我们知道类里面有啥方法,然后直接使用里面的方法、变量
如果我们不知道我们要使用什么类,这个时候需要使用反射获取类的信息,再去使用里面的方法、变量
如果不能理解,也无所谓,在后面开发中再去体会。(不然就成书呆子了
我一直认为,刚刚开始接触编程,最好抛开书本,尤其是教科书。
教科书应该当作一本字典,哪里不会点哪里,千万不要一个字一个字看。
教科书对于初学者来说没有太多的益处。
个人认为最好的方法是:先写代码,再看理论;先学会使用,再了解原理。
怎么在实际开发中使用“反射”?
1-获取class对象
先获取一个类的class对象。注意我的描述,是某个类的class对象,类的class对象!
这里有个类:
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println(name);
}
}
第一种获取方式:
我们要获取这个User类的class对象,就使用getClass()方法,这个方法中Object中自带的,不用自己创建。
public class getClassTest {
public static void main(String[] args) {
User u1 = new User("remoo");
User u2 = new User("rcccc");
Class c1 = u1.getClass();
System.out.println(c1);
}
}
输出:
Class c1 = u1.getClass();
System.out.println(c1);
Class c2 = u2.getClass();
System.out.println(c1==c1);
输出:
说明c1和c2是一个类对象。
也就是说,每个类只会被加载class对象一次。
c1和c2的class对象都是user,无论创建了多少个User对象!
大家可以自己尝试获取上面代码中的getClassTest类的class对象,与c1的class做比较。
第二种获取方式:
直接通过类获取class,
直接某某类.class就可以了。
Class c3 = User.class;
第三种获取方式:
通过forName获取,
forName是Class中的静态方法。
try {
Class c4 = Class.forName("User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
这个方法要抛异常,原因是你填写的类名字编辑器不会帮你检查,有可能你写错了。
对了,如果你的类在包里,就要加上包的名字,
eg:com.test.User
更多例子:
错误的:
Class c4 = Class.forName("Math");
正确的:
Class c4 = Class.forName("java.lang.Math");
第三种方法用的比较多啦。
2-利用反射构造对象Constructor
我们获取这个类的方法:
public class User {
private String name;
private User(int a){System.out.println("private");}
public User() {
System.out.println("none");
}
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println(name);
}
}
获取方法:
1、获取全部构造方法
import java.lang.reflect.Constructor;
public class getConstructors {
public static void main(String[] args) throws Exception {
Class c = Class.forName("User");
Constructor[] cs = c.getConstructors();
for (Constructor constructor : cs)
System.out.println(constructor);
}
}
输出:
我们注意到,我们只能获取public的方法,私有的方法获取不到。
2、通过可变参数得到特定的构造方法

看到那三个...了吗,那个就是可变参数,参数数量可变。
Constructor constructor = c.getConstructor();
现在可以调用一波这个方法,
(但是实际开发中你肯定不知道这里面有啥方法,这里只是验证一下,这里得到的Object其实就是User)
Object o1 = constructor.newInstance();
User user =(User)o1;
user.show();

指定参数构造:
Constructor constructor = c.getConstructor(String.class);
对应User中的:
public User(String name) {
this.name = name;
}
验证:

如果想得到包括私有的所有构造方法,就使用:Declared
Constructor[] css = c.getDeclaredConstructors();
忽略访问权限!
但是在后面newInstance的时候不能直接调用,在newInstance之前调用一下:
constructor.setAccessible(true);
确保可以访问到里面的private对象。
3-获取字段getField
遍历所有的
import java.lang.reflect.Field;
class Test{
public int age;
public double height;
public String name;
public long money;
}
public class getField {
public static void main(String[] args) throws Exception {
Class c = Class.forName("Test");
Field[] fs = c.getFields();
for (Field f : fs){
System.out.println(f);
}
}
}
返回:

查找特定名称的
Field f = c.getField("name");
System.out.println(f);

与上面反射构造方法后直接newInstance()不同,之前是创建一个对象
而现在我们要访问字段,我们需要明确是哪一个对象中的字段。
例子:
比如我们现在获取了一个Test对象t1,我们使用反射的方式获得其中的age字段。假设所有字段都已经赋了初值:
age 18 height 1.77 name "remoo" money 100

public class getField {
public static void main(String[] args) throws Exception {
Class c = Class.forName("Test");
Test t1 = new Test();
t1.age=18;
t1.height =1.77;
t1.name="remoo";
t1.money=100;
Field ageField = c.getField("age");
System.out.println(ageField.getInt(t1));
}
}
c.getField("age")返回的是Test这个类的class对象中变量名为age的字段
再通过 字段.getInt() 或者 字段.getDouble() 或者 字段.get() 等方法,传入那个需要“反射”的对象,“反射”出字段。
引用类型就用 get()
返回:

以前我们使用t1.age获得字段,
现在反射是ageField.t1
这就是反射。
访问匿名字段
和上面访问私有构造方法一样
我们把上面的例子中,Test类的age改成private的。

public class getField {
public static void main(String[] args) throws Exception {
Class c = Class.forName("Test");
Test t1 = new Test();
t1.height =1.77;
t1.name="remoo";
t1.money=100;
Field age = c.getDeclaredField("age");
age.setAccessible(true);
age.setInt(t1,18);
System.out.println(age.getInt(t1));
}
}
上述操作之后,也是ok的

4-获取调用成员方法
一个类里边有三大部分:
- 构造方法
- 成员变量(字段)
- 成员方法
但是成员方法相当于是1和2的结合
为什么这么说呢?
和构造方法一样,成员方法需要传递可变参数
和成员变量一样,成员方法需要传入一个对象
待反射的类:
class TestClass{
private int age;
public TestClass() {}
public TestClass(int age) {
this.age = age;
}
public void sayHello(String name){
System.out.println(name + age);
}
public void sayHello(){
System.out.println(age);
}
}
获取全部的方法(包括了系统内部的方法)
public class getMethod {
public static void main(String[] args) throws Exception {
TestClass tc = new TestClass(18);
Class c = Class.forName("TestClass");
Method[] ms = c.getMethods();
for (Method m : ms)
System.out.println(m);
}
}

调用方法invoke,带形参
Method m = c.getMethod("sayHello",String.class);
m.invoke(tc,"remoo");
返回:

调用私有化的方法
待测试类
class TestClass{
private int age;
public TestClass() {}
public TestClass(int age) {
this.age = age;
}
public void sayHello(String name){
System.out.println(name + age);
}
public void sayHello(){
System.out.println(age);
}
private void sayHello(int date){
System.out.println("private:"+date);
}
}
调用getDeclaredMethods()

我们注意到在使用getDeclaredMethods()的时候不会得到系统内部(父类)的方法。
调用带参数的私有化方法
Method m = c.getDeclaredMethod("sayHello",int.class);
m.setAccessible(true);
m.invoke(tc,19);
效果:

【Java】学习路径63-反射、类的加载-附思维导图(完结)的更多相关文章
- Java温故而知新(10)类的加载机制
类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指导开发者采取更有效的措施配合程序执行. 研究类加载机制的第二个目的是让程序能动态的控制类加载,比如热部署等,提高程序的灵活性 ...
- 反射 类的加载 Schema DOM 解析方式和解析器 命名空间
Day15 反射 1.1 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. l 加载 就是指将class文件读入内存,并为之创建 ...
- 2020年Java多线程与并发系列22道高频面试题(附思维导图和答案解析)
前言 现在不管是大公司还是小公司,去面试都会问到多线程与并发编程的知识,大家面试的时候这方面的知识一定要提前做好储备. 关于多线程与并发的知识总结了一个思维导图,分享给大家 1.Java中实现多线程有 ...
- web前端开发初学者必看的学习路线(附思维导图)
很多同学想学习WEB前端开发,虽然互联网有很多的教程.网站.书籍,可是却又不知从何开始如何选取.看完网友高等游民白乌鸦无私分享的原标题为<写给同事的前端学习路线>这篇文章,相信你会有所收获 ...
- UI设计初学者必备的工具以及学习路线(附思维导图)
今天千锋UI设计小编着重为大家介绍5个学习ui设计必须要会的工具和软件以及UI设计学习路线,希望能对大家所帮助. UI设计必要的工具和软件 1.PS 图像处理合成软件 ui设计核心软件,强大的图像处理 ...
- java类的加载、链接、初始化
JVM和类的关系 当我们调用JAVA命令运行某个java程序时,该命令将会启动一条java虚拟机进程,不管该java程序有多么复杂,该程序启动了多少个线程,它们都处于该java虚拟机进程里.正如前面介 ...
- java 类的加载、连接和初始化
JVM和类 调用Java命令运行Java程序时,该命令将会启动一条Java虚拟机进程,不管该Java程序启动了多少条线程,创建了多少个变量,它们都处于该Java虚拟机进程里,共享该JVM进程的内存区. ...
- java 基础-思维导图
思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具.了解了思维导图的作用之后,觉得把它运用到java上应该是个不错的想法,这样回顾知识点的时候一目了然,快速知道自己的短板. 思维 ...
- Java知识体系思维导图
Java知识体系,为方便预览,将思维导图上传至印象笔记,博客园直接上传图片受限于图片大小,暂时接触这么多,待以后丰富 https://app.yinxiang.com/shard/s24/nl/272 ...
随机推荐
- C语言学习之我见-strncpy()字符串复制函数(可控制范围)
strncpy()函数,用于两个字符串值的复制. (1)函数原型 char *strncpy(char * _Dest,const char * _Source,size_t _Count); (2) ...
- linux系统调优工具
系统调优思路 性能优化就是找到系统处理中的瓶颈以及去除这些的过程,性能优化其实是对 OS 各子系统达到一种平衡的定义.具体步骤如下: 1. 系统的运行状况: CPU -> MEM -> D ...
- RPA应用场景-日终清算操作
场景概述 日终清算操作 所涉系统名称 登记过户管理系统(TA),投资交易系统(032) 人工操作(时间/次) 60-80分钟 所涉人工数量 2 操作频率 每日 场景流程 这两个流程一般在晚上8-9点开 ...
- 2m高分辨率土地利用分类数据
数据下载链接:百度云下载链接 土地利用数据是在根据影像光谱特征,结合野外实测资料,同时参照有关地理图件,对地物的几何形状,颜色特征.纹理特征和空间分布情况进行分析,建立统一解译标志的基础之上,依据多源 ...
- warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8): No such file or directory
1)apt-get clean && apt-get update && apt-get install -y locales 2)locale-gen en_US.U ...
- AI写代码! 神器copilot介绍+安装+使用
!郑重提示!!!!!!!: 正在学编程.算法的同学请千万不要依赖此插件,否则你可能甚至无法手写出一个for循环 AI帮我写代码?我帮AI写代码?庄周梦蝶?蝶梦庄周?十分梦幻. copilot在VSco ...
- APISpace 疫情地区校验API接口 免费好用
从2019年疫情开始爆发到现在,我们去到某个地方都会提心吊胆的,很怕一不小心就染上了这个病毒.在去到某个地方之前,我们提前查看到它的一个疫情等级,同时做好防护再出门我们心里也会有底一些.所以疫情地区校 ...
- Solution -「BZOJ3894」文理分科
Sol. 说实话,对于一个初学者,这道题很难看出是一道网络流-最小割.对于一个熟练者,这是比较套路的一种模型. 最小割,可以看做是在一个图中删掉最小的边权和使得源点.汇点不连通.或者换一个角度,可以看 ...
- 苹果手机和Windows之间互传文件
参考链接:https://jingyan.baidu.com/article/a378c960c46804f229283064.html 实现原理:就是使用Samba服务,windows共享一个文件夹 ...
- NodeJS 基于 Dapr 构建云原生微服务应用,从 0 到 1 快速上手指南
Dapr 是一个可移植的.事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的.无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架.Dapr 确保开发人员专注 ...