1、反射使用的背景

  最近在做一个功能,就是实现邮件发送功能,但是邮件发送有不同的内容和数据格式,在开始设计的时候直接将发送的内容写在了发送模块中,后来发现功能增加后,无法继续在里边写了,因为里边的功能已经固定住了,只好重新添加一个发送模块 ,这样就相当于维护了两套代码,发送功能和发送格式配置代码耦合太严重,一直想着重构这个功能,后来有时间了,开始考虑重构了。

  一直在想我的发送功能是固定的,如何把发送的不同内容和格式抽取取来呢,以后添加新内容,只需把样式和格式的类写好,发送模块会自动匹配要发送的内容呢;一开始想到用多态,父类去调用子类的功能,但是发现一个问题,就是每次调用的时候需要通过 Fu f = new Zi() 这种模式进行创建对象,但是在发送模块不能确定使用哪个子类去创建,在不改变代码的情况下无法做到new Zi()的动态化;

  后来相当了,如果我每次发送不同功能的时候,可以读取配置文件来确定使用哪个类进行调用,然后发送这个类的内容和格式,这时候突然想到了使用反射技术,在发送模块我写成反射模式,反射的时候调用的通过读取配置文件来确定所要调用的类和方法,每次添加了新功能,我只要设置配置文件,那么反射的代码可以更具配置去使用该类,然后调用其方法,完全做到了发送模块与内容格式的分离,不需要再去维护发送模块了。nice!!!

反射技术是实现各大框架的重要技术之一!

2、过程描述

从图中看出 反射地方可以根据配置文件自动的实现调用不同的功能,所以说 以后当我们新增功能的时候,我们只需要写好对应的类以及对应配置文件,那么就会自动调用新增代码了;

3、反射技术的原理

3.1、获取class的方式 通用方式

  Class car = Class.forName("com.gxy.src.Car");   //注意此字符串必须是真实路径,就是带包名的类路径,包名.类名

3.2、获取class的构造函数

1.获取构造方法:
  1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
    Constructor[] con = car .getDeclaredConstructors();
     
  2).获取单个的方法,并调用:
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
    Constructor con = clazz.getConstructor(null);
    Constructor con = clazz.getConstructor(Char.class);
  调用构造方法:
Constructor-->newInstance(Object... initargs)
  Object obj = con.newInstance();
  Object obj = con.newInstance('r');
 

2、newInstance是 Constructor类的方法(管理构造函数的类)

api的解释为:
newInstance(Object... initargs)
           使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

3.3、获取class的方法 通过代码来看

//获取类中所有的方法。
public static void method_1() throws Exception {
Class clazz = Class.forName("com.makaruina.reflect.Person");
//获取的是该类中所有的公有方法,包含继承和实现的方法。
Method[] methods = clazz.getMethods();
//获取的是该类中的所有方法,包含私有方法,但不包含继承的方法。
methods = clazz.getDeclaredMethods();
for(Method method : methods) {
System.out.println(method);
}
}
//获取指定方法;
public static void method_2() throws Exception {
Class clazz = Class.forName("com.makaruina.reflect.Person");
//获取指定名称的方法。
Method method = clazz.getMethod("show", int.class,String.class);
//想要运行指定方法,当然是方法对象最清楚,为了让方法运行,调用方法对象的invoke方法即可,但是方法运行必须要明确所属的对象和具体的实际参数。
Object obj = clazz.newInstance();
method.invoke(obj, 39,"hehehe");//执行一个方法
}
//想要运行私有方法。
public static void method_3() throws Exception {
Class clazz = Class.forName("com.makaruina.reflect.Person");
//想要获取私有方法。必须用getDeclearMethod();
Method method = clazz.getDeclaredMethod("method", null);
// 私有方法不能直接访问,因为权限不够。非要访问,可以通过暴力的方式。
method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问。
}
//反射静态方法。
public static void method_4() throws Exception {
Class clazz = Class.forName("com.makaruina.reflect.Person");
Method method = clazz.getMethod("function",null);
method.invoke(null,null);
}

3.3、获取class的属性 通过代码来看

* 获取成员变量并调用:
*
* 1.批量的
* 1).Field[] getFields():获取所有的"公有字段"
* 2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
* 2.获取单个的:
* 1).public Field getField(String fieldName):获取某个"公有的"字段;
* 2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
*
* 设置字段的值:
* Field --> public void set(Object obj,Object value):
* 参数说明:
* 1.obj:要设置的字段所在的对象;
* 2.value:要为字段设置的值;

3.4、获取main方法 通过代码来看

try {
//1、获取Student对象的字节码
Class clazz = Class.forName("fanshe.main.Student"); //2、获取main方法
Method methodMain = clazz.getMethod("main", String[].class);//第一个参数:方法名称,第二个参数:方法形参的类型,
//3、调用main方法
// methodMain.invoke(null, new String[]{"a","b","c"});
//第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
//这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。。。所以需要将它强转。
methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二 } catch (Exception e) {
e.printStackTrace();
}

4、通过反射可以越过泛型检查

为什么泛型可以越过泛型检查  ---  泛型用在编译期,编译过后泛型擦除(自动失效)。

举例:

ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb"); // strList.add(100);
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100); //遍历集合
for(Object obj : strList){
System.out.println(obj);
}

  

使用JAVA反射技术实现代码零耦合与功能无限扩展!的更多相关文章

  1. java 反射技术

    什么是反射?反射就是将字节码中的各种成分映射到相应的java类中来,java反射技术自JDK1.1以来就出现了,目前大多数流行的框架都采用了这种技术,可见其重要性,这篇文章将详细介绍我对java反射技 ...

  2. java反射技术实例

    java反射技术实例​1. [代码][Java]代码     package com.gufengxiachen.java.reflectiontest; public class Person {p ...

  3. Android 插件化开发(一):Java 反射技术介绍

    写在前面:学习插件化开发推荐书籍<Android 插件化开发指南>,本系列博客所整理知识部分内容出自此书. 在之前的项目架构的博文中,我们提到了项目插件化架构,提到插件化架构不得不提的到J ...

  4. Android中Java反射技术的使用示例

    import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Metho ...

  5. java反射技术主要实现类有哪些,作用分别是什么

    Java反射技术主要实现类有哪些,作用分别是什么? 在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中 1)Class类:代表一个类 2)Field 类 ...

  6. Android系统原理与源码分析(1):利用Java反射技术阻止通过按钮关闭对话框

    原文出处:博主宇宙的极客http://www.cnblogs.com/nokiaguy/archive/2010/07/27/1786482.html 众所周知,AlertDialog类用于显示对话框 ...

  7. 由浅入深理解----java反射技术

    java反射机制详解 java反射机制是在运行状态下,对任意一个类可以获取该类的属性和方法,对任意一个对象可以调用其属性和方法.这种动态的获取信息和调用对象的方法的功能称为java的反射机制 clas ...

  8. java反射机制学习代码

    根据 http://www.iteye.com/topic/137944 文档进行学习 代码如下: package reflectTest; import java.lang.reflect.*; i ...

  9. JAVA反射技术的使用

    前言 在开发html使用jquery提交post的时候,可以使用jquery遍历from元素里面的input元素实现参数组合,这样就不用手动打参数了,特别是在参数很多的时候,费神费时. 我开发Andr ...

随机推荐

  1. pytorch bug

    ImportError: torch.utils.ffi is deprecated raise ImportError("torch.utils.ffi is deprecated. Pl ...

  2. 手动实现一个虚拟DOM算法

    发现一个好文:<深度剖析:如何实现一个 Virtual DOM 算法> 源码 文章写得非常详细,仔细看了一遍代码,加了一些注释.其实还有有一些地方看的不是很懂(毕竟我菜qaq 先码 有时间 ...

  3. 异步请求中jetty处理ServletRequestListener的坑

    标题起得比较诡异,其实并不是坑,而是jetty似乎压根就没做对异步request的ServletRequestListener的特殊处理,如果文中有错误欢迎提出,可能自己有所疏漏了. 之前遇到了一个b ...

  4. Java核心技术及面试指南 流程控制方面的面试题答案

    2.2.5.1 switch语句能否作用在byte上,能否作用在long上,能否作用在String上? 1 switch里可以用char,byte,short,int这些基本类型,以及它们的封装类.  ...

  5. ReentrantLock 详解

    ReentrantLock的功能是实现代码段的并发访问控制,也就是通常意义上所说的锁,java中实现锁有两种方式,一种是本文所提的ReentrantLock,另一种是synchronized.Reen ...

  6. Apache-Flink深度解析-概述

    摘要: Apache Flink 的命脉 "命脉" 即生命与血脉,常喻极为重要的事物.系列的首篇,首篇的首段不聊Apache Flink的历史,不聊Apache Flink的架构, ...

  7. 支付宝客户端架构解析:Android 容器化框架初探

    摘要: 本文将介绍支付宝 Android 容器化框架设计的基本思路. 1. 前言 由本章节开始,我们将从支付宝客户端的架构设计方案入手,细分拆解客户端在“容器化框架设计”.“网络优化”.“性能启动优化 ...

  8. The 2018 ACM-ICPC Asia Qingdao Regional Contest(部分题解)

    摘要: 本文是The 2018 ACM-ICPC Asia Qingdao Regional Contest(青岛现场赛)的部分解题报告,给出了出题率较高的几道题的题解,希望熟悉区域赛的题型,进而对其 ...

  9. MySQL系列详解五: xtrabackup实现完全备份及增量备份详解-技术流ken

    xtrabackup简介 xtrabackup是一个用来对mysql做备份的工具,它可以对innodb引擎的数据库做热备.xtrabackup备份和还原速度快,备份操作不会中断正在执行的事务,备份完成 ...

  10. 关于Vue数组操作

    Vue的数组操作的实现代码大致如下: const aryMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse ...