【框架基础】:Java反射机制详解(一)

来源:互联网 发布:图片去码软件 编辑:程序博客网 时间:2024/04/30 08:04

        在学习框架设计之前,先来了解一下框架基础——Java反射机制。

        一、什么是反射机制

        反射机制是在程序运行状态时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都

能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应

用所描述行为的状态和相关的语义。

       反射是Java语言中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在

组件之间进行源代码链接。

       要让Java程序能够运行,就得让Java类被Java虚拟机加载。Java类如果不被Java虚拟机加载就不能正常运行。正

常情况下,我们运行的所有的程序在编译期时候就已经把那个类被加载了。

       Java的反射机制是在编译时并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用的是

在编译期并不知道的类。这样的编译特点就是Java反射。

       简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在Java中,只要给定类的名字, 那么就可以通

过反射机制来获得类的所有信息。


       二、反射机制能做什么

       反射机制主要提供了以下功能: 

       1.在运行时判断任意一个对象所属的类;

       2.在运行时构造任意一个类的对象;

       3.在运行时判断任意一个类所具有的成员变量和方法;

       4.在运行时调用任意一个对象的方法;

       5.生成动态代理;

       6.进行反编译:.class(字节码文件)-->.java(源代码文件);


       三、Java反射的作用

       假如有两个程序员,一个程序员在写程序的时需要使用第二个程序员所写的类,但第二个程序员并没完成他所写

的类。那么第一个程序员的代码是不能通过编译的。此时,利用Java反射的机制,就可以让第一个程序员在没有得到

第二个程序员所写的类的时候,来完成自身代码的编译。

      Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。如Eclipse

中,一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利

用了Java反射的原理,是对我们创建对象的探知、自审。   

  

       四、反射机制的优点与缺点 

       为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。

       静态编译:在编译时确定类型,绑定对象,即通过。 

       动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,有以降低

类之间的藕合性。 

       一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在JavaEE的开发中。

的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发

布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软

件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能 的更新,而采用反射机制的

话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 

       它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我

们的要求。这类操作总是慢于只直接执行相同的操作。   

       在下面我们会举一个比较简单的小例子。


       五、一个简单的例子

       首先我们先来编写一个静态加载类的示例:

       Office.java源文件:

class Office{public static void main(String[] args){//使用new创建对象是静态加载类,在编译时刻就需要加载所有可能使用到的类//通过加载加载类可以解决该问题    if("Word".equals(args[0])){Word w = new Word();w.start();    }    if("Excel".equals(args[0])){Excel e = new Excel();    e.start();    }    } } 

       使用javac进行编译:

       
       编译出错的原因我们大家都知道,就是找不到Word类和Excel类。

       假设我们写好了Word类,Word.java源文件:

class Word{public void start(){    System.out.println("word...starts...");}}

       使用javac编译:

       
       再次编译此程序还是不通过,因为找不到Excel类,那么我们需要的就是Word功能,不需要Excel功能,那么主要

的程序还是无法编译运行,我们所需要的功能还是无法使用,这就是静态加载的不足之处。如果主程序中有多个功

能,只要其中一个没有实现或者是错误的,那么这个主程序就无法编译运行。那么这就需要使用动态加载来进行类的

加载了。

       下面就来通过反射来实现动态加载:

       OfficeBetter.java源文件:

class OfficeBetter{public static void main(String[] args){    try{    //动态加载类,在运行时刻加载Class clazz = Class.forName(args[0]);//通过类类型创建该类的对象OfficeAble oa = (OfficeAble)clazz.newInstance();oa.start();}catch(Exception e){e.printStackTrace();}} }    

       在其中我们需要定义一个接口,那么我们的功能类需要实现这个接口规范,这个规范就是OfficeAble接口。

       OfficeAble.java源文件:

interface OfficeAble{public void start();}
       我们来进行编译:

       

       我们对它们进行编译,那么编译就会顺利通过。纵然是我们没有实现一个功能类,我们的主程序依然会通过。下

面的我们实现的功能类只要实现这个接口规范,然后编译功能类,我们不编译主类就可以运行。

       我们将先前的Word功能类进行改写,也就是实现OfficeAble接口规范:

class Word implements OfficeAble{public void start(){    System.out.println("word...starts...");}}

       编译运行:

       

       那么我们再扩展新的功能类Excel.java

class Excel implements OfficeAble{public void start(){    System.out.println("excel...starts...");}}

       编译运行:

       

       

       总结:

       通常情况下,Java程序能够运行,必须要让Java类被虚拟机加载,如果不被Java虚拟机加载,程序不能运行。运

行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。通过反射机制可以让程序在编

译期间并不需要加载某个类,而是在程序运行的时候才加载。
       利用反射机制可以很灵活的对运行时已经加载到Java虚拟机当中的类信息进行检测。当然这种检测在对运行的性

能上会有些减弱,所以什么时候使用反射,就要靠业务的需求、大小,以及经验的积累来决定。

       反射提高程序的灵活性和扩展性,低耦合。常用于系统架构和框架搭建。



1 0
原创粉丝点击