??xml version="1.0" encoding="utf-8" standalone="yes"?>在线观看亚洲精品专区,亚洲国产精品无码久久久不卡 ,国产精品亚洲一区二区三区在线观看http://www.tkk7.com/masen/category/21087.htmlzh-cnMon, 02 Feb 2015 21:35:36 GMTMon, 02 Feb 2015 21:35:36 GMT60Java 创徏对象方式http://www.tkk7.com/masen/articles/422168.htmlMasenMasenSat, 10 Jan 2015 14:42:00 GMThttp://www.tkk7.com/masen/articles/422168.htmlhttp://www.tkk7.com/masen/comments/422168.htmlhttp://www.tkk7.com/masen/articles/422168.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/422168.htmlhttp://www.tkk7.com/masen/services/trackbacks/422168.htmlJava 创徏对象方式Q?br />
    ●  用new语句创徏对象
    ●  q用反射手段,调用java.lang.Class 或?java.lang.reflect.Constructor cȝnewInstance()实例Ҏ
    ●  调用对象的clone()Ҏ
    ●  q用序列化手D?调用java.io.ObjectInputStream 对象?readObject()Ҏ.

分别创徏100万个javaBean Q性能如下Q?br />

//new : 46,47,47,62,47
//clone : 171,188,172,,157,172
//getClass().newInstance() : 140,141,141,,157,172
//Class.forName and newInstance : 1765,1781,1813,1797,1781
//Proxy.newProxyInstance : 2984
//Serializable : 60422

另外试了Field ?Method 执行效率Q?br />
//method : 1406
//feild : 1360 getField("")得到实例和父cȝ“公共”属?span style="white-space:pre">
//getDeclaredField() 得到实例的指定属?Public,protected,dfault,pivate),不包括父cd?/div>
//getFields()q回field数组Q?得到实例 ?父类 的所? “公共”属?br />
动态代理:
JDKQjdk1.7.0_02 
CGLIBQ和spring2.0.6 使用同样的cglib-nodep-2.1_3.jar 
CPUQP8400 2.53GHz 2.53GHz 
试l果4Q?nbsp;
Create JDK Proxy: 43 ms 
Create CGLIB Proxy: 129 ms
Run JDK Proxy: 940 ms, 1,500,069 t/s
Run CGLIB Proxy: 299 ms, 4,715,937 t/s
CGLIB创徏代理对象速度大概比JDK Proxy?倍,执行速度是JDK Proxy?倍以?/span>

区别Q?br />如果一个目标对象如果实C接口Spring则会选择JDK动态代理策略动态的创徏一个接口实现类Q动态代理类Q来代理目标对象Q可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出java.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现M接口QSpring会选择CGLIB代理Q?其生成的动态代理对象是目标cȝ子类?/span>
spring 配置实用cglib动态代?br /> proxy-target-class 属性设为true ?nbsp;<aop:aspectj-autoproxy proxy-target-class="true"/>


Masen 2015-01-10 22:42 发表评论
]]>
Java动态代理机制详解(JDK 和CGLIBQJavassistQASMQ?(转CSDN)http://www.tkk7.com/masen/articles/422092.htmlMasenMasenTue, 06 Jan 2015 13:42:00 GMThttp://www.tkk7.com/masen/articles/422092.htmlhttp://www.tkk7.com/masen/comments/422092.htmlhttp://www.tkk7.com/masen/articles/422092.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/422092.htmlhttp://www.tkk7.com/masen/services/trackbacks/422092.html阅读全文

Masen 2015-01-06 21:42 发表评论
]]>
cglibhttp://www.tkk7.com/masen/articles/348105.htmlMasenMasenMon, 11 Apr 2011 15:52:00 GMThttp://www.tkk7.com/masen/articles/348105.htmlhttp://www.tkk7.com/masen/comments/348105.htmlhttp://www.tkk7.com/masen/articles/348105.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/348105.htmlhttp://www.tkk7.com/masen/services/trackbacks/348105.html cglib是一个开源项目!
  是一个强大的,高性能,高质量的Code生成cd,它可以在q行期扩展JavacM实现Java接口。Hibernate用它来实现PO字节码的动态生成?/span>
  CGLIB包的介绍
  代理为控制要讉K的目标对象提供了一U途径。当讉K对象Ӟ它引入了一个间接的层。JDK自从1.3版本开始,引入了动态代理,q且l常被用来动态地创徏代理。JDK的动态代理用h非常单,当它有一个限Ӟ是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的承的c,该怎么办?现在我们可以使用CGLIB?/span>
  CGLIB是一个强大的高性能的代码生成包。它q泛的被许多AOP的框架用,例如Spring AOP和dynaopQؓ他们提供Ҏ的interceptionQ拦截)。最行的OR Mapping工具hibernate也用CGLIB来代理单端single-ended(多对一和一对一)兌Q对集合的gq抓取,是采用其他机制实现的Q。EasyMock和jMock是通过使用模仿QmokeQ对象来试java代码的包。它们都通过使用CGLIB来ؓ那些没有接口的类创徏模仿QmokeQ对象?/span>
  CGLIB包的底层是通过使用一个小而快的字节码处理框架ASMQ来转换字节码ƈ生成新的cR除了CGLIB包,脚本语言例如Groovy和BeanShellQ也是用ASM来生成java的字节码。当不鼓q接用ASMQ因为它要求你必dJVM内部l构包括class文g的格式和指o集都很熟悉?/span>

