Java:反射机制学习笔记
一、反射机制
1、概述
反射机制:将类的各个组成部分封装成其他对象,在运行状态中,可以动态获取类信息和调用类对象的方法。
2、优缺点
- 优点
- 可以在程序运行过程中,操作类的组成部分。
- 可以解耦,提高程序的可扩展性。
- 缺点
- 产生一系列的解释操作,性能较差。
3、类加载的过程
java语言有着”一处编译,处处运行“的优良特点,能够很好地适应不同的平台,过程大致如下:
- 我们通过
javac命令将.java文件编译,会在磁盘上生成不面向平台的字节码文件.class。 - 类加载器通过一系列的操作,如加载、连接和初始化之后,将
.class文件加载进内存中。 - 将.class字节码文件代表的静态存储结构转化为方法区的运行时数据结构。
- 类加载时还会再内存中创建一个
java.lang.Class的对象,该对象包含类的信息,作为程序从方法区访问各种数据的接口。
二、获取Class对象的三种方式
这个Class对象包含类的所有信息,也就是说,我们获得了这个Class类的对象,就可以访问到JVM中的这个类。那么,如何获取呢?主要有以下三种方式。
1、Class.forName("全类名")
通过Class的静态方法forName("全类名"),返回和全类名对应类的Class对象。
//Class.forName("全类名");
Class cls1 = Class.forName("com.my.base.Person");
System.out.println(cls1);
- 多用于配置文件,将类名定义在配置文件中,便可以动态读取文件,加载类。
- 全类名指:完整包名.类名,如果找不到,会抛出ClassNotFoundException的异常。
2、类名.class
通过类名的class属性获取,返回该类对应的Class对象。
//类名.class;
Class cls2 = Person.class;
System.out.println(cls2);
- 该方式在程序编译阶段就可以检查需要访问的Class对象是否存在,相对来说更加安全。
- 该方式无需调用方法,程序性能方面相对较好。
3、对象.getClass()
getClass()方法在Object中定义,返回该对象所属类对应得Class对象。
//对象.getClass();
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);
同一个字节码文件.class在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的Class对象都是同一个。
// == 比较三个对象,都是true
System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);
System.out.println(cls3 == cls2);
三、反射相关的方法
Class对象包含着类的所有信息,而这些信息被封装在java.lang.reflect包下,成了一个个的类,不完全统计如下:
| Method | Field | Annotation | Constructor | Package | Modifier | Parameter |
|---|---|---|---|---|---|---|
| 方法类 | 字段类 | 注解类 | 构造器类 | 包类 | 修饰符类 | 方法参数类 |
Class类中提供了相应的方法,获取这些信息,由于方法众多,具体的还需要参看JDK官方文档。
我在这里总结几点通用的:
调用对应的
getXxx通常是获得对应public修饰的单个信息,getDeclaredXxx则不考虑修饰符,找不到,则往超类找。调用对应的
getXxxs通常获得对应的public修饰信息的数组,getDeclaredXxxs则不考虑修饰符,找不到,则往超类找。上面两者遇到参数的情况不同,如果本身用于获取public修饰信息的方法强行去获取达不到的权限,则会抛出异常:
- 对于Field而言,括号内是:
"参数名"。 - 对于Method而言,括号内是:
"方法名",参数类型对应的类。 - 对于Constructor而言,括号内是:
"参数对应的类"。
- 对于Field而言,括号内是:
Field类中有获取值的方法:
Object get(Object obj),也有设置值的方法:void set(Object obj, Object value)。Method类可以调用方法:
Object invoke(Object obj, Object... args)。Constructor类可以创建实例:
T newInstance(Object... initargs),如果类中有无参构造器,可以直接利用Class类中的newInstance()方法创建实例。在反射中,没有什么是私有的,如果有,那就使用
xxx.setAccessible(true)暴力破解。判断修饰符时,
getModifiers()返回的时int值,是各个修饰符表示数的和,可以用位运算判断,(xx.getModifiers()&Modifier.STATIC)!=0表示存在static修饰符。
ps:肯定有遗漏的API,到时候用的时候,翻翻API就完事了。
四、Demo×2
1、尝试自己写一个clone()方法
package com.my.reflect.practice;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @auther Summerday
*/
@SuppressWarnings("unchecked")
public class ImplementClone {
public Object clone(Object o) throws Exception{
//获取对象的实际类型
Class<Object> clz = (Class<Object>) o.getClass();
//获取所有构造方法
Constructor<Object>[] cs = (Constructor<Object>[]) clz.getDeclaredConstructors();
//任取一个构造方法
Constructor<Object> c = cs[0];
//防止取出构造方法为私有
c.setAccessible(true);
//该构造方法参数有or无?
//获取参数类型
Class[] ps = c.getParameterTypes();
//存储参数的数组
Object[] os = new Object[ps.length];
for(int i = 0;i<ps.length;i++){
//判断是否为基本类型
if(ps[i].isPrimitive()){
if(ps[i] == boolean.class)
os[i] = false;
else if(ps[i] == char.class)
os[i] = '\u0000';
else
os[i] = 0;
}else{
os[i] = null;
}
}
//执行构造方法创建对象
Object obj = c.newInstance(os);
//获取属性数组
Field[] fs = clz.getDeclaredFields();
for (Field f : fs){
//如果final修饰则返回,无法修改
if((f.getModifiers()&Modifier.FINAL)!=0){
continue;
}
//暴力破解
f.setAccessible(true);
//取出原属性值
Object value = f.get(o);
//将取出的属性值赋值给新对象的属性
f.set(obj, value);
}
return obj;
}
}
2、利用配置文件动态加载
package com.my.reflect.practice;
/**
* @auther Summerday
*/
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
/**
*
* 参考黑马程序员教学视频
*
* 实现:1、配置文件 2、反射
*
* 一、将需要创建的对象的全类名和需要执行的方法定义在配置文件中
*
* 二、在程序中加载读取配置文件
*
* 三、使用反射来加载类文件进内存
*
* 四、创建对象
*
* 五、执行方法
*
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1、加载配置文件
//1.1 创建Properties对象
Properties pro = new Properties();
//1.2 加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
//创建类加载器
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
pro.load(resourceAsStream);
//2、获取配置文件中定义的数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3、加载该类进内存
Class cls = Class.forName(className);
//4、创建对象
Object obj = cls.newInstance();
//5、获取方法
Method method = cls.getMethod(methodName);
//6、执行方法
method.invoke(obj);
}
}
以后会有越来越多真实的场景需要用到反射这项灵魂技术,总之,好好看,好好学。
Java:反射机制学习笔记的更多相关文章
- java反射机制学习笔记
内容引用自:https://www.cnblogs.com/wkrbky/p/6201098.html https://www.cnblogs.com/xumBlog/p/8882489.html,本 ...
- JAVA的反射机制学习笔记(二)
上次写JAVA的反射机制学习笔记(一)的时候,还是7月22号,这些天就瞎忙活了.自己的步伐全然被打乱了~不能继续被动下去.得又一次找到自己的节奏. 4.获取类的Constructor 通过反射机制得到 ...
- JAVA反射机制—学习总结
最近收到很多关于Java反射机制的问题留言,其实Java反射机制技术方面没有太多难点,或许是大家在学习过程中遗漏了细小知识点,导致一些问题无法彻底理解,现在我们简单的总结一下,加深印象.什么是反射机制 ...
- Java反射机制——学习总结
前几天上REST课,因为涉及到Java的反射机制,之前看过一直没有用过,有些遗忘了,周末找了些资料来重新学习,现在总结一下,加深印象. 什么是反射机制? 参考百度百科对java反射机制的定义: “JA ...
- Java反射机制学习与研究
Java反射机制:可以获取正在运行时的Java对象. 1.判断运行时对象对象所属的类. 2.判断运行时对象所具有的成员变量和方法. 3.还可以调用到private方法,改变private变量的值. S ...
- Java反射机制学习
Java 反射是Java语言的一个很重要的特征,它使得Java具体了“动态性”. 在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答 ...
- java反射机制(笔记)
java反射机制就是获取出class的相应方法 例如 获取构造函数: 模版: Class test = Class.forName("cn.test.Person");//得到相应 ...
- Java SPI机制学习笔记
最近在阅读框架源代码时,常常看到 SPI 的子包, 忍不住查了下: Service Provider Interface : 服务提供接口. JavaSPI 实际上是“基于接口的编程+策略模式+配置文 ...
- JAVA反射机制学习随笔
JAVA反射机制是用于在运行时动态的获取类的信息或者方法,属性,也可以用来动态的生成类,由于所有类都是CLASS的子类,我们可以用一个CLASS类的实例来实例化各种类 例如: Class<?&g ...
随机推荐
- Sublime Text(代码编辑软件)
特点 Sublime Text 3是一个轻量.简洁.高效.跨平台的编辑器,方便的配色以及兼容vim快捷键等各种优点: 它体积小巧,无需安装,绿色便携:它可跨平台支持Windows/Mac/Linux: ...
- 二分-D - Can you solve this equation?
D - Can you solve this equation? Now,given the equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,can you ...
- sort函数的用法(C++排序库函数的调用)
对数组进行排序,在c++中有库函数帮我们实现,这们就不需要我们自己来编程进行排序了. (一)为什么要用c++标准库里的排序函数 Sort()函数是c++一种排序方法之一,学会了这种方法也打消我学习c+ ...
- numpy基础知识练习
# 1.导入numpy模块 # 2.创建一个大小为10的空向量 # 3.创建一个大小为10的空向量,但是第五个值为1 # 4.创建一个10-49的ndarray数组 # 5.创建一个3x3的矩阵,其值 ...
- 使用pip install mysqlclient命令安装mysqlclient失败?(基于Python)
我们使用Django.flask等来操作MySQL,实际上底层还是通过Python来操作的.因此我们想要用Django来操作MySQL,首先还是需要安装一个驱动程序.在Python3中,驱动程序有多种 ...
- 题解 【洛谷P1115】最大子段和
这是一道枚举经典题. 本题有三种做法,各位需要根据每个题的数据范围来决定自己用哪种方法. 本题解中统一设最大和为Max. 方法一. 枚举子序列,从起点到终点求和.时间复杂度:O(n^3) 我们可以枚举 ...
- 操作系统-多用户如何理解(Linux)
单用户.多用户.单任务.多任务,这么多种操作系统容易让人迷糊.其实这种初看你会觉得理解了一点,但其实你仔细研究会发现,多用户到底讲的是什么鬼? 多任务比较简单,就是应用程序都要放置到内存上去给CPU调 ...
- C#中获取时间戳
{ 注意:下面是以毫秒为单位的13位 UTC 时间戳(非正规) }//先取得当前的UTC时间,然后转换成计算用的周期数(简称计时周期数),每个周期为100纳钞(ns)=0.1微秒(us)=0.00 ...
- C++-POJ3274-Gold Balanced Lineup[hash]
不是很懂? 胡乱hash #include <set> #include <map> #include <cmath> #include <queue> ...
- 514 ,css不同选择器的权重(css层叠的规则)
!important规则最重要,大于其它规则 行内样式规则,加1000 eg,<html> <head> </head> <body> & ...