编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

大佬,到底什么是Java的反射? java什么是反射,怎么使用

gowuye 2024-04-04 11:58 2 浏览 0 评论


什么是反射

JAVA反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

一般情况下,我们使用类来创建对象都是一开始就知道具体的类型以及类的用途,直接通过类来创建对象

Order order = new Order(new BigDecimal(4.32));
order.getPrice();

而反射是一开始不知道我需要初始化的类是什么,到实际运行的时候才知道具体的类型,此时只能通过反射的API来创建对象

Class clazz = Class.forName("org.kxg.reflection.Order");
Method method = clazz.getMethod("getPrice");
Constructor constructor = clazz.getConstructor(BigDecimal.class);
Object object = constructor.newInstance(new BigDecimal(4.4));
method.invoke(object);

上面两种方式的效果是一样的,都是创建了Order对象,调用Order对象的getPrice()方法,只不过一个是普通调用、一个是反射调用

所以简单来说,反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法

为什么需要反射

Java在不同的时期可以分成两种编译类型:

  • 静态编译:就是我们常用的方式,在编译时就确定的类型
  • 动态编译:在编译时无法确认类型,到运行才确定类型

动态编译发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性

Java反射是Java被视为动态语言的一个关键性质。

这个机制允许程序在运行时通过反射取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

Reflection可以在运行时加载、探知、使用编译期间完全未知的classes。

即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods

反射是解决什么问题?

反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。 在静态语言中,使用一个变量时,必须知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才能保证准确无误;换句话说,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了

一句话概括就是使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现,例如热加载,Tomcat的classloader等等都没法支持

反射常用API

1、反射获取Class对象

//方式一:通过Class.forName()获取Class
Class c1 = Class.forName("org.kxg.reflection.Order");

//方式二:使用.class方法
Class c2 = Order.class;

//方式三:通过getClass()方法
Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();

2、通过反射创建类对象

//方式一:通过Class对象的newInstace()方法创建对象
Class c1 = Class.forName("org.kxg.reflection.Order");
Order o1 = (Order) c1.newInstance();

//方式二:通过Constructor对象的newInstance()方法创建对象
Class c2 = Order.class;
Constructor constructor = c2.getConstructor(Order.class);
Order o2 = (Order) constructor.newInstance();

3、获取类的属性

Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();

//只能获取除私有以外的属性
Field[] fields = c3.getFields();
//获取所有属性
Field[] fields1 = c3.getFields();

4、获取类方法

Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
Method[] methods = c3.getMethods();

5、获取注解

Order o = new Order(new BigDecimal(1));
Class c3 = o.getClass();
Annotation[] annotations = c3.getAnnotations();

反射实现动态代理

实现方式:利用Java的反射机制,在java.lang.reflect 包下提供了Proxy类和InvocationHandler 接口来实现动态代理

下面以增加日志的需求来演示一下JDK动态代理的用法

//抽象对象
public interface CustService {
  public void editCust();
}

//真实对象
public class CustServiceImpl implements CustService {
  public void editCust() {
    System.out.println("edit cust ----");
  }
}

//日志对象
public class LogService {
  public void addLog(){
    System.out.println("add log ----");
  }
}

//动态代理对象
public class JDKProxyCustService implements InvocationHandler {

  private Object target;
  private LogService logService = new LogService();

  public JDKProxyCustService(Object target){
    this.target = target;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String methodName = method.getName();
    System.out.println("methodName:" + methodName );
    logService.addLog();
    Object o = method.invoke(target,args);
    logService.addLog();
    return o;
  }
}

//测试
public class TestJDKProxy {

  public static void main(String[] args){
    CustService custService = new CustServiceImpl();
    Class c = custService.getClass();
    ClassLoader classLoader = c.getClassLoader();//目标对象的类加载器
    Class[] interfaces = c.getInterfaces();//目标对象实现的所有接口
    InvocationHandler h = new JDKProxyCustService(custService);//获取一个InvocationHandler,并将custService对象传入

    /**
     * 参数说明:
     * 1.classLoader表示目标对象的类加载器
     * 2.interfaces表示目标对象实现的所有接口
     * 3.InvocationHandler接口的实现
     */
    CustService proxy = (CustService) Proxy.newProxyInstance(classLoader,interfaces,h);
    proxy.editCust();
  }
}

运行结果:
methodName:editCust
add log ----
edit cust ----
add log ----

每个动态代理类(JDKProxyCustService)都必须实现InvocationHandler接口,当我们通过代理对象调用方法时,调用会被转到InvocationHandler接口的invoke方法。

public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

proxy:被代理的真实对象 method:调用真实对象的某个方法 args:调用真实对象某个方法所传的参数

实际上,真正有用的代码是:

Object o = method.invoke(target,args);

