[Java] 反射机制 01

java程序的执行过程
    ClassLoader 将编译好的 class 文件 load 到内存中的 codeSegment 代码段;运行环境找到 main 方法开始执行;运行过程中会有更多的 class 被 load 到内存 

ClassLoader
    ClassLoader是类装载器,用于将class装载进内存。
URL getResource(String name);

    用于获取资源URL,寻找资源不依赖于相对路径,不依赖于绝对路径,只要资源处于 classpath 里即可。方法执行时将找遍当前所设定的 classpath 目录,eclipsesrc 目录默认地被编译到 bin 目录,bin 目录即项目本身的 classpath,用于存放编译好的类文件,所以约定俗成将资源放入工程src目录下,这样做的好处在于程序部署到何处都可以访问到资源而不用修改代码。
URL getResourceAsStream(String name);一般用于读取配置文件
java ClassLoader动态加载机制
   ClassLoader 加载类的时候并非一次性加载,而是需要的时候才加载(运行期间加载)例:TestDynamicLoading.java注意运行时要指定虚拟机参数 java -vervose:class打印类装载信息

-TestDynamicLoading.java
public class TestDynamicLoading {
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new A();
        System.out.println("`````````````````````````````");
        new B();
        new C();
        new C();
        new D(1);
        new D(2);
    }
}

class A {
}

class B {
}

class C {
    static {
        System.out.println("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC");
    }
}

class D {
    D(int i) {
    }

    {
        System.out.println("DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD");
    }
}

相关输出 :

[Loaded A from file:/D:/Java/MyEclipse/Workspaces/TestReflection/bin/]
`````````````````````````````
[Loaded B from file:/D:/Java/MyEclipse/Workspaces/TestReflection/bin/]
[Loaded C from file:/D:/Java/MyEclipse/Workspaces/TestReflection/bin/]
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
[Loaded D from file:/D:/Java/MyEclipse/Workspaces/TestReflection/bin/]
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD

从上面输出可以看出以下问题 : 

  1. ClassLoader 加载类时候的动态加载机制:即需要时再加载
  2. 静态语句块 static{} 只在类加载时执行一次
  3. 动态语句块 {} 在每次实例化对象的时候都执行一次,类似于强行嵌入了构造函数中

ClassLoader在加载class的时候首先通过getParent()方法找上一层Classloader,看该class是否被上层loader加载过了,如果已经加载了,就不在重复加载

如此保证了java核心类的安全性;此机制保证了class的逐层唯一加载,安全性好。

[Loaded java.lang.Object
[Loaded java.io.Serializable
[Loaded java.lang.Comparable 
[Loaded java.lang.CharSequence
[Loaded java.lang.String
[Loaded java.lang.reflect.GenericDeclaration
[Loaded java.lang.reflect.Type
[Loaded java.lang.reflect.AnnotatedElement
[Loaded java.lang.Class 
[Loaded java.lang.Cloneable
[Loaded java.lang.ClassLoader
[Loaded java.lang.System
[Loaded java.lang.Throwable
......
 JDK 内部用到的一些类以上是。
----ClassLoader 动态加载
 动态语句块 (多次) 无条件加载在构造函数的前面 

 静态语句块 (1次)
)

关于ClassLoader示例代码如下:TestJDKClassLoader.java

public class TestJDKClassLoader {
    public static void main(String[] args) {
        // 获得加载了rt.jar中类的ClassLoader,即bootStrap ClassLoader,但是该类无名
        System.out.println(String.class.getClassLoader());
        // 获得加载扩张包中类的ClassLoader的名字,下面的类来自jre/lib/ext/sunjce_provider.jar
        System.out.println(com.sun.crypto.provider.DESKeyFactory.class
                .getClassLoader().getClass().getName()); // @@@待检错@@@
        // 获得加载了用户自定义的类的Classloader的名字
        System.out.println(TestJDKClassLoader.class.getClassLoader().getClass()
                .getName());
        // 通过ClassLoader.getSystemClassLoader()获得加载了用户自定义的类的Classloader
        System.out.println(ClassLoader.getSystemClassLoader().getClass()
                .getName());

        System.out.println("---------分割线-----------");

        // 逐层获取ClassLoader
        ClassLoader c = TestJDKClassLoader.class.getClassLoader();
        while (c != null) {
            System.out.println(c.getClass().getName());
            c = c.getParent();
        }
    }
}
输出:
null
sun.misc.Launcher$ExtClassLoader
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$AppClassLoader
---------分割线-----------
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader

Class类

对于类装载器而言每个class文件就是一个Class对象;Class类事对于编译好的某一类对象的描述,描述了编译好的class文件的信息,是对类信息的描述,是类的metainfo(元信息)或者metadata(元数据),即描述数据的数据

ClassLoader getClassLoader(),获得该类的类装载器

static Class forName(String); 可根据类名加载相应的类,返回一个Class对象

Object newInstance():实例化对象

其实从面向对象的高度看,类中的一个的属性也是一个对象,方法也是对象,即属性对象和方法对象

Method[]  getMethods()

     Class[] getParameterTypes()

     Class m.getReturnType()

     invoke(Object,Object... args)

Field[] getFields()

反射

  1. 反射机制即指java可以在运行期间通过Class的Class Class.forName(String)方法动态地加载一个类
  2. 继而可以通过获得的该类对应的的Class对象的Object newInstance()方法实例化出该类的对象
  3. 然后可以通过Method[]  getMethods() 和Field[] getFields()等方法了解类的内部结构
  4. 最后就可以根据方法的内部结构决定该方法应该怎么样去调用,从而动态地去调用类的方法m.invoke(Object,Object... args)



posted @ 2014-01-17 17:18  小尼人00  阅读(139)  评论(0编辑  收藏  举报