-
day42-反射01
1.反射(reflection)机制
1.1反射机制问题
一个需求引出反射
请看下面问题:
- 根据配置文件 re.properties 指定信息,创建Cat对象并调用方法hi
|
classfullpath=li.reflection.Cat |
|
method=hi |
使用现有的技术,你能做的到吗?
-
这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码的情况下来控制程序,也符合设计模式的ocp原则(开闭原则)
开闭原则:不修改源码,扩展功能
例子:
re.properties:
|
classfullpath=li.reflection.Cat |
|
method=cry |
Cat:
|
package li.reflection; |
|
|
|
public class Cat { |
|
private String name = "招财猫"; |
|
|
|
public void hi() { |
|
System.out.println("hi " + name); |
|
} |
|
|
|
public void cry() { |
|
System.out.println(name + " cry"); |
|
} |
|
} |
ReflectionQuestion:
|
package li.reflection; |
|
|
|
import java.io.FileInputStream; |
|
import java.io.IOException; |
|
import java.lang.reflect.InvocationTargetException; |
|
import java.lang.reflect.Method; |
|
import java.util.Properties; |
|
|
|
public class ReflectionQuestion { |
|
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { |
|
|
|
//根据配置文件 re.properties 指定信息,创建Cat对象 并调用方法hi |
|
|
|
//1.传统方法 new 对象 -->调用方法 |
|
//Cat cat = new Cat(); |
|
//cat.hi(); |
|
|
|
//2.尝试使用读取文件的方法 |
|
//2.1使用properties类,可以读写配置文件 |
|
Properties properties = new Properties(); |
|
properties.load(new FileInputStream("src\\re.properties")); |
|
String classfullpatch = properties.get("classfullpath").toString(); |
|
String methodName = properties.get("method").toString(); |
|
System.out.println("classfullpath" + classfullpatch); |
|
System.out.println("method" + methodName); |
|
//2.2创建对象 |
|
//使用传统的方法行不通 |
|
|
|
//3.使用反射机制解决 |
|
//3.1加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class) |
|
Class cls = Class.forName(classfullpatch); |
|
|
|
//3.2通过cls得到加载的类 li.reflection.Cat 的一个对象实例 |
|
Object o = cls.newInstance(); |
|
System.out.println("o的运行类型=" + o.getClass());//o的运行类型 |
|
|
|
//3.3通过 cls 得你加载的类 li.reflection.Cat 的methodName"hi" 的方法对象 |
|
// 即:在反射机制中,可以把方法视为一个对象(万物皆对象) |
|
Method method1 = cls.getMethod(methodName); |
|
//3.4通过 method1 调用方法:即通过方法对象来实现调用方法 |
|
System.out.println("========"); |
|
method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象) |
|
|
|
//意义在与反射机制可以通过不求该源码就完成功能的拓展 |
|
/** |
|
* 例如,在Cat类中有两个方法,hi()和cry(),现在要求将调用用的hi方法改为调用cry方法, |
|
* 这时候只需要在配置文件re.properties中修改引用的方法名即可 |
|
* 不需像想传统方法一样,需要在源码中修改 |
|
*/ |
|
} |
|
} |
1.2反射机制
1.2.1Java Reflection
-
反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等,包括private权限的属性和方法),并能够操作对象的属性以及方法。
反射在设计模式和框架底层都会用到
-
加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个Class对象就像一面镜子,透过这个镜子看到了的结构,所以形象地称之为:反射
例如:一个Person类型的实例对象叫 p
则 p 对象 - -> 类型 Person类
Class 对象 cls --> 类型 Class 类(这个类的名字就叫Class)
1.2.2Java反射机制原理图
-
Java反射机制可以完成
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时获取泛型信息
- 在运行时处理注解
- 生成动态代理
1.2.3反射相关类
反射相关的主要类:
- java.lang.Class:代表一个类,Class的对象表示某个类加载过后在堆中的对象
- java.lang.reflect.Method:表示类的方法(Method对象表示某个类的方法)
- java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量)
- java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器)
这些类在 java.lang.reflect
例子:
Cat:
|
package li.reflection; |
|
|
|
public class Cat { |
|
private String name = "招财猫"; |
|
public int age = 10; |
|
|
|
public Cat() { |
|
}//无参构造器 |
|
|
|
public Cat(String name) { |
|
this.name = name; |
|
} |
|
|
|
public void hi() { |
|
System.out.println("hi " + name); |
|
} |
|
|
|
public void cry() { |
|
System.out.println(name + " cry"); |
|
} |
|
} |
re.properties:
|
classfullpath=li.reflection.Cat |
|
method=hi |
Reflection01:
|
package li.reflection; |
|
|
|
import java.io.FileInputStream; |
|
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 { |
|
|
|
//使用properties类,读写配置文件 |
|
Properties properties = new Properties(); |
|
properties.load(new FileInputStream("src\\re.properties")); |
|
String classfullpatch = properties.get("classfullpath").toString(); |
|
String methodName = properties.get("method").toString(); |
|
System.out.println("classfullpath" + classfullpatch); |
|
System.out.println("method" + methodName); |
|
|
|
//反射机制 |
|
//1.加载类,返回一个Class类型的对象cls(这里的Class就是一个类,他的类名就叫Class) |
|
Class cls = Class.forName(classfullpatch); |
|
|
|
//通过cls得到加载的类 li.reflection.Cat 的一个对象实例 |
|
Object o = cls.newInstance(); |
|
System.out.println("o的运行类型=" + o.getClass());//o的运行类型 |
|
|
|
//2.通过 cls得到加载的类 li.reflection.Cat 的methodName"hi" 的方法对象 |
|
// 即:在反射机制中,可以把方法视为一个对象(万物皆对象) |
|
Method method1 = cls.getMethod(methodName); |
|
//通过 method1 调用方法:即通过方法对象来实现调用方法 |
|
System.out.println("========"); |
|
method1.invoke(o);//传统方法: 对象.方法() , 反射机制:方法.invoke(对象) |
|
|
|
//3.java.lang.reflect.Field:表示类的成员变量(Field对象表示某个类的成员变量) |
|
//得到name字段 |
|
//getField不能得到私有的属性 |
|
Field nameField = cls.getField("age"); |
|
System.out.println(nameField.get(o));//传统方法:对象.成员变量 , 反射:成员变量的对象.get(对象) |
|
|
|
//4.java.lang.reflect.Constructor:表示类的构造方法(Constructor对象表示某个类的构造器) |
|
Constructor constructor1 = cls.getConstructor();//()中可以指定构造器的类型,这里返回无参构造器 |
|
System.out.println(constructor1);//Cat() |
|
|
|
Constructor constructor2 = cls.getConstructor(String.class);//这里传入的String.class 就是String类的Class对象 |
|
System.out.println(constructor2);//Cat(String name) |
|
} |
|
} |
1.2.4反射优点和缺点
- 优点:可以动态地创建和使用对象(也是底层框架的核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
- 缺点:使用反射机制基本是解释执行,对执行速度有影响
- 调用反射优化-关闭访问检查
- Method和Field、Constructor对象都有setAccessible()方法
- setAccessible作用是启动和禁用服务安全检查的开关
- 参数值为true表示 反射的对象在使用时 取消访问检查,提高反射效率。参数值为false则表示反射的对象执行访问检查
例子:测试反射调用的性能 和优化方案
|
package li.reflection; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
//测试反射调用的性能 和 优化方案 |
|
public class Reflection02 { |
|
public static void main(String[] args) throws Exception { |
|
m1(); |
|
m2(); |
|
m3(); |
|
} |
|
|
|
//传统方法,调用hi |
|
public static void m1() { |
|
Cat cat = new Cat(); |
|
long start = System.currentTimeMillis(); |
|
for (int i = 0; i < 900000000; i++) { |
|
cat.hi(); |
|
} |
|
long end = System.currentTimeMillis(); |
|
System.out.println("m1() 耗时=" + (end - start)); |
|
} |
|
|
|
//反射机制调用hi |
|
public static void m2() throws Exception { |
|
//拿到Cat类的Class对象 |
|
Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了 |
|
//构造Cat类的对象 |
|
Object o = cls.newInstance(); |
|
//得到Cat类的成员方法 |
|
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 Exception { |
|
//拿到Cat类的Class对象 |
|
Class cls = Class.forName("li.reflection.Cat");//这里为了方便,就不读文件了 |
|
//构造Cat类的对象 |
|
Object o = cls.newInstance(); |
|
//得到Cat类的成员方法 |
|
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)); |
|
} |
|
} |
出处:https://www.cnblogs.com/liyuelian/p/16732313.html
栏目列表
最新更新
一个超经典 WinForm 卡死问题的再反思
C# 计算不规则多边形的相交/包含等关系
.NET Core 引发的异常:“sqlsugar.sqlsugarexcep
快速创建软件安装包-ClickOnce
nuget打包静态资源的问题
要写文档了,emmm,先写个文档工具吧——
乘风破浪,遇见最佳跨平台跨终端框架
【Windows版本控制】上海道宁为您提供Vi
available 处理办法
Visual Studio自定义背景图片
三大常用数据库事务详解之三:事务运行
三大常用关系型数据库事务详解之二:基
三大关系型数据库事务详解之一:基本概
MongoDB常用命令(2)
MongoDB基本介绍与安装(1)
SQLServer触发器调用JavaWeb接口
SQL Server索引的原理深入解析
SqlServer2016模糊匹配的三种方式及效率问题
SQL中Truncate的用法
sqlserver 多表关联时在where语句中慎用tri
在vscode中使用R时,用快捷键来快捷键入卡
VB.NET中如何快速访问注册表
ASP.NET中图象处理过程详解
Vue(1)Vue安装与使用
JavaScript 语言入门
js将一段字符串的首字母转成大写
纯原生html编写的h5视频播放器
H5仿原生app短信验证码vue2.0组件附源码地
TypeScript(4)接口
TypeScript(3)基础类型