Masen 2011-04-11 23:52 发表评论
]]>
候捷谈Java反射机制(?http://www.tkk7.com/masen/articles/344086.htmlMasenMasenFri, 11 Feb 2011 14:50:00 GMThttp://www.tkk7.com/masen/articles/344086.htmlhttp://www.tkk7.com/masen/comments/344086.htmlhttp://www.tkk7.com/masen/articles/344086.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/344086.htmlhttp://www.tkk7.com/masen/services/trackbacks/344086.html阅读全文

Masen 2011-02-11 22:50 发表评论
]]>
Java Reflection (? http://www.tkk7.com/masen/articles/344084.htmlMasenMasenFri, 11 Feb 2011 14:01:00 GMThttp://www.tkk7.com/masen/articles/344084.htmlhttp://www.tkk7.com/masen/comments/344084.htmlhttp://www.tkk7.com/masen/articles/344084.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/344084.htmlhttp://www.tkk7.com/masen/services/trackbacks/344084.htmlJava Reflection (JAVA反射)    

Reflection ?Java E序开发语a的特征之一Q它允许q行中的 Java E序对自w进行检查,或者说“自审”Qƈ能直接操作程序的内部属性。例如,使用它能获得 Java cM各成员的名称q显C出来?/p>

Java 的这一能力在实际应用中也许用得不是很多Q但是在其它的程序设计语a中根本就不存在这一Ҏ。例如,Pascal、C 或?C++ 中就没有办法在程序中获得函数定义相关的信息?/p>

JavaBean ?reflection 的实际应用之一Q它能让一些工具可视化的操作Y件组件。这些工具通过 reflection 动态的载入q取?Java lg(c? 的属性?/p>

 

1. 一个简单的例子

考虑下面q个单的例子Q让我们看看 reflection 是如何工作的?/p>

import java.lang.reflect.*;
public class DumpMethods {
    public static void main(String args[]) {
        try {
            Class c = Class.forName(args[0]);
            Method m[] = c.getDeclaredMethods();
            for (int i = 0; i < m.length; i++)
                System.out.println(m[i].toString());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

按如下语句执行:

java DumpMethods java.util.Stack

它的l果输出为:

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Object java.util.Stack.pop()

public synchronized java.lang.Object java.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized int java.util.Stack.search(java.lang.Object)

q样列Zjava.util.Stack cȝ各方法名以及它们的限制符和返回类型?/p>

q个E序使用 Class.forName 载入指定的类Q然后调?getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描q某个类中单个方法的一个类?/p>

2.开始?Reflection

用于 reflection 的类Q如 MethodQ可以在 java.lang.relfect 包中扑ֈ。用这些类的时候必要遵@三个步骤Q第一步是获得你想操作的类?java.lang.Class 对象。在q行中的 Java E序中,?java.lang.Class cL描述cd接口{?/p>

下面是获得一?Class 对象的方法之一Q?/p>

Class c = Class.forName("java.lang.String");

q条语句得到一?String cȝcd象。还有另一U方法,如下面的语句Q?/p>

Class c = int.class;

或?/p>

Class c = Integer.TYPE;

它们可获得基本类型的cM息。其中后一U方法中讉K的是基本cd的封装类 (?Integer) 中预先定义好?TYPE 字段?/p>

W二步是调用诸如 getDeclaredMethods 的方法,以取得该cM定义的所有方法的列表?/p>

一旦取得这个信息,可以进行第三步了——?reflection API 来操作这些信息,如下面这D代码:

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它将以文本方式打印出 String 中定义的W一个方法的原型?/p>

在下面的例子中,q三个步骤将Z?reflection 处理Ҏ应用E序提供例证?/p>

模拟 instanceof 操作W?/p>

得到cM息之后,通常下一个步骤就是解军_?Class 对象的一些基本的问题。例如,Class.isInstance Ҏ可以用于模拟 instanceof 操作W:

class A {
}

public class instance1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("A");
            boolean b1 = cls.isInstance(new Integer(37));
            System.out.println(b1);
            boolean b2 = cls.isInstance(new A());
            System.out.println(b2);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

在这个例子中创徏了一?A cȝ Class 对象Q然后检查一些对象是否是 A 的实例。Integer(37) 不是Q但 new A() 是?/p>

3.扑ևcȝҎ

扑և一个类中定义了些什么方法,q是一个非常有价g非常基础?reflection 用法。下面的代码实Cq一用法Q?/p>

import java.lang.reflect.*;

public class method1 {
    private int f1(Object p, int x) throws NullPointerException {
        if (p == null)
            throw new NullPointerException();
        return x;
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("method1");
            Method methlist[] = cls.getDeclaredMethods();
            for (int i = 0; i < methlist.length; i++) {
                Method m = methlist[i];
                System.out.println("name = " + m.getName());
                System.out.println("decl class = " + m.getDeclaringClass());
                Class pvec[] = m.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println("param #" + j + " " + pvec[j]);
                Class evec[] = m.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println("exc #" + j + " " + evec[j]);
                System.out.println("return type = " + m.getReturnType());
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个E序首先取得 method1 cȝ描述Q然后调?getDeclaredMethods 来获取一pd?Method 对象Q它们分别描qC定义在类中的每一个方法,包括 public Ҏ、protected Ҏ、package Ҏ?private Ҏ{。如果你在程序中使用 getMethods 来代?getDeclaredMethodsQ你q能获得l承来的各个Ҏ的信息?/p>

取得?Method 对象列表之后Q要昄q些Ҏ的参数类型、异常类型和q回值类型等׃难了。这些类型是基本cdq是cȝ型,都可以由描述cȝ对象按顺序给出?/p>

输出的结果如下:

name = f1

decl class = class method1

param #0 class java.lang.Object

param #1 int

exc #0 class java.lang.NullPointerException

return type = int

-----

name = main

decl class = class method1

param #0 class [Ljava.lang.String;

return type = void

-----


4.获取构造器信息

获取cL造器的用法与上述获取Ҏ的用法类|如:

import java.lang.reflect.*;

public class constructor1 {
    public constructor1() {
    }

    protected constructor1(int i, double d) {
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("constructor1");
            Constructor ctorlist[] = cls.getDeclaredConstructors();
            for (int i = 0; i < ctorlist.length; i++) {
                Constructor ct = ctorlist[i];
                System.out.println("name = " + ct.getName());
                System.out.println("decl class = " + ct.getDeclaringClass());
                Class pvec[] = ct.getParameterTypes();
                for (int j = 0; j < pvec.length; j++)
                    System.out.println("param #" + j + " " + pvec[j]);
                Class evec[] = ct.getExceptionTypes();
                for (int j = 0; j < evec.length; j++)
                    System.out.println("exc #" + j + " " + evec[j]);
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子中没能获得返回类型的相关信息Q那是因为构造器没有q回cd?/p>

q个E序q行的结果是Q?/p>

name = constructor1

decl class = class constructor1

-----

name = constructor1

decl class = class constructor1

param #0 int

param #1 double

-----

5.获取cȝ字段(?

扑և一个类中定义了哪些数据字段也是可能的,下面的代码就在干q个事情Q?/p>


import java.lang.reflect.*;

public class field1 {
    private double d;
    public static final int i = 37;
    String s = "testing";

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("field1");
            Field fieldlist[] = cls.getDeclaredFields();
            for (int i = 0; i < fieldlist.length; i++) {
                Field fld = fieldlist[i];
                System.out.println("name = " + fld.getName());
                System.out.println("decl class = " + fld.getDeclaringClass());
                System.out.println("type = " + fld.getType());
                int mod = fld.getModifiers();
                System.out.println("modifiers = " + Modifier.toString(mod));
                System.out.println("-----");
            }
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子和前面那个例子非常相伹{例中用了一个新东西 ModifierQ它也是一?reflection c,用来描述字段成员的修饰语Q如“private int”。这些修饰语自n由整数描qͼ而且使用 Modifier.toString 来返回以“官方”序排列的字W串描述 (?#8220;static”?#8220;final”之前)。这个程序的输出是:

name = d

decl class = class field1

type = double

modifiers = private

-----

name = i

decl class = class field1

type = int

modifiers = public static final

-----

name = s

decl class = class field1

type = class java.lang.String

modifiers =

-----

和获取方法的情况一下,获取字段的时候也可以只取得在当前cMx了的字段信息 (getDeclaredFields)Q或者也可以取得父类中定义的字段 (getFields) ?/p>


6.ҎҎ的名U来执行Ҏ

文本到这里,所丄例子无一例外都与如何获取cȝ信息有关。我们也可以?reflection 来做一些其它的事情Q比如执行一个指定了名称的方法。下面的CZ演示了这一操作Q?/p>

import java.lang.reflect.*;
public class method2 {
    public int add(int a, int b) {
        return a + b;
    }
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("method2");
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Method meth = cls.getMethod("add", partypes);
            method2 methobj = new method2();
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = meth.invoke(methobj, arglist);
            Integer retval = (Integer) retobj;
            System.out.println(retval.intValue());
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

假如一个程序在执行的某处的时候才知道需要执行某个方法,q个Ҏ的名U是在程序的q行q程中指定的 (例如QJavaBean 开发环境中׃做这L?Q那么上面的E序演示了如何做到?/p>

上例中,getMethod 用于查找一个具有两个整型参C名ؓ add 的方法。找到该Ҏq创Z相应?Method 对象之后Q在正确的对象实例中执行它。执行该Ҏ的时候,需要提供一个参数列表,q在上例中是分别包装了整?37 ?47 的两?Integer 对象。执行方法的q回的同h一?Integer 对象Q它装了返回?84?/p>

7.创徏新的对象

对于构造器Q则不能像执行方法那栯行,因ؓ执行一个构造器意味着创徏了一个新的对?(准确的说Q创Z个对象的q程包括分配内存和构造对?。所以,与上例最怼的例子如下:

import java.lang.reflect.*;

public class constructor2 {
    public constructor2() {
    }

    public constructor2(int a, int b) {
        System.out.println("a = " + a + " b = " + b);
    }

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("constructor2");
            Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

Ҏ指定的参数类型找到相应的构造函数ƈ执行它,以创Z个新的对象实例。用这U方法可以在E序q行时动态地创徏对象Q而不是在~译的时候创建对象,q一炚w常有价倹{?/p>

8.改变字段(?的?/p>

reflection 的还有一个用处就是改变对象数据字D늚倹{reflection 可以从正在运行的E序中根据名U找到对象的字段q改变它Q下面的例子可以说明q一点:

import java.lang.reflect.*;

public class field2 {
    public double d;

    public static void main(String args[]) {
        try {
            Class cls = Class.forName("field2");
            Field fld = cls.getField("d");
            field2 f2obj = new field2();
            System.out.println("d = " + f2obj.d);
            fld.setDouble(f2obj, 12.34);
            System.out.println("d = " + f2obj.d);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

q个例子中,字段 d 的D变ؓ?12.34?/p>

9.使用数组

本文介绍?reflection 的最后一U用法是创徏的操作数l。数l在 Java 语言中是一U特D的cȝ型,一个数l的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:

import java.lang.reflect.*;

public class array1 {
    public static void main(String args[]) {
        try {
            Class cls = Class.forName("java.lang.String");
            Object arr = Array.newInstance(cls, 10);
            Array.set(arr, 5, "this is a test");
            String s = (String) Array.get(arr, 5);
            System.out.println(s);
        } catch (Throwable e) {
            System.err.println(e);
        }
    }
}

例中创徏?10 个单位长度的 String 数组QؓW?5 个位|的字符串赋了|最后将q个字符串从数组中取得ƈ打印了出来?/p>

下面q段代码提供了一个更复杂的例子:

import java.lang.reflect.*;

public class array2 {
    public static void main(String args[]) {
        int dims[] = new int[]{5, 10, 15};
        Object arr = Array.newInstance(Integer.TYPE, dims);
        Object arrobj = Array.get(arr, 3);
        Class cls = arrobj.getClass().getComponentType();
        System.out.println(cls);
        arrobj = Array.get(arrobj, 5);
        Array.setInt(arrobj, 10, 37);
        int arrcast[][][] = (int[][][]) arr;
        System.out.println(arrcast[3][5][10]);
    }
}
例中创徏了一?5 x 10 x 15 的整型数l,qؓ处于 [3][5][10] 的元素赋了gؓ 37。注意,多维数组实际上就是数l的数组Q例如,W一?Array.get 之后Qarrobj 是一?10 x 15 的数l。进而取得其中的一个元素,即长度ؓ 15 的数l,q?Array.setInt 为它的第 10 个元素赋倹{?/p>

注意创徏数组时的cd是动态的Q在~译时ƈ不知道其cd?/p>

Masen 2011-02-11 22:01 发表评论
]]>
Java的类装蝲?Class Loader)和命名空?NameSpace) (?http://www.tkk7.com/masen/articles/107302.htmlMasenMasenThu, 29 Mar 2007 10:40:00 GMThttp://www.tkk7.com/masen/articles/107302.htmlhttp://www.tkk7.com/masen/comments/107302.htmlhttp://www.tkk7.com/masen/articles/107302.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/107302.htmlhttp://www.tkk7.com/masen/services/trackbacks/107302.html Java的类装蝲?Class Loader)和命名空?NameSpace)

摘要

Java的类装蝲器是Java动态性的核心Q本文将向大家简要介lJava的类装蝲器,及相关的parent delegation模型Q命名空_q行时包{概念,同时讨论一些在学习中容易؜淆的问题?

c装载器的功能及分类

֐思义Q类装蝲器是用来把类(class)装蝲qJVM的。JVM规范定义了两U类型的c装载器Q启动内装蝲?bootstrap)和用戯定义装蝲?user-defined class loader)?

bootstrap是JVM自带的类装蝲器,用来装蝲核心cdQ如java.lang.*{。由?可以看出Qjava.lang.Object是由bootstrap装蝲的?

Java提供了抽象类ClassLoaderQ所有用戯定义c装载器都实例化自ClassLoader的子cR?System Class Loader是一个特D的用户自定义类装蝲器,由JVM的实现者提供,在编E者不特别指定装蝲器的情况下默认装载用L。系l类装蝲器可以通过ClassLoader.getSystemClassLoader() Ҏ得到?/p>

?Q测试你所使用的JVM的ClassLoader

/*LoaderSample1.java*/
public class LoaderSample1 {
    public static void main(String[] args) {
        Class c;
        ClassLoader cl;
        cl = ClassLoader.getSystemClassLoader();
        System.out.println(cl);
        while (cl != null) {
            cl = cl.getParent();
            System.out.println(cl);
        }
        try {
            c = Class.forName("java.lang.Object");
            cl = c.getClassLoader();
            System.out.println("java.lang.Object's loader is " + cl);
            c = Class.forName("LoaderSample1");
            cl = c.getClassLoader();
            System.out.println("LoaderSample1's loader is " + cl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在我的机器上(Sun Java 1.4.2)的运行结?/p>

sun.misc.Launcher$AppClassLoader@1a0c10f
sun.misc.Launcher$ExtClassLoader@e2eec8
null 
java.lang.Object's loader is null
LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@1a0c10f

W一行表C,pȝc装载器实例化自csun.misc.Launcher$AppClassLoader

W二行表C,pȝc装载器的parent实例化自csun.misc.Launcher$ExtClassLoader

W三行表C,pȝc装载器parent的parent为bootstrap

W四行表C,核心cjava.lang.Object是由bootstrap装蝲?

W五行表C,用户cLoaderSample1是由pȝc装载器装蝲?

parent delegation模型

?.2版本开始,Java引入了双亲委托模型,从而更好的保证Javaq_的安全。在此模型下Q当一个装载器被请求装载某个类Ӟ它首先委托自qparent去装载,若parent能装载,则返回这个类所对应的Class对象Q若parent不能装蝲Q则由parent的请求者去装蝲?/p>

如图1所C,loader2的parent为loader1Qloader1的parent为system class loader。假设loader2被要求装载类MyClassQ在parent delegation模型下,loader2首先hloader1代ؓ装蝲Qloader1再请求系l类装蝲器去装蝲MyClass。若pȝ装蝲器能成功装蝲Q则MyClass所对应的Class对象的referenceq回lloader1Qloader1再将referenceq回lloader2Q从而成功将cMyClass装蝲q虚拟机。若pȝc装载器不能装蝲MyClassQloader1会尝试装载MyClassQ若loader1也不能成功装载,loader2会尝试装载。若所有的parent及loader2本n都不能装载,则装载失败?/p>

若有一个能成功装蝲Q实际装载的c装载器被称为定义类装蝲器,所有能成功q回Class对象的装载器Q包括定义类装蝲器)被称为初始类装蝲器。如?所C,假设loader1实际装蝲了MyClassQ则loader1为MyClass的定义类装蝲器,loader2和loader1为MyClass的初始类装蝲器?/p>

?1 parent delegation模型

需要指出的是,Class Loader是对象,它的父子关系和类的父子关pL有Q何关pR一对父子loader可能实例化自同一个ClassQ也可能不是Q甚至父loader实例化自子类Q子loader实例化自父类。假设MyClassLoaderl承自ParentClassLoaderQ我们可以有如下父子loaderQ?/p>

ClassLoader loader1 = new MyClassLoader();
//参数 loader1 ?parent
ClassLoader loader2 = new ParentClassLoader(loader1); 

那么parent delegation模型Z么更安全了?因ؓ在此模型下用戯定义的类装蝲器不可能装蝲应该q亲装载器装蝲的可靠类Q从而防止不可靠甚至恶意的代码代替由父亲装蝲器装载的可靠代码。实际上Q类装蝲器的~写者可以自由选择不用把请求委托给parentQ但正如上所_会带来安全的问题?/p>

命名I间及其作用

每个c装载器有自q命名I间Q命名空间由所有以此装载器为创始类装蝲器的cȝ成。不同命名空间的两个cL不可见的Q但只要得到cL对应的Class对象的referenceQ还是可以访问另一命名I间的类?/p>

?演示了一个命名空间的cd何用另一命名I间的类。在例子中,LoaderSample2ql类装蝲器装载,LoaderSample3p定义的装载器loader负责装蝲Q两个类不在同一命名I间Q但LoaderSample2得到了LoaderSample3所对应的Class对象的referenceQ所以它可以讉KLoaderSampl3中公q成员(如age)?/p>

?不同命名I间的类的访?/p>

										/*LoaderSample2.java*/
import java.net.*;
import java.lang.reflect.*;
public class LoaderSample2 {
    public static void main(String[] args) {
        try {
            String path = System.getProperty("user.dir");
            URL[] us = {new URL("file://" + path + "/sub/")};
            ClassLoader loader = new URLClassLoader(us);
            Class c = loader.loadClass("LoaderSample3");
            Object o = c.newInstance();
            Field f = c.getField("age");
            int age = f.getInt(o);
            System.out.println("age is " + age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
										}
								
										/*sub/Loadersample3.java*/
public class LoaderSample3 {
    static {
        System.out.println("LoaderSample3 loaded");
    }
    public int age = 30;
}

~译Qjavac LoaderSample2.java; javac sub/LoaderSample3.java

q行Qjava LoaderSample2

LoaderSample3 loaded
age is 30

从运行结果中可以看出Q在cLoaderSample2中可以创建处于另一命名I间的类LoaderSample3中的对象q可以访问其公共成员age?/p>

q行时包(runtime package)

由同一c装载器定义装蝲的属于相同包的类l成了运行时包,军_两个cL不是属于同一个运行时包,不仅要看它们的包名是否相同,q要看的定义c装载器是否相同。只有属于同一q行时包的类才能互相讉K包可见的cd成员。这L限制避免了用戯q代码冒充核心cd的类讉K核心cd包可见成员的情况。假讄戯己定义了一个类java.lang.YesQƈ用用戯定义的类装蝲器装载,׃java.lang.Yes和核心类库java.lang.*׃同的装蝲器装载,它们属于不同的运行时包,所以java.lang.Yes不能讉K核心cdjava.lang中类的包可见的成员?

ȝ

在简单讨Zc装载器Qparent delegation模型Q命名空_q行时包后,怿大家已经对它们的作用有了一定的了解。命名空间ƈ没有完全止属于不同I间的类的互相访问,双亲委托模型加强了Java的安全,q行时包增加了对包可见成员的保护?/p>



Masen 2007-03-29 18:40 发表评论
]]>
ClassLoader基础知识Q{Q?/title><link>http://www.tkk7.com/masen/articles/107291.html</link><dc:creator>Masen</dc:creator><author>Masen</author><pubDate>Thu, 29 Mar 2007 10:00:00 GMT</pubDate><guid>http://www.tkk7.com/masen/articles/107291.html</guid><wfw:comment>http://www.tkk7.com/masen/comments/107291.html</wfw:comment><comments>http://www.tkk7.com/masen/articles/107291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/masen/comments/commentRss/107291.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/masen/services/trackbacks/107291.html</trackback:ping><description><![CDATA[ <ul> <b>JVM</b> <br />jvm是jre里头一个动态连接函数库,jdk里面的jre一般用于运行java本n的程?比如javac,{等.programfiles下面的jre用于q行用户~写的javaE序. <br />JRE下的bin\client 或?bin\server 的jvm.dll是JVM? <p></p><p>当一台机器上有多个jvm可选择的时?jvm的选择步骤: <br />1)当前目录有没有jre目录(不准?, <br />2)父目录下的jre子目?<br />3)注册表HEKY_LOCAL_MACHINE\SoftWare\Java\Java Runtime Environment\ <br />所以当q行的是jdk\bin\java.exe的时?用的jre是bin的父目录jdk下面的jre\ <br />q行java.exe扑ֈ了jre后有一个验证程?验证jre和java.exe的版本是否一?如果不一致则会发生错?/p></ul> <br /> <ul>java -verbose:class Main 昄调用的详l信?/ul> <br /> <ul>classloader的两U蝲入方?1)pre-loading预先载入,载入基础c?2)load-on-demand按需求蝲?<br />只有实例化一个类才会被classloader载入,仅仅xq不会蝲?/ul> <br /> <ul> <b>java动态蝲入class的两U方?</b> <br />1)implicit隐式,卛_用实例化才蝲入的Ҏ来动态蝲入class <br />2)explicit昑ּ方式,又分两种方式: <br />1)java.lang.Class的forName()Ҏ <br />2)java.lang.ClassLoader的loadClass()Ҏ</ul> <br /> <ul> <b>static块在什么时候执?</b> <br />1)当调用forName(String)载入class时执?如果调用ClassLoader.loadClassq不会执?forName(String,false,ClassLoader)时也不会执行. <br />2)如果载入Class时没有执行static块则在第一ơ实例化时执?比如new ,Class.newInstance()操作 <br />3)static块仅执行一?/ul> <br /> <ul> <br /> <b>Classcȝ实例.</b> <br />>>ClasscL法手工实例化,当蝲入Q意类的时候自动创Z个该cd应的Class的实? <br />>>某个cȝ所有实例内部都有一个栏位记录着该类对应的Class的实例的位置., <br />>>每个javacd应的Class实例可以当作是类在内存中的代理h.所以当要获得类的信?如有哪些cd?有哪些方??都可以让cd应的Class的实例代?java的Reflection机制大量的使用q种Ҏ来实?<br />>>每个javac都是由某个classLoader(ClassLoader的实?来蝲入的,因此Classcd的实例中都会有栏位记录他的ClassLoader的实?如果该栏位ؓnull,则表Ccd是由bootstrap loader载入?也称root laoder),bootstrap loader不是java所写成,所以没有实? <p></p><p>原生Ҏ:forName0(){方?native修饰W?/p></ul> <br /> <ul> <b>自定义ClassLoader:</b> <br />如实例化一个URLClassLoader. URLClassLoader ucl = new URLClassLoader(new URL[]{new URL("file:/e:/bin/")}),URLClassLoader优先扑ֽ前目?再在url中找.class加蝲.URL中别忘在最后加"/"表示目录</ul> <br /> <ul> <b>各个javacȝ哪些classLoader加蝲?</b> <br />1)javacd以通过实例.getClass.getClassLoader()得知 <br />2)接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()获得实例)载入 <br />3)ClassLoadercȝbootstrap loader载入</ul> <br /> <ul> <b>ClassLoader hierachy:</b> <br />jvm建立->初始化动?>产生W一个ClassLoader,即bootstrap loader->bootstrap loader在sum.misc.Launcherc里面的ExtClassLoader,q设定其Parent为null->bootstrap loader载入sun.misc.Launcher$AppClassLoader,q设定其parent为ExtClassLoader(但是AppClassLoader也是由bootstrap loader所载入?->AppClassLoader载入各个xx.class,xx.class也有可能被ExtclassLoader或者bootstrap loader载入. <br />>>自定义的ClassLoader?getParent()是AppClassLoader.parent和他的加载器q没有关p?<br />>>ExtClassLoader和AppClassLoader都是URLClassLoader的子c?AppClassLoader的URL是由pȝ参数java.class.path取出的字W串军_,而java.class.path?q行java.exe??cp?classpath或CLASSPATH环境变量军_ <br />>>ExtClassLoader查找的url是系l变量java.ext.dirs,java.ext.dirs默认为jdk\jre\lib\ext <br />>>Bootstrap loader的查找url是sun.boot.class.path <br />>>在程序运行后调用System.setProperty()来改变系l变量ƈ不能改变以上加蝲的\?因ؓclassloaderd在System.setProperty之前.sun.boot.class.path是在E序中写ȝ,完全不能修改 <p></p><p>委派模型 <br />当classloader有类需要蝲入时先让其parent搜寻其搜寻\径帮忙蝲?如果parent找不?在由自己搜寻自己的搜寻\径蝲?ClassLoader hierachy本来有q种性质</p></ul> <br /> <ul> <br /> <b>NoClassDefFoundError和ClassNotFoundException</b> <br />NoClassDefFoundError:当java源文件已~译?class文g,但是ClassLoader在运行期间在其搜寻\径load某个cL,没有扑ֈ.class文g则报q个?<br />ClassNotFoundException:试图通过一个String变量来创Z个ClasscL不成功则抛出q个异常</ul> <img src ="http://www.tkk7.com/masen/aggbug/107291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/masen/" target="_blank">Masen</a> 2007-03-29 18:00 <a href="http://www.tkk7.com/masen/articles/107291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Javac装载体pM的隔L(转)http://www.tkk7.com/masen/articles/107225.htmlMasenMasenThu, 29 Mar 2007 06:39:00 GMThttp://www.tkk7.com/masen/articles/107225.htmlhttp://www.tkk7.com/masen/comments/107225.htmlhttp://www.tkk7.com/masen/articles/107225.html#Feedback0http://www.tkk7.com/masen/comments/commentRss/107225.htmlhttp://www.tkk7.com/masen/services/trackbacks/107225.htmlJava中类的查找与装蝲出现的问题L会时不时出现在JavaE序员面前,qƈ不是什么丢脸的事情Q相信没有一个JavaE序员没遇到qClassNotException,因此不要人瞅见自׃犯这L错误而觉得不自然Q但是在如果出现了ClassNotFoundException后异常后一脸的茫然Q那我想你该了解一下java的类装蝲的体制了Q同时ؓ了进行下面的关于c装载器之间的隔L的讨论Q我们先单介l一下类装蝲的体pȝ构?/p>

1. Javac装载体pȝ?/b>

装蝲cȝq程非常单:查找cL在位|,q将扑ֈ的Javacȝ字节码装入内存,生成对应的Class对象。Java的类装蝲器专门用来实现这Lq程QJVMq不止有一个类装蝲器,事实上,如果你愿意的话,你可以让JVM拥有无数个类装蝲器,当然q除了测试JVM外,我想不出q有其他的用途。你应该已经发现Cq样一个问题,c装载器自n也是一个类Q它也需要被装蝲到内存中来,那么q些c装载器p来装载呢Qd有个根吧Q没错,实存在q样的根Q它是龙见首不见Bootstrap ClassLoader. Z么说它神龙见首不见尾呢,因ؓ你根本无法在Java代码中抓住哪怕是它的一点点的尾_管你能时时d体会到它的存在,因ؓjava的运行环境所需要的所有类库,都由它来装蝲Q而它本n是C++写的E序Q可以独立运?可以说是JVM的运行v?伟大吧。在Bootstrap完成它的d后,会生成一个AppClassLoader(实际上之前系l还会用扩展类装蝲器ExtClassLoaderQ它用于装蝲Javaq行环境扩展包中的类),q个c装载器才是我们l常使用的,可以调用ClassLoader.getSystemClassLoader() 来获得,我们假定E序中没有用类装蝲器相x作设定或者自定义新的c装载器Q那么我们编写的所有javac通通会由它来装载,值得敬吧。AppClassLoader查找cȝ区域是耳熟能详的ClasspathQ也是初学者必跨q的门槛Q有没有灵光一闪的感觉Q我们按照它的类查找范围l它取名为类路径c装载器。还是先前假定的情况Q当Java中出现新的类QAppClassLoader首先在类传递给它的父类c装载器Q也是Extion ClassLoaderQ询问它是否能够装蝲该类Q如果能Q那AppClassLoader׃q这zMQ同样Extion ClassLoader在装载时Q也会先问问它的父类装蝲器。我们可以看出类装蝲器实际上是一个树状的l构图,每个c装载器有自q父亲Q类装蝲器在装蝲cLQL先让自己的父c装载器装蝲(多么敬长辈),如果父类装蝲器无法装载该cLQ自己就会动手装载,如果它也装蝲不了Q那么对不vQ它会大喊一壎ͼExceptionQclass not found。有必要提一句,当由直接使用c\径装载器装蝲cd败抛出的是NoClassDefFoundException异常。如果用自定义的类装蝲器loadClassҎ或者ClassLoader的findSystemClassҎ装蝲c,如果你不d意改变,那么抛出的是ClassNotFoundException?/p>

我们短ȝ一下上面的讨论Q?/p>

1.JVMc装载器的体pȝ构可以看作是树状l构?/p>

2.父类装蝲器优先装载。在父类装蝲器装载失败的情况下再装蝲Q如果都装蝲p|则抛出ClassNotFoundException或者NoClassDefFoundError异常?/p>

那么我们的类在什么情况下被装载的呢?

2. cd何被装蝲

在java2中,JVM是如何装载类的呢Q可以分ZU类型,一U是隐式的类装蝲Q一U式昑ּ的类装蝲?/p> 2.1 隐式的类装蝲

隐式的类装蝲是编码中最常用得方式:

A b = new A();

如果E序q行到这D代码时q没有Ac,那么JVM会请求装载当前类的类装器来装载类。问题来了,我把代码弄得复杂一点点Q但依旧没有M隑ֺQ请思考JVM得装载次序:

package test;
Public class A{
    public void static main(String args[]){
        B b Q?new B();
    }
}

class B{C c;}

class C{}

揭晓{案Q类装蝲的次序ؓA->BQ而类CҎ不会被JVM理会,先不要惊Ӟ仔细xQ这不正是我们最需要得到的l果。我们仔l了解一下JVM装蝲序。当使用Java A命oq行AcLQJVM会首先要求类路径c装载器(AppClassLoader)装蝲Ac,但是q时只装载AQ不会装载A中出现的其他c?Bc?Q接着它会调用A中的main函数Q直到运行语句b Q?new B()ӞJVM发现必须装蝲Bcȝ序才能l运行,于是c\径类装蝲器会去装载Bc,虽然我们可以看到B中有有Ccȝ声明Q但是ƈ不是实际的执行语句,所以ƈ不去装蝲Cc,也就是说JVM按照q行时的有效执行语句Q来军_是否需要装载新c,从而装载尽可能的c,q一点和~译cL不相同的?/p>

2.2 昑ּ的类装蝲

使用昄的类装蝲Ҏ很多Q我们都装蝲ctest.AZ?/p>

使用ClasscȝforNameҎ。它可以指定装蝲器,也可以用装载当前类的装载器。例如:

Class.forName("test.A");
它的效果?
Class.forName("test.A",true,this.getClass().getClassLoader());
是一L?

使用c\径类装蝲装蝲.

ClassLoader.getSystemClassLoader().loadClass("test.A");

使用当前q程上下文的使用的类装蝲器进行装载,q种装蝲cȝҎ常常被有着复杂c装载体pȝ构的pȝ所使用?/p>

Thread.currentThread().getContextClassLoader().loadClass("test.A")

使用自定义的c装载器装蝲c?/p>

public class MyClassLoader extends URLClassLoader{
public MyClassLoader() {
        super(new URL[0]);
    }
}
MyClassLoader myClassLoader = new MyClassLoader();
myClassLoader.loadClass("test.A");

MyClassLoaderl承了URLClassLoaderc,q是JDK核心包中的类装蝲器,在没有指定父c装载器的情况下Q类路径c装载器是它的父类装蝲器,MyClassLoaderq没有增加类的查找范_因此它和c\径装载器有相同的效果?/p>

我们已经知道Java的类装蝲器体pȝ构ؓ树状Q多个类装蝲器可以指定同一个类装蝲器作q父类Q每个子c装载器是树状l构的一个分支,当然它们又可以个有子c装载器c装载器Q类装蝲器也可以没有父类装蝲器,q时Bootstrapc装载器作为它的隐含父c,实际上Bootstrapc装载器是所有类装蝲器的先Q也是树状结构的栏V这U树状体pȝ构,以及父类装蝲器优先的机制Qؓ我们~写自定义的c装载器提供了便利,同时可以让程序按照我们希望的方式q行cȝ装蝲。例如某个程序的c装载器体系l构囑֦下:

?Q某个程序的c装载器的结?/p>

解释一下上面的图,ClassLoaderA定义的类装蝲器,它的父类装蝲器ؓc\径装载器Q它有两个子c装载器ClassLoaderAA和ClassLaderABQClassLoaderB为程序用的另外一个类装蝲器,它没有父c装载器Q但有一个子c装载器ClassLoaderBB。你可能会说Q见|我的E序怎么会用这么复杂的c装载器l构。ؓ了进行下面的讨论Q暂且委屈一下?/p>

3. 奇怪的隔离?/b>

我们不难发现Q图2中的c装载器AA和ABQ?AB和BBQAA和B{等位于不同分支下,他们之间没有父子关系Q我不知道如何定义这U关p,姑且UC们位于不同分支下。两个位于不同分支的c装载器h隔离性,q种隔离性得在分别使用它们装蝲同一个类Q也会在内存中出C个Classcȝ实例。因h隔离性的c装载器装蝲的类不会׃n内存I间Q得用一个类装蝲器不可能完成的Q务变得可以轻而易举,例如cȝ静态变量可能同时拥有多个|虽然好像作用不大Q,因ؓq是被装蝲cȝ同一静态变量,它们也将被保存不同的内存I间Q又例如E序需要用某些包Q但又不希望被程序另外一些包所使用Q很单,~写自定义的c装载器。类装蝲器的q种隔离性在许多大型的Y件应用和服务E序得到了很好的应用。下面是同一个类静态变量ؓ不同值的例子?/p>

package test;
public class A {
  public static void main( String[] args ) {
    try {
      //定义两个c装载器
      MyClassLoader aa= new MyClassLoader();
      MyClassLoader bb = new MyClassLoader();

      //用类装蝲器aa装蝲testb.Bc?
      Class clazz=aa.loadClass("testb. B");
      Constructor constructor= 
        clazz.getConstructor(new Class[]{Integer.class});
      Object object = 
	    constructor.newInstance(new Object[]{new Integer(1)});
      Method method = 
	    clazz.getDeclaredMethod("printB",new Class[0]);

      //用类装蝲器bb装蝲testb.Bc?
      Class clazz2=bb.loadClass("testb. B");
      Constructor constructor2 = 
        clazz2.getConstructor(new Class[]{Integer.class});
      Object object2 = 
	    constructor2.newInstance(new Object[]{new Integer(2)});
      Method method2 = 
	    clazz2.getDeclaredMethod("printB",new Class[0]);

      //昄test.B中的静态变量的?
      method.invoke( object,new Object[0]);
      method2.invoke( object2,new Object[0]);
    } catch ( Exception e ) {
      e.printStackTrace();
    }
  }
}

//Class B 必须位于MyClassLoader的查找范围内Q?
//而不应该在MyClassLoader的父c装载器的查找范围内?
package testb;
public class B {
    static int b ;

    public B(Integer testb) {
        b = testb.intValue();
    }

    public void printB() {
        System.out.print("my static field b is ", b);
    }
}

public class MyClassLoader extends URLClassLoader{
  private static File file = new File("c:\\classes ");
  //该\径存攄class BQ但是没有class A

  public MyClassLoader() {
    super(getUrl());
  }

  public static URL[] getUrl() {
    try {
      return new URL[]{file.toURL()};
    } catch ( MalformedURLException e ) {
      return new URL[0];
    }
  }
}

E序的运行结果ؓQ?/p>

my static field b is 1
my static field b is 2

E序的结果非常有意思,从编E者的角度Q我们甚臛_以把不在同一个分支的c装载器看作不同的java虚拟机,因ؓ它们彼此觉察不到Ҏ的存在。程序在使用h分支的类装蝲的体pȝ构时要非常小心,弄清楚每个类装蝲器的cL找范_量避免父类装蝲器和子类装蝲器的cL找范围中有相同类名的c(包括包名和类名)Q下面这个例子就是用来说明这U情况可能带来的问题?/p>

假设有相同名字却不同版本的接?AQ?/p>

版本 1Q?
package test;
Intefer Same{ public String getVersion(); }
版本 2Q?
Package test;
Intefer Same{ public String getName(); }

接口A两个版本的实玎ͼ

版本1的实?
package test;
public class Same1Impl implements Same {
public String getVersion(){ return "A version 1";}
}
版本2的实?
public class Same 2Impl implements Same {
public String getName(){ return "A version 2";}
}

我们依然使用?的类装蝲器结构,首先版?的Same和Same的实现类Same1Impl打成包same1.jarQ将版本2的Same和Same的实现类Same1Impl打成包same2.jar。现在,做这L事情Q把same1.jar攑օc装载器ClassLoaderA的类查找范围中,把same2.jar攑օc装器ClassLoaderAB的类查找范围中。当你兴冲冲的运行下面这个看似正的E序?/p>

实际上这个错误的是由父类载器优先装蝲的机刉成Q当c装载器ClassLoaderAB在装载Same2ImplcL发现必须装蝲接口test.SameQ于是按规定h父类装蝲器装载,父类装蝲器发C版本1的test.Same接口q兴冲冲的装载,但是却想不到Same2Impl所希望的是版本2 的test.SameQ后面的事情可想而知了,异常被抛出?/p>

我们很难责怪Java中暂时ƈ没有提供区分版本的机Ӟ如果使用了比较复杂的c装载器体系l构Q在出现了某个包或者类的多个版本时Q应特别注意?/p>

掌握和灵z运用Java的类装蝲器的体系l构Q对E序的系l设计,E序的实玎ͼ已经E序的调试,都有相当大的帮助。希望以上的内容能够Ҏ有所帮助?/p>

Masen 2007-03-29 14:39 发表评论
]]>
վ֩ģ壺 ޾ƷѹۿƵ| ޾ƷƷ˿| ƬĻӰ| Ƶ| þ91޾ƷĻ| þѸƵ| þþƷAVũ帾Ů| ʮ˽վ| ߹ۿ| 91㽶Ƶ| ˳ŷĻ| ɬɬɬƵ߹ۿ | Ƶۿ| Ƶ߹ۿ| ߹ۿվ| AV˾Ʒպ| ѻɫƬ| ɫƵѹۿ| 츾AVһ˳| ھƷ뿨123| һëƬĻ| Ѹ弤Ƶ| ˾Ʒ| ޾ƷƵ| 99ƷƵۿ| ޳aƬ߲| Ļѹۿ| 91ѹƵ| AV뾫Ʒ| ַѹۿ | ߹ۿ˳Ƶ| smһ| ˵www| ĻmvӰ| ޹ŷպƷһ| ר| þþƷѿ| | ɫ͵С˵| ëƬѹۿվ| ŮƵۿ|