上一页已经推出反映的一些基本概念,这主要是通过一个例子反映谈的过程,以及样品的实际应用。

这个样例是这种设计思路:从一个属性文件里读取一段字符串,然后,依据该字符串生成相应的类实例对象;这之后另一个增强版的样例,能够依据类里面的setter()方法将类的成员变量(引用类型)也进行初始化,Spring框架是这么实现的。

项目结构例如以下:

本样例包含三个类

1.reflect.properties属性文件,里面为key-value键值对。例如以下

name=javax.swing.JFrame

useraction=com.tgb.reflect.UserAction

2.UserAction.java。Action类

<span style="font-size:14px;">public class UserAction {

		public void addUser()
{
System.out.println("加入用户");
}
}</span>

3.ObjectPoolFactory.java,该类负责读取文件,实例化对象

<span style="font-size:14px;">public class ObjectPoolFactory {

		//定义一个对象池,採用key-value key为对象名、value为对象
private Map<String, Object> objectPool=new HashMap<>(); //定义一个创建对象的方法。參数为字符串 类名
private Object createObject(String clazzName)
throws InstantiationException,IllegalAccessException,ClassNotFoundException
{
//依据字符串来获取相应的class对象
Class<? > clazz=Class.forName(clazzName); return clazz.newInstance();
} //从属性文件里读取key-value初始化类的实例,也能够利用dom4j从配置文件里读取
public void initPool(String fileName)
throws InstantiationException,IllegalAccessException,ClassNotFoundException
{
try(FileInputStream fis=new FileInputStream(fileName))
{
Properties pros=new Properties();
//从输入流载入属性文件
pros.load(fis);
//循环属性文件里的key
for(String name:pros.stringPropertyNames())
{
//取出key-value,依据value创建对象,并放入对象池中
objectPool.put(name, createObject(pros.getProperty(name)));
} } catch (Exception e) {
e.printStackTrace();
}
} public Object getObject(String name)
{
return objectPool.get(name);
}
public void test()
throws InstantiationException, IllegalAccessException, ClassNotFoundException
{
String path=this.getClass().getResource("/com/tgb/reflect/reflect.properties").toString();
path=path.substring(path.indexOf("/")+1);
System.out.println(path); ObjectPoolFactory opf=new ObjectPoolFactory();
opf.initPool(path); UserAction userAction=(UserAction)opf.getObject("useraction");
userAction.addUser(); } public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException
{
ObjectPoolFactory opf=new ObjectPoolFactory();
opf.test();
}</span>

此类中。主要是createObject()这种方法创建实例对象。然后又调用Class类的forName()方法,该方法返回的是一个类的Class对象。再利用Class对象的newInstance()返回它所代表的类的实例。

我们用一个map对象来存储一个已经创建好的对象,作为对象池使用。Class<?>这里使用了类型通配符。代表的意思是Class对象的类型,这次Class对象未知因此使用了类型通配符,这里事实上使用类型參数也是能够的,如Class<T>,至于类型參数与类型通配符差别以后会介绍。

那么跟类载入器有什么关系呢?

我们能够看一下JDK源代码。forName()这种方法重载了两个,有一个是须要提供类载入器这个參数的,如

<span style="font-size:14px;">    @CallerSensitive
public static Class<? > forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
if (loader == null) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
if (ccl != null) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader);
}</span>

这种方法是forName()參数最多。重载之前的方法,它为我们提供了默认的类载入器,里面还有关于一些安全方面的处理推断。

执行结果例如以下:

我们能够看到上面程序UserAction的addUser()已经运行,表名创建实例成功。

接下来我们完好该方法,实现对UserAction里面的一个引用属性赋值,改动UserAction例如以下添加了一个setter()方法,这里你也就知道setter()方法的作用,Spring进行诸如时就是依据setter()来给依赖属性注入的。

UserAction.java

<span style="font-size:14px;">public class UserAction {
//依赖属性
private UserManager userManager; public void addUser()
{
System.out.println("运行UserAction的addUser()方法");
}
//属性的set方法
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
}</span>

在工厂类里面主要多了一个初始化属性的方法。其余有略微修改但基本类似,例如以下

