java 反射机制_基础篇:深入解析JAVA反射机制

88865cd1a956e36a1cf233252c79e9ab.gif

362414cdf445cefd39f997f8f3440672.png

反射的概念

  • java 的放射机制:在程序运行时,程序有能力获取一个类的所有方法和属性;并且对于任意一个对象,可以调用它的任意方法或者获取其属性

  • 通俗解析:java 文件需要编译成. class 文件才能被 jvm 加载使用, 对象的. class 数据在 jvm 里就是 Class;我们如果能拿到这个 Class对象,就能获取该 Class对应的对象类型,及在该类型声明的方法和属性值;还可以根据 Class创建相应的类型对象,通过 Field,Method 反过来操作对象

  • java 相关类介绍

类名描述
Class代表类的实体,在运行的 Java 应用程序中表示类或者接口
Field类的成员变量(成员变量也称为类的属性)
Method类的方法
Constructor类的构造方法

获取 Class 的三种方法

  • 1 通过已知的类型获取 class
// 根据Example 获取Class =》Example.class
public Class getExample(){
    Class clazz = Example.class;return clazz;
}
  • 2 通过实例对象获取 class
public Class getExampleByInstance(){
    Example example = new Example();
    // getClass是Object类里面的方法;《?》 是通配符
    Class clazz = example.getClass();return (Class)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 getInteger()throws ClassNotFoundException{
    Class clazz = Class.forName("java.lang.Integer");return (Class)clazz;
}

JAVA 反射 API

  • Class 常用操作方法
//获取所有的构造方法 / private public
public Constructor\[\] getDeclaredConstructors()
//获取特定的构造方法 / private public
public Constructor getDeclaredConstructor(Class... parameterTypes)    
//获取类的父类
public native Class 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 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 clazz = Example.class;
        //根据指定构造函数参数获取Constructor
        Constructor 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 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 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对象。可以由 Class 或者 Constructor 实例化对象 instance;根据接口定义,可以获取 Class里的某一方法 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 implements InvocationHandler{
    private T target; //被代理对象
    public T bind(T obj){
        target = obj;return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
           obj.getClass().getInterfaces(),this);
    }
    /\*\* Object o 是代理对象; o的方法调用 -> ExampleFactory.invoke 
    \*  invoke(...) -> 在invoke方法里面 反射调用代理对象方法+增强逻辑
    \*/
    @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 相当于一个中介人
        ExampleFactory factory = new ExampleFactory<>();
        //example 是代理对象
        Face example = exampleProxy.bind(new Example());
        example.hello("思婷");
    }
}
-----log start
思婷 Hello!log end

欢迎指正文中错误

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html div float center,跨浏览器实现float:center

跨浏览器实现float:center互联网 发布时间&#xff1a;2008-10-17 19:26:11 作者&#xff1a;佚名 我要评论原文&#xff1a;http://www.macji.com/blog/article/to-achieve-cross-browser-css-float-center/to-achieve-cross-browser-css-float-center/我们都知道float…

oracle左连接没用_一周零基础学完Oracle数据库第三天02

四、 多表查询1 什么是多表查询多表查询&#xff1a;当查询的数据并不是来源一个表时&#xff0c;需要使用多表链接操作完成查询。根据 不同表中的数据之间的关系查询相关联的数据。多表链接方式&#xff1a; 内连接&#xff1a;连接两个表&#xff0c;通过相等或不等判断链接列…

weblogic启动项目报错找不到类_启动类报错是经常出现的事但是单一的从一个地方找原因会越找越错...

Error starting ApplicationContext. To display the conditions report rerun your application with debug enabled.当我们看到这个报错的时候有的说是jar包重复&#xff0c;有的说是Controller包和Application包处于平行位置&#xff0c;还有的觉得是RequestMapping的valu…

深入理解javascript原型和闭包(7)——原型的灵活性

在Java和C#中&#xff0c;你可以简单的理解class是一个模子&#xff0c;对象就是被这个模子压出来的一批一批月饼&#xff08;中秋节刚过完&#xff09;。压个啥样&#xff0c;就得是个啥样&#xff0c;不能随便动&#xff0c;动一动就坏了。 而在javascript中&#xff0c;就没…

c语言为什么有这么多的编程环境?_为什么98%的程序员学编程都会从C语言开始?...

在互联网蓬勃发展的时代&#xff0c;有一类人做出了巨大的贡献&#xff0c;这一群人被大家称之为程序员&#xff0c;怎样才能成为一名优秀的程序员呢&#xff0c;为什么每一个程序员都需要学习C语言呢&#xff1f;就让我来跟大家分享分享&#xff1a;壹第一&#xff1a;相比较其…

Angular 星级评分组件

一、需求演变及描述&#xff1a; 1. 有一个“客户对公司的总体评价”的字段&#xff08;evalutation&#xff09;。字段为枚举类型&#xff0c;0-5&#xff0c;对应关系为&#xff1a;0-暂无评价&#xff0c;1-很差&#xff0c;2-差&#xff0c;3-一般&#xff0c;4-好&#xf…

计算机网络怎么查看连接打印机驱动,如何检测网络打印机是否已成功连接到计算机[检测方法]...

大概很多婴儿都像以前的编辑一样. 使用网络打印机时&#xff0c;有时它们可​​以打印打印机没有和电脑连接&#xff0c;有时却不能. 那么如何检测网络打印机是否已成功连接到计算机&#xff1f;跟随编辑器往下看.系统反复提示“无法打印”&#xff0c;因此本来很忙的小修几乎快…

