基础篇:深入解析JAVA反射机制
反射的概念
- java的放射机制:在程序运行时,程序有能力获取一个类的所有方法和属性;并且对于任意一个对象,可以调用它的任意方法或者获取其属性
- 通俗解析:java文件需要编译成.class文件才能被jvm加载使用,对象的.class数据在jvm里就是Class<T>;我们如果能拿到这个Class<T>对象,
就能获取该Class<T>对应的对象类型,及在该类型声明的方法和属性值;还可以根据Class<T>创建相应的类型对象,通过Field,Method反过来操作对象 - java相关类介绍
类名 | 描述 |
---|---|
Class<T> | 代表类的实体,在运行的Java应用程序中表示类或者接口 |
Field | 类的成员变量(成员变量也称为类的属性) |
Method | 类的方法 |
Constructor<T> | 类的构造方法 |
获取Class的三种方法
- 1通过已知的类型获取class
// 根据Example 获取Class =》Example.class
public Class<Example> getExample(){
Class<Example> clazz = Example.class;
return clazz;
}
- 2通过实例对象获取class
public Class<Example> getExampleByInstance(){
Example example = new Example();
// getClass是Object类里面的方法;《?》 是通配符
Class<?> clazz = example.getClass();
return (Class<Example>)clazz;
}
- 3通过Class.forName获取全路径指定类名的class
/** forName0 本地方法,C++实现,jvm调用
* 1 className 是个类名 2 initialize 是否延迟加载 3 loader 加载器
*/
private static native Class<?> forName0(String className, boolean initialize,
ClassLoader loader, Class<?> caller) throws ClassNotFoundException;
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
// 两个forName方法最终都会调用forName0方法去加载class
public static Class<?> forName(String name,
boolean initialize, ClassLoader loader) throws ClassNotFoundException {
....
return forName0(name, initialize, loader, caller);
}
// 示例:通过java.lang.Integer
public Class<Integer> getInteger()throws ClassNotFoundException{
Class<?> clazz = Class.forName("java.lang.Integer");
return (Class<Integer>)clazz;
}
JAVA反射API
- Class常用操作方法
//获取所有的构造方法 / private public
public Constructor<?>[] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//获取类的父类
public native Class<? super T> getSuperclass()
//获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)
//获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()
//获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException
//根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//获取类型的定义的所有属性
public Field[] getFields() throws SecurityException
// 根据属性命名获得特定的Field
public Field getField(String name)
- Method常用的操作方法
//获得方法的放回类型
public Class<?> getReturnType()
//获得方法的传入参数类型
public Class<?>[] getParameterTypes()
//obj是实例对象,args是方法,反过来由Method控制对象的方法调用
public Object invoke(Object obj, Object... args)
- Field常用的操作方法
//属性与obj相等则返回true
public boolean equals(Object obj)
//获得obj中对应的属性值
public Object get(Object obj)
//设置obj中对应属性值
public void set(Object obj, Object value)
- Constructor
//根据传递的参数创建类的对象:initargs 构造方法参数
public T newInstance(Object... initargs)
- 1根据class创建对象
//方式一 clazz.newInstance()
Class<Example> clazz = Example.class;
Example example = clazz.newInstance();
//方式二 先获取再由Constructor:clazz.getConstructors()/getConstructor(...)
//再由Constructor.newInstance 方法构造对象
-----------------------------------------
public class Example {
private int value;
public Example(){ } // 如果只声明有参构造函数,clazz.newInstance()会报错
public Example(Integer value){ this.value = value; }
static public void main(String[] args) throws Exception{
Class<Example> clazz = Example.class;
//根据指定构造函数参数获取Constructor
Constructor<Example> constructor = clazz.getConstructor(Integer.class);
Example example = constructor.newInstance(100);
System.out.println(example.value);
}
}
- 2由class获取Field,并操作实例的属性
public class Example {
private int value , count;
static public void main(String[] args) throws Exception{
Class<Example> clazz = Example.class;
//获取所有的属性,getField只能获取public的属性
Field[] fs = clazz.getDeclaredFields();
//根据名称获取指定 Field
Field value = clazz.getDeclaredField("value");
Example example = clazz.newInstance();
//使用反射机制可以打破封装性,导致了java对象的属性不安全
value.setAccessible(true); //setAccessible(true)让private的参数可赋值操作
//由Field反过去设置example的值
value.set(example,100);
System.out.println(example.value);
}
}
- 3由class获取Method,并反射调用实例方法
public class Example {
public static void main(String[] args) throws Exception {
Class<Example> clazz = Example.class;
Example example = clazz.newInstance();
Method[] methods = clazz.getDeclaredMethods();
//getDeclaredMethod和getMethod是:getMethod只能返回public的方法
Method method = clazz.getDeclaredMethod("hello", String.class);
method.setAccessible(true);
method.invoke(example, "cscw");
}
private void hello(String name) { System.out.println(name + " Hello!"); }
}
-----
cscw Hello!
反射机制应用的场景
- 1 动态拓展:假设有同一组类是实现相同的接口,并且类的加载方式不限制。当我们需要那种具体类实现的功能时,只需加载.class文件,并获取对应的Class<T>对象。可以由Class或者Constructor实例化对象instance;根据接口定义,可以获取Class<T>里的某一方法Method,并配合instance调用功能方法
- 2 Spring的IOC就是基于反射机制实现
- 3 JDK的动态代理
反射和JDK动态代理
- 在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口。通过这个类和接口可以生成JDK动态代理类或动态代理对象
public interface InvocationHandler {
//所有方法都会调用此代理方法
Object invoke(Object var1, Method var2, Object[] var3) throws Throwable;
}
public class Proxy implements Serializable{
...
//根据interfaces和InvocationHandler生成代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
...
}
- JDK的动态代理由Proxy和InvocationHandler实现;而被代理对象必须实现一个接口。代理对象由Proxy生成,可转为接口interface的实现类对象OBJ。当调用OBJ的方法时,则会触发InvocationHandler.invoke,参数依次为代理对象,Method对象,和方法Method所需的参数。在invoke方法可以加入拓展的逻辑,如日志记录操作;并可以在invoke里利用反射的技术调用 被代理对象方法
- 示例
public class ExampleFactory<T> implements InvocationHandler{
private T target;
public T bind(T obj){
target = obj;
return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//增强逻辑
System.out.println("log start");
//反射调用被代理对象方法
Object result = method.invoke(target,objects);
System.out.println("log end");
return result;
}
}
-----------
public interface Face {
void hello(String name);
}
---------
//被代理对象必须实现一个接口,并由接口方法对方提供功能
public class Example implements Face {
public void hello(String name) {
System.out.println(name + " Hello!");
}
public static void main(String[] args) {
//ExampleFactory<Face> 相当于一个中介人
ExampleFactory<Face> factory = new ExampleFactory<>();
//example 是代理对象
Face example = exampleProxy.bind(new Example());
example.hello("思婷");
}
}
-----
log start
思婷 Hello!
log end
欢迎指正文中错误
关注公众号,一起交流
参考文章
基础篇:深入解析JAVA反射机制的更多相关文章
- Java 基础之详解 Java 反射机制
一.什么是 Java 的反射机制? 反射(Reflection)是Java的高级特性之一,是框架实现的基础,定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- Java开发培训基础知识解析之反射机制
Java是老牌编程语言,是当前应用最广泛的编程语言之一.想要学习Java你就一定要掌握Java基础知识,而反射对于初学Java的人来说绝对是非常重要的知识点.什么是反射?如何理解反射机制?如何使用反射 ...
- 深入解析Java反射(1) - 基础
深入解析Java反射(1) - 基础 最近正筹备Samsara框架的开发,而其中的IOC部分非常依靠反射,因此趁这个机会来总结一下关于Java反射的一些知识.本篇为基本篇,基于JDK 1.8. 一.回 ...
- java基础知识(十一)java反射机制(上)
java.lang.Class类详解 java Class类详解 一.class类 Class类是java语言定义的特定类的实现,在java中每个类都有一个相应的Class对象,以便java程序运行时 ...
- java反射机制(基础版)
package com.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import ja ...
- 深入解析Java反射基础
博客原文:http://www.sczyh30.com/posts/Java/java-reflection-1/ - 这老哥写的特别好 一.回顾:什么是反射? 反射(Reflection)是Java ...
- 【java基础】Java反射机制
一.预先需要掌握的知识(java虚拟机) 1)java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存 ...
- Java反射机制(Reflect)解析-----https://www.cnblogs.com/fzz9/p/7738381.html
Java反射机制(Reflect)解析-----https://www.cnblogs.com/fzz9/p/7738381.html
随机推荐
- Python中pytesseract库的使用以及注意事项
当我们在使用pytesseract库的时候,使用 pip install pytesseract安装完成后,发现它并不能识别出图片内容,并且会抛出异常pytesseract.pytesseract.T ...
- 简单实现C++Stack模板
栈的特点是先进后出以及只能在栈顶进行插入和删除操作 本次实现的栈的基本操作: 1)弹栈 2)压栈 3)求栈大小 4)求栈容量 5)判断栈空 6)获取栈顶元素 1.用数组的方式实现栈基本操作 /** * ...
- Hadoop 3.x 与Hadoop 2.x 的区别和优化点
Hadoop 3.x 与Hadoop 2.x 的区别和优化点 通用性 1.精简Hadoop内核,包括剔除过期的API和实现,将默认组件实现替换成最高效的实现(比如将FileOutputCommitte ...
- 兼容低版本IE浏览器的一些心得体会(持续更新)
前言: 近期工作中,突然被要求改别人的代码,其中有一项就是兼容IE低版本浏览器,所以优雅降级吧. 我相信兼容低版本IE是许多前端开发的噩梦,尤其是改别人写的代码,更是痛不欲生. 本文将介绍一些本人兼容 ...
- 2020.08.14小bug
页面下面的滚动条怎么清除 css overflow-x: hidden;
- 史上!最最最简洁明了的 Java JDK 安装目录及其子目录含义 10分钟详解 - 精简归纳
Java JDK 安装目录及其子目录含义 10分钟详解 - 精简归纳 JERRY_Z. ~ 2020 / 8 / 30 转载请注明出处!️ 目录 Java JDK 安装目录及其子目录含义 10分钟详解 ...
- 深入浅出 Java JDK 安装目录及其子目录含义 10分钟详解 - 精简归纳
Java JDK 安装目录及其子目录含义 10分钟详解 - 精简归纳 JERRY_Z. ~ 2020 / 8 / 30 转载请注明出处!️ 目录 Java JDK 安装目录及其子目录含义 10分钟详解 ...
- Python 到底是强类型语言,还是弱类型语言?
0.前言 我在上一篇文章中分析了 为什么 Python 没有 void 类型 的话题,在文章发布后,有读者跟我讨论起了另一个关于类型的问题,但是,我们很快就出现了重大分歧. 我们主要的分歧就在于:Py ...
- vue bus 中央事件总线
1.全局定义bus 新建src/eventBus.js 文件 import Vue from 'vue' export default new Vue() // 全局引入mai.jsvue中央事件总 ...
- ASP.NET Uploadify 上传文件过大 报错(http error)借鉴,以防忘记
Uploadify上传文件原来很早之前用过,没发现什么问题.今天再使用过程中,当文件大于30M的时候就会报错404.查看错误消息提示配置最大上传太小了.需要修改. 记得原来配置上传文件大小在这里:&l ...