<span style="font-size:14px;">//初始化类的属性。也能够利用dom4j从配置文件里读取
public void initProperty()
throws InstantiationException,IllegalAccessException,ClassNotFoundException
{
try
{
//循环属性文件里的key
for(String name:pros.stringPropertyNames())
{
if (name.contains("%")) {
String[] namesArray=name.split("%");
Object target=getObject(namesArray[0]); Class<? > targetClass=target.getClass();
String mName="set"+namesArray[1].substring(0,1).toUpperCase()+namesArray[1].substring(1);
//得到目标对象userManager属性的set方法
//第一个參数为方法名、第二个为set方法中传入的參数类型,即UserManager.class=userManager.getClass()
Method m=targetClass.getMethod(mName,getObject(name).getClass());
//调用set方法给属性赋值
m.invoke(target,getObject(name));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}</span>

通过看凝视大家也能够理解,和上面类似这里仅仅只是是找到属性相应的实例。然后,通过set方法把这个实例给属性赋值的。

属性文件改为了例如以下变量值:

name=javax.swing.JFrame

useraction=com.tgb.reflect.UserAction

useraction%userManager=com.tgb.reflect.UserManager

第三句用一个%切割,前面代表类后面代表该类的属性。该属性主要用于拼接set方法名。由于得到set方法时须要用到这个作为參数。

至此,反射的基本内容就介绍完了,相信大家通过上面的一些概念和简单的实例已经理解了反射的原理是怎么实现的,非常多框架也是利用这一个过程通过xml配置文件来实例化各种类,所不同的是框架对于xml里面的标签已经作为限制,道理和读取属性文件是一样的,xml文件包括的信息会更丰富一些,这样在解析xml和实例化对象时也会更复杂一些。通过配置文件来处理类之间的各种关系。

我们通常接触到的AOP、IOC、容器、另一些注解原理都依赖反射实现。多了解一些反射的机制是非常有优点的。

非常多内容在内部都是有联系的,把它们都相互联系起来比較着学习和应用才会掌握的更好。

版权声明:本文博客原创文章,博客,未经同意,不得转载。

JAVA基金会 (三)反射 反思的深度分析的更多相关文章

  1. java基础(三):反射、反序列化破解单列模式和解决方式

    单例模式指的是一个类只有一个对象,通过一些措施达到达到这个目的.但是反射和反序列化可以获得多个不同的对象. 先简单的认识一下单例模式 一:单例模式 通过私有构造器,声明一个该类的静态对象成员,提供一个 ...

  2. 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)

    写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...

  3. 【JVM】深度分析Java的ClassLoader机制(源码级别)

    原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...

  4. 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

    原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...

  5. java集合框架(1) hashMap 简单使用以及深度分析(转)

    java.util 类 HashMap<K,V>java.lang.Object  java.util.AbstractMap<K,V>      java.util.Hash ...

  6. Java的三种代理模式&完整源码分析

    Java的三种代理模式&完整源码分析 参考资料: 博客园-Java的三种代理模式 简书-JDK动态代理-超详细源码分析 [博客园-WeakCache缓存的实现机制](https://www.c ...

  7. java反射(三)--反射与操作类

    一.反射与操作类 在反射机制的处理过程之中不仅仅只是一个实例化对象的处理操作,更多的情况下还有类的组成的操作,任何一个类的基本组成结构:父类(父接口),包,属性,方法(构造方法,普通方法)--获取类的 ...

  8. Java 序列化和反序列化(三)Serializable 源码分析 - 2

    目录 Java 序列化和反序列化(三)Serializable 源码分析 - 2 1. ObjectStreamField 1.1 数据结构 1.2 构造函数 2. ObjectStreamClass ...

  9. 深度分析 Java 的 ClassLoader 机制(源码级别)

    写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...

随机推荐

  1. NPC

    这里的想说的NPC不是Non-Player-Controled,非玩家控制角色,而是Non-determinisitc Polynomial complete problem,它属于一类很特殊的问题, ...

  2. Top 10 Mistakes Java Developers Make(转)

    文章列出了Java开发者最常犯的是个错误. 1.将数组转换为ArrayList 为了将数组转换为ArrayList,开发者经常会这样做: ? 1 List<String> list = A ...

  3. hunnu-11546--Sum of f(x)

    Sum of f(x) Time Limit: 1000ms, Special Time Limit:2500ms, Memory Limit:32768KB Total submit users:  ...

  4. 道破Redis的VM

    原创文章是freas_1990.转载请注明出处:http://blog.csdn.net/freas_1990/article/details/42052813 Redis唯一的那个key的value ...

  5. zend studio代码字体修改字体和大小.

    第一步:进入设置窗口    windows -> preferences 第二步:进入修改字体的选项卡.    General -> Appearance -> Colors and ...

  6. windows phone 7,sliverlight 下载网页的解析,关于wp7 gb2312编码

    原文:windows phone 7,sliverlight 下载网页的解析,关于wp7 gb2312编码 关于silverlight和wp7(windows phone 7)是默认不支持gb2312 ...

  7. Json,Gson,FastJson解析笔记

    Json,Gson,FastJson解析笔记 1.将JavaBean转换成Json对象: public static String CreatJsonFromObject(Object key,Obj ...

  8. JBOSS EAP6.2.0的下载安装、环境变量配置以及部署

    JBOSS EAP6.2.0的下载安装.环境变量配置以及部署 JBoss是纯Java的EJB(企业JavaBean)server. 第一步:下载安装 1.进入官网http://www.jboss.or ...

  9. Solr入门指南

    本文转自http://chuanliang2007.spaces.live.com/blog/cns!E5B7AB2851A4C9D2!499.entry?wa=wsignin1.0 因为搜索引擎功能 ...

  10. BrowserSync使用

    在Gulp中使用BrowserSync 2016-02-24 23:47 by 那时候的我, 116 阅读, 0 评论, 收藏, 编辑 博客已迁移至http://lwzhang.github.io. ...