a - 数据结构实验之图论一:基于邻接矩阵的广度优先搜索遍历_数据结构--图

故事凌 今天基本知识点图可说是所有数据结构里面知识点最丰富的一个, 自己笨的知识点如下:阶(oRDER), 度: 出度(out-Degree), 入度(in-Degree)树(Tree), 森林(Forest), 环(Loop)有向图(Directed Graph), 无向图(Undirected Graph), 完全有向图, 完全无向图连通图(Connected Gra…

vim: vimrc

2019独角兽企业重金招聘Python工程师标准>>> 打造vim CIDE http://blog.csdn.net/doc_sgl/article/details/47205779 转载于:https://my.oschina.net/u/2528742/blog/843176

计算机二级考试试题在线看,【TOP182015年全国计算机二级考试试题题库.doc文档免费在线阅读材料】...

TOP182015年全国计算机二级考试试题题库.doc文档免费在线阅读《2015年全国计算机二级考试试题题库.doc》由会员分享&#xff0c;可免费在线阅读全文&#xff0c;更多与《TOP182015年全国计算机二级考试试题题库.doc文档免费在线阅读》相关文档资源请在帮帮文库(www.woc88.com)数…

不用开发实现RDS RDWeb门户美化和个性化

个性化RDWeb界面RDWeb原生界面相对比较简洁&#xff0c;每个企业部署的RDWeb都是千篇一律的&#xff0c;有些用户可能希望将网页装饰得个性化点。在谈到自定义Web界面&#xff0c;第一反应可能是使用代码进行编写&#xff0c;但是这里要和大家分享的是无代码美化和自定义RDWeb界…

其他大神的配置 nginx 配置参考

2019独角兽企业重金招聘Python工程师标准>>> user nginx nginx; worker_processes 2; #error_log logs/error.log; error_log logs/error.log notice; #error_log logs/error.log info; pid logs/nginx.pid; google_perftools_profiles /tmp/tcmalloc; worker_rlim…

小孩用计算机做作业怎么表达,计算机作业

满意答案尧Dreaman夕2014.09.25采纳率&#xff1a;40% 等级&#xff1a;10已帮助&#xff1a;1121人Windows中可以设置、控制计算机硬件配置和修改桌面布局的应用程序是( D)A) Word B) Excel C)资源管理器 D)控制面板多窗口的切换可以通过(D )来实现A)在任务栏上用鼠标单击右…

[No0000178]改善C#程序的建议1:非用ICloneable不可的理由

好吧&#xff0c;我承认&#xff0c;这是一个反标题&#xff0c;实际的情况是&#xff1a;我找不到一个非用ICloneable不可的理由。事实上&#xff0c;接口ICloneable还会带来误解&#xff0c;因为它只有一个Clone方法。 我们都知道&#xff0c;对象的拷贝分为&#xff1a;浅拷…

SOM 的两种算法

我参考了这篇文章http://www.scholarpedia.org/article/Kohonen_network另一个很好的演示在这里http://www.math.le.ac.uk/people/ag153/homepage/PCA_SOM/PCA_SOM.htmlSOMt是训练步一个输入数据是n维向量待训练的是一堆节点&#xff0c;这堆节点之间有边连着&#xff0c;通常是…

秒懂,Java 注解 (Annotation)你可以这样学

转自: https://blog.csdn.net/briblue/article/details/73824058 文章开头先引入一处图片。 这处图片引自老罗的博客。为了避免不必要的麻烦&#xff0c;首先声明我个人比较尊敬老罗的。至于为什么放这张图&#xff0c;自然是为本篇博文服务&#xff0c;接下来我自会说明。好了…

Java技术中的三大特性

为什么80%的码农都做不了架构师&#xff1f;>>> 1&#xff0e;虚拟机 Java虚拟机JVM&#xff08;Java Virtual Machine&#xff09;在Java编程里面具有非常重要的地位&#xff0c;约相当…

matlab图像增强分段线性函数_图像增强、锐化,利用 PythonOpenCV 来实现 4 种方法!...

图像增强目的使得模糊图片变得更加清晰、图片模糊的原因是因为像素灰度差值变化不大&#xff0c;图片各区域产生视觉效果似乎都是一样的&#xff0c; 没有较为突出的地方&#xff0c;看起来不清晰的感觉解决这个问题的最直接简单办法&#xff0c;放大像素灰度值差值、使图像中的…

计算机考研保护一志愿,考研良心大学,保护一志愿的考研名校!

大家好&#xff0c;我是&#xff0c;今天胖胖要跟大家送一些重要的干货&#xff0c;就是对于选学校的小伙伴来说也好&#xff0c;或者是即将要参加研究生复试的小伙伴们来好胖胖在这里要跟大家说一个关于考研白名单的事情&#xff0c;因为大家都知道考研是会分黑名单和白名单&a…

华为备份历史版本_华为手机NAS备份时提示“需处于同一局域网”的解决方法

本内容来源于什么值得买APP&#xff0c;观点仅代表作者本人 &#xff5c;作者&#xff1a;噩梦飘雷创作立场声明&#xff1a;在使用华为手机向群晖NAS中备份时发现一直无法成功&#xff0c;经过一番研究找到了解决方案&#xff0c;希望能帮到大家~前言最近看了一位老哥的帖子&a…