利用Java的反射机制,动态的去调用目标对象的方法。 再来看看Proxy类,我们在测试类中真正有用的代码是:

CustService proxy = (CustService) Proxy.newProxyInstance(classLoader,interfaces,h);

Proxy类的作用就是创建一个动态代理对象的类,newProxyInstance方法的作用是创建一个动态代理的对象 参数说明: classLoader:目标对象的类加载器 interfaces:目标对象所实现的所有接口 h:InvocationHandler接口的实现

还有这句:

InvocationHandler h = new JDKProxyCustService(custService);

传入需要代理的真实对象,实现调用的就是真实对象的方法

参考:

https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html

https://blog.csdn.net/grandgrandpa/article/details/84832343

相关推荐

PHPMailer远程命令执行漏洞分析

摘要:PHPMailer是一个强大的PHP编写的邮件发送类,但近日被爆出远程命令执行漏洞,该漏洞实际上是什么,有何种影响,本文对该漏洞进行了分析及验证方法,并给出防护方案。0x00漏洞概要PHPMa...

「安全漏洞」DedeCMS-5.8.1 SSTI模板注入导致RCE

漏洞类型SSTIRCE利用条件影响范围应用漏洞概述2021年9月30日,国外安全研究人员StevenSeeley披露了最新的DedeCMS版本中存在的一处SQL注入漏洞以及一处SSTI导致的RCE...

回顾使用PHP原生发送电子邮件(终)文件附件

FileAttachments文件附件Fileattachmentsworkjustlikemixedemail,exceptthatadifferentcontenttyp...

php-fpm.conf & php.ini 安全优化实践

0x01关于php其历史相对已经比较久远了,这里也就不废话了,属弱类型中一种解释型语言除了web开发以及写些简单的exp,暂未发现其它牛逼用途,暂以中小型web站点开发为主另外,低版本的php自身...

linux 安全配置 ossec 开源检测

linux安全配置ossec开源检测一:介绍主要功能有日志分析、完整性检查、rootkit检测、基于时间的警报和主动响应。除了具有入侵检测系统功能外,它还一般被用在SEM/SIM(安全事件管理(...

PHP使用PHPMailer发送验证码邮件的方法与调用逻辑

首先我们需要下载PHPMailer:https://github.com/PHPMailer/PHPMailer一般情况下我们只需要压缩包中的src文件夹中的文件,并保存至根目录即可:设置一个文件,如...

回顾使用PHP原生发送电子邮件(一)

IwishIcouldremembertheveryfirstemailmessageIeversent.Unfortunately,thetruthisthatI...

PHPMAILER实现PHP发邮件功能php实例

这篇文章主要为大家详细介绍了PHPMAILER实现PHP发邮件功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下本文实例为大家分享了PHPMAILER实现PHP发邮件功能的具体代码,供大家参考,具...

500道网络安全面试题集锦(附答案)

本篇文章内容为网络安全各个方向涉及的面试题,星数越多代表问题出现的几率越大,但是无论如何都无法覆盖所有的面试问题,更多的还是希望由点达面,查漏补缺,然后祝各位前程似锦,都能找到自己满意的工作!一、We...

网站放家里,随处看电影「Apache+php+ssl 安装和配置」

  使用5G网络,随处都可以看到放自己家里电脑的视频。这个功能很容易实现,不需要太多的专业知识,也不需要额外花钱。如果确实需要,最多花不到两百块钱买一台旧电脑放家里,做个网站,就能解决全部问题,Fre...

Windows2008中 Magic Winmail Server提权

MagicWinmailServer是安全易用全功能的邮件服务器软件,不仅支持SMTP/POP3/IMAP/Webmail/LDAP(公共地址簿)/多域/发信认证/反垃圾邮件/邮件过滤/邮件组...

利用PHPmailer发送邮件

早上帮朋友做一个收集客户联系方式的页面,要求能实时推送信息给管理员。刚开始想到做后台管理,因为时间紧,做后台是赶不上了。想过通过短信发送,成本太高,否决了。。。灵机一动,客户提交时直接把信息发送到邮箱...

phpmailer发送邮件

phpmailer发送邮件PHP内置的mail函数使用起来不够方便,另外受其他语言的影响,博主更偏好面向对象的包管理模式,因此phpmailer成为了我用PHP发送邮件的首选,这里分享给大家。库导入这...

PHP初级教程:读取输入

PHP读取输入:Form:?formaction="welcome.php"method="post">Name:(inputtype="text...

php filter 验证Email,Url,Ip格式

今天发现一个非常好用的函数东西,filter过滤器,用于验证和过滤来自非安全来源的数据,比如用户的输入。验证Email:$email='1234567@qq.com';if(!filter_v...

取消回复欢迎 发表评论: