for getting the resource files independent from the existing of the application.

解决方案 »

  1.   

    谢谢,可以说的清楚一些么?
    感谢!
    类加载器ClassLoader究竟怎么样使用呢,加载类究竟是一个什么样的概念?
      

  2.   

    String strResource = "resource.jpg";ClassLoader loader = Thread.currentThread().getContextClassLoader();
    URL url = loader.getResource(strResource);
    File file = url.getFile();If your project exists under C:\Projects\JChat
    save the resource file as C:\Projects\JChat\resource.jpg
    If the whole project is moved to D:\JChat with the resource file(s), there's no need to change the code.
      

  3.   

    The class ClassLoader is an abstract class. A class loader is an object that is responsible for loading classes. Given the name of a class, it should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system. Every Class object contains a reference to the ClassLoader that defined it. Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader. Applications implement subclasses of ClassLoader in order to extend the manner in which the Java virtual machine dynamically loads classes. Class loaders may typically be used by security managers to indicate security domains. The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When called upon to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the bootstrap class loader, does not itself have a parent but may serve as the parent of a ClassLoader instance. Normally, the Java virtual machine loads classes from the local file system in a platform-dependent manner. For example, on UNIX systems, the virtual machine loads classes from the directory defined by the CLASSPATH environment variable. However, some classes may not originate from a file; they may originate from other sources, such as the network, or they could be constructed by an application. The method defineClass converts an array of bytes into an instance of class Class. Instances of this newly defined class can be created using the newInstance method in class Class. The methods and constructors of objects created by a class loader may reference other classes. To determine the class(es) referred to, the Java virtual machine calls the loadClass method of the class loader that originally created the class. For example, an application could create a network class loader to download class files from a server. Sample code might look like:    ClassLoader loader = new NetworkClassLoader(host, port);
       Object main = loader.loadClass("Main", true).newInstance();
      . . .
     The network class loader subclass must define the methods findClass and loadClassData to load a class from the network. Once it has downloaded the bytes that make up the class, it should use the method defineClass to create a class instance. A sample implementation is: --------------------------------------------------------------------------------     class NetworkClassLoader extends ClassLoader {
             String host;
             int port;         public Class findClass(String name) {
                 byte[] b = loadClassData(name);
                 return defineClass(name, b, 0, b.length);
             }         private byte[] loadClassData(String name) {
                 // load the class data from the connection
                  . . .
             }
         }
    //摘自《Java 2 SDK SE Developer Documentation》
      

  4.   

    http://www-900.ibm.com/developerWorks/cn/education/java/j-classloader/tutorial/j-classloader-2-2.shtml讲解得相当细致
      

  5.   

    JVM在运行时会产生三个ClassLoader,Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.其中,Bootstrap是用C++编写的,我们在Java中看不到它,是null。它用来加载核心类库,在JVM源代码中这样写道:
    static const char classpathFormat[] =
    "%/lib/rt.jar:"
    "%/lib/i18n.jar:"
    "%/lib/sunrsasign.jar:"
    "%/lib/jsse.jar:"
    "%/lib/jce.jar:"
    "%/lib/charsets.jar:"
    "%/classes";
    知道为什么不需要在classpath中加载这些类了吧?人家在JVM启动的时候就自动加载了,并且在运行过程中根本不能修改Bootstrap加载路径。
    Extension ClassLoader用来加载扩展类,即/lib/ext中的类。
    最后AppClassLoader才是加载Classpath的。
    ClassLoader加载类用的是委托模型。即先让Parent类(而不是Super,不是继承关系)寻找,Parent找不到才自己找。看来ClassLoader还是蛮孝顺的。三者的关系为:AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent为Bootstrap ClassLoader。加载一个类时,首先BootStrap先进行寻找,找不到再由ExtClassLoader寻找,最后才是AppClassLoader。
    为什么要设计的这么复杂呢?其中一个重要原因就是安全性。比如在Applet中,如果编写了一个java.lang.String类并具有破坏性。假如不采用这种委托机制,就会将这个具有破坏性的String加载到了用户机器上,导致破坏用户安全。但采用这种委托机制则不会出现这种情况。因为要加载java.lang.String类时,系统最终会由Bootstrap进行加载,这个具有破坏性的String永远没有机会加载。
    我们来看这段代码:
    //A.java
    public class A{
    public static void main(String[] args){
    A a=new A();
    System.out.println(System.getProperty("java.ext.dirs"));
    System.out.println(a.getClass().getClassLoader());
    B b=new B();
    b.print();
    }
    }
    //B.java
    public class B{
    public void print(){
    System.out.println(this.getClass().getClassLoader());
    }
    }
    1、我们将它放在Classpath中,则打印出
    sun.misc.Launcher$AppClassLoader@92e78c
    sun.misc.Launcher$AppClassLoader@92e78c
    可见都是由AppClassLoader来加载的。
    2、我们将其放在%jre%/lib/ext/classes(即ExtClassLoader的加载目录。其加载/lib/ext中的jar文件或者子目录classes中的class文件)中。则会打印出:
    sun.misc.Launcher$ExtClassLoader
    sun.misc.Launcher$ExtClassLoader
    3、我们将A.class放到%jre%/lib/ext/classes中,而将B.class放到classpaht中又会怎么样呢?结果是:
    sun.misc.Launcher$ExtClassLoader
    Exception in thread "main" java.lang.NoClassDefFoundError:B
    at A.main(A.java:6)
    怎么会这样呢?这其中有一个重要的问题:A类当然是由ExtClassLoader来加载的,B类要由哪个加载呢?B类要由调用它自己的类的类加载器(真拗口)。也就是说,A调用了B,所以B由A的类加载器ExtClassLoader来加载。ExtClassLoader根据委托机制,先拜托Bootstrap加载,Bootstrap没有找到。然后它再自己寻找B类,还是没找到,所以抛出异常。ExtClassLoader不会请求AppClassLoader来加载!你可能会想:这算什么问题,我把两个类放到一起不就行了?
    呵呵,没这么简单。比如JDBC是核心类库,而各个数据库的JDBC驱动则是扩展类库或在classpath中定义的。所以JDBC由Bootstrap ClassLoader加载,而驱动要由AppClassLoader加载。等等,问题来了,Bootstrap不会请求AppClassLoader加载类啊。那么,他们怎么实现的呢?我就涉及到一个Context ClassLoader的问题,调用Thread.getContextClassLoader。具体我还没搞太明白,要知后事如何,请听下回分解!(啊!别拿砖头砸我...)