zoukankan      html  css  js  c++  java
  • 5.8 反射机制

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

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

    • 在运行时判定任意一个对象所属的类;
    • 在运行时构造任意一个类的对象;
    • 在运行时判定任意一个类所具有的成员变量和方法;
    • 在运行时调用任意一个对象的方法;
    • 生成动态代理。

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

      在 JDK 中,主要由以下类来实现Java 反射机制,这些类都位于java.lang.reflect包中。

    • Class类:代表一个类。
    • Field类:代表类的成员变量(成员变量也称为类的属性)。
    • Method类:代表类的方法。
    • Constructor 类:代表类的构造方法。
    • Array类:提供了动态创建数组,以及访问数组元素的静态方法。

      Java 反射机制是Java 语言的一个重要特性。考虑实现一个newInstance(String className)方法,它的作用是根据参数className 指定的类名,通过该类的不带参数的构造方法创建这个类的对象,并将其返回。如果不运用Java 反射机制,必须在newInstance()方法中罗列参数className所有可能的取值,然后创建相应的对象:

    public Object newInstance(String className) throws Exception{
      if(className.equals("HelloService1"))  
        return new HelloService1();   if(className.equals("HelloService2"))
        return new HelloService2();   //...   if(className.equals("HelloService1000"))
        return new HelloService1000(); }

      以上程序代码很冗长,而且可维护性差。如果在以后软件的升级版本中去除了一个HelloService4类,或者增加了一个HelloService1001类,都需要修改以上newInstance()方法。

      如果运用反射机制,就可以简化程序代码,并且提高软件系统的可维护性和可扩展性:

    public Object newInstance(String className) throws Exception{
      Class classType = Class.forName(className);
      return classType.newInstance();
    }

      我们在进行Android程序的开发时,为了方便调试程序,并快速定位程序的错误点,会从网上下载到对应版本的Android SDK的源码(这里给大家提供一个2.3.3版本的下载链接)。你会发现很多类或方法中经常加上了“@hide”注释标记,它的作用是使这个方法或类在生成SDK时不可见,那么我们的程序可能无法编译通过,而且在最终发布的时候,就可能存在一些问题。

      那么,对于这个问题,第一种方法就是自己去掉Android源码中的"@hide"标记,然后重新编译生成一个SDK。另一种方法就是使用Java反射机制了,可以利用这种反射机制访问存在访问权限的方法或修改其域。

    反射机制的优缺点?

    • 静态编译:在编译时确定类型,绑定对象,即通过
    • 动态编译:运行时确定类型,绑定对象。动态编译最大限度的发挥了java的灵活性,体现了多态的应用,有利于降低类之间的耦合性。

      反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

      它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

     下面给两个小例子:

    例1:执行另外一个包里面的某个类的方法,另外一个包的包名是chroya.demo,类名Main,方法名print

    package chroya.demo;
    import android.app.Activity;
    import android.os.Bundle;
    import android.util.Log;
    class Main extends Activity {
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
      }
      public void print(String msg) {
        Log.d("Main", "msg:"+ msg);
      }
    }

    本包调用Main的print方法的代码块如下:

    Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);  
    //载入这个类  
    Class clazz = c.getClassLoader().loadClass("chroya.demo.Main");  
    //新建一个实例  
    Object owner = clazz.newInstance();  
    //获取print方法,传入参数并执行  
    Object obj = clazz.getMethod("print", String.class).invoke(owner, "Hello"); 

    2:永不消失的Toast

    public class MainActivity extends Activity implements OnClickListener{
        Toast myToast;
        TextView vt;
        Object obj;
        Field field; 
        Field fieldview;
        Method methodshow;
        Method methodhide;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          ……
            //  先创建一个Toast对象
            myToast = new Toast(this);
                vt = new TextView(this);
                vt.setText("永不消失的Toast");
            myToast.setView(vt);
        }
        void showToast(){
            try {
                //  从Toast对象中获得mTN变量
                field = myToast.getClass().getDeclaredField("mTN");
                field.setAccessible(true); // setAccessible(true)可以访问private域
                obj = field.get(myToast);
               
                fieldview = obj.getClass().getDeclaredField("mNextView");
                fieldview.setAccessible(true);
                fieldview.set(obj, vt);
                //  TN对象中获得了show方法
                methodshow =  obj.getClass().getDeclaredMethod("show", null);
                methodhide =  obj.getClass().getDeclaredMethod("hide", null);
                methodshow.invoke(obj, null);
            } catch (Exception e) { }
        }
  • 相关阅读:
    算法之递归(4) 应用
    算法之递归(1)
    [Async] [Series #1] 初识Async异步编程模型。
    CVE202142287/CVE202142278 复现
    易读文库下载器1.2版发布
    Sqlite.net 读取DateTime异常的解决方案
    QZFL 2.0.5 源代码
    Sqlite 管理工具 SQLiteDeveloper 及破解
    visio2010数据库正向工程生成数据库脚本
    什么是高内聚、低耦合?
  • 原文地址:https://www.cnblogs.com/keyarchen/p/6062993.html
Copyright © 2011-2022 走看看