Difference between Loading a class using ClassLoader and Class.forName

后端 未结 9 1041
梦如初夏
梦如初夏 2020-11-29 20:38

Below are 2 code snippets

The first one uses ClassLoader class to load a specified class

ClassLoader cls = ClassLoader.getSystemClassL

相关标签:
9条回答
  • 2020-11-29 21:14

    The 2nd approach loads a class using a ClassLoader

     public static Class<?> forName(String className) 
                    throws ClassNotFoundException {
            return forName0(className, true, ClassLoader.getCallerClassLoader());
    

    This is what the JavaDoc says:

    forName(String name, boolean initialize, ClassLoader loader)
    

    The specified class loader is used to load the class or interface. If the parameter loader is null, the class is loaded through the bootstrap class loader.

    So, the 2nd option uses the System ClassLoader (which is, in essence, what it does in the first option).

    0 讨论(0)
  • 2020-11-29 21:17

    In your concrete case:

    ClassLoader cls = ClassLoader.getSystemClassLoader();
    Class someClass = cls.loadClass("TargetClass");
    

    Above code will load TargetClass ALWAYS with system classloader.

    Class cls = Class.forName("TargetClass");
    

    The second code snippet will load (and initialise) TargetClass with the classloader that was used to load the class that is executing that line of code. If that class was loaded with system classloader, the two approaches are identical (except for class initialisation, as explained in an excellent answer by Bruno).

    Which one to use? For loading and inspecting classes with reflection, I recommend to use specific class loader (ClassLoader.loadClass()) - it puts you in control and helps to avoid potentially obscure issues between different environments.

    If you need to load AND initialise, use Class.forName(String, true, ClassLoader).

    How to find the right class loader? It depends on your environment:

    • if you are running a command-line application, you could just use system classloader or the class loader that loaded your application classes (Class.getClassLoader()).
    • if you are running inside a managed environment (JavaEE, servlet container, etc) then the best would be to check current thread context class loader first and then fall back to options given in previous point.
    • or just use your own custom class loader (if you are into that sort of thing)

    In general, the most fool-proof and tested would be to use ClassUtils.forName() from Spring (see JavaDoc).

    More in-depth explanation:


    The most common form of Class.forName(), the one that takes a single String parameter, always uses the caller's classloader. This is the classloader that loads the code executing the forName() method. By comparison, ClassLoader.loadClass() is an instance method and requires you to select a particular classloader, which may or may not be the loader that loads that calling code. If picking a specific loader to load the class is important to your design, you should use ClassLoader.loadClass() or the three-parameter version of forName() added in Java 2 Platform, Standard Edition (J2SE): Class.forName(String, boolean, ClassLoader).

    Source: What is the difference between Class.forName() and ClassLoader.loadClass()?


    Also, SPR-2611 highlights one interesting obscure corner case when using Class.forName(String, boolean, ClassLoader).

    As seen in that Spring issue, using ClassLoader.loadClass() is the recommended approach (when you need to load classes from specific class loader).

    0 讨论(0)
  • 2020-11-29 21:22

    there's also a difference when loading array-types. I think classloader.loadClass(clazz) cannot handle array-types, but Class.forName(clazz,true,classloader) can.

    0 讨论(0)
提交回复
热议问题