4

I am little bit confused in class loading and initializing concept

1: Class.forName("test.Employee").newInstance();
2: ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();
3: new test.Employee(); 

Every line of above written code is creating an instance of Employee class but I don't understand what is the difference in all three methods.

halfer
  • 19,824
  • 17
  • 99
  • 186
Deepu--Java
  • 3,742
  • 3
  • 19
  • 30
  • ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance().getClass(); returns you the class object of Employee not instance of Employee. Interstingly you create an instance using the class then using that instance, you are getting the class. – TheLostMind Apr 24 '14 at 06:51

3 Answers3

2

You cannot create a instance of an Object unless class is loaded into the memory. In all three cases class is loaded and then instance is created.

  1. class is loaded by Class.forName("test.Employee")
  2. class is loaded by ClassLoader.getSystemClassLoader().loadClass("test.Employee")
  3. class is loaded automatically as Employee class is referenced for 1st time.
Aniket Thakur
  • 66,731
  • 38
  • 279
  • 289
  • 1
    There are difference in how the classes are "located" – MadProgrammer Apr 24 '14 at 06:54
  • @MadProgrammer can you elaborate more on this. – Deepu--Java Apr 24 '14 at 06:54
  • @DeepakTiwari - Class.forName() will always use the ClassLoader of the caller, whereas ClassLoader.loadClass() can specify a different ClassLoader. check http://stackoverflow.com/questions/8345220/java-difference-between-class-forname-and-classloader-loadclass – TheLostMind Apr 24 '14 at 06:56
  • 1
    `Class.forName` uses the current `Class`s classloader, `ClassLoader.getSystemClassLoader` uses the system `Classloader`, which is typically the one that loaded the application. This can affect visibility and restrict what each can load. There can also be restrictions on how the loaded class might be cast, as the physical implementation may be unknown at compile time... – MadProgrammer Apr 24 '14 at 07:00
  • @MadProgrammer you should post that as a separate answer. – Dawood ibn Kareem Apr 24 '14 at 07:16
2

The core differences between the three approaches come down to how the classes are located at runtime and what you can do with them.

For example...

Class.forName("test.Employee").newInstance();

Will use the current class's ClassLoader to search the class named Employee in the test package. This would allow you to discover classes that might not be available at compile time and which are loaded dynamically into the same class loader context. This will also search it's parent class loaders if the class is not found within the current context...

ClassLoader.getSystemClassLoader().loadClass("test.Employee").newInstance();

This will use the "system" ClassLoader, this typically the one that launched the main application.

Using either of these two methods is a great way to generate dynamic applications where the actual implementation of a Class is not known at compile type. The problem here is it can affect visibility and restrict what you can do with the loaded classes.

For example, while you may have loaded the test.Employee class and created an instance of it, unless you have a reference to test.Employee at compile time, you want be able to cast it. This is typically where interfaces come in very handy.

Equally, you could create your own ClassLoader instance and load classes or jars at runtime to provide, for example, plugins, factories or managers where the implementation is unknown at compile time. The functionality for these would, typically, be described through the use of interfaces.

Examples would include java.awt.Toolkit and JDBC java.sql.Driver

At the end of the day, the ClassLoader mechanism is providing a means by which a class file can be loaded and instantiated into the current JVM. The new keyword does a similar job, but the results are pre-determined at compile time

ClassLoaders are a very powerful feature and provide a lot of functionality, but can also be down right confusion, especially the way that they chain together

You might find...

of some help

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

Just to illustrate it with an example and complete the other answers:

public class ClassLoaderTest {
    public ClassLoaderTest() throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        System.out.println("Current CL: "+getClass().getClassLoader());
        System.out.println("Parent CL: "+getClass().getClassLoader().getParent());

        // ClassTest class is defined in the current CL so I can dynamically create an instance
        // from the current CL and assign it (forName uses the current CL)
        ClassTest c1 = (ClassTest)Class.forName("ClassTest").newInstance();
        System.out.println("CL using forName: "+c1.getClass().getClassLoader());

        // the new keyword creates an instance using the current CL but doesn't have the
        // advantages of creating instances dynamically
        ClassTest c2 = (ClassTest) new ClassTest();
        System.out.println("CL using new: "+c2.getClass().getClassLoader());

        // Here we are indicating to use the system CL that in this case is the parent of the current CL
        Object c3 = ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
        System.out.println("CL using system CL: "+c3.getClass().getClassLoader());

        // This won't work because the ClassTest is defined in the current CL but I'm trying to assign it to a
        // dynamically created instance of ClassTest associated to the system CL so:
        // java.lang.ClassCastException: ClassTest cannot be cast to ClassTest
        // ClassTest c4 = (ClassTest)ClassLoader.getSystemClassLoader().loadClass("ClassTest").newInstance();
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        CustomClassLoader cl = new CustomClassLoader(Test.class.getClassLoader());
        cl.loadClass("ClassLoaderTest").newInstance();
    }
}

The output in my case is:

Current CL: CustomClassLoader@1cfb549
Parent CL: sun.misc.Launcher$AppClassLoader@8ed465
CL using forName: CustomClassLoader@1cfb549
CL using new: CustomClassLoader@1cfb549
CL using system CL: sun.misc.Launcher$AppClassLoader@8ed465

I'm using this custom ClassLoader (CL): www.javablogging.com/java-classloader-2-write-your-own-classloader/

IsidroGH
  • 2,037
  • 19
  • 27