They are quite different!

As stated in the documentation for Class.forName(String),

Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to: Class.forName(className, true, currentLoader)

(true here refers to do you want to initialize the class? )

On the other hand, ClassLoader.loadClass(String):

Invoking this method is equivalent to invoking loadClass(name, false).

(here, the boolean has nothing to do with initialization; but if you check loadClass(String, boolean) documentation, you will see that all it does is load the class, not initialize it).

The first one (Class.forName("SomeClass");) will:

  • use the class loader that loaded the class which calls this code
  • initialize the class (that is, all static initializers will be run)

The other (ClassLoader.getSystemClassLoader().loadClass("SomeClass");) will:

  • use the "system" class loader (which is overridable)
  • not initialize the class (say, if you use it to load a JDBC driver, it won't get registered, and you won't be able to use JDBC!)

Suppose you are coding a web application that will be executed on a container such as Tomcat. What Tomcat does is create a class loader for each web application (so that it can unload the webapps later and release memory -- you need a dedicated class loader for this to work!). In this situation, you can see that both calls will yield quite different results!

For more detailed (and authoritative) information on class loading and initialization, check sections 12.2 and 12.4 of the latest (3rd) edition of the Java Language Specification.