What is the difference between Class.forName() and Class.forName().newInstance() ?
Maybe an example demonstrating how both methods are used will help you to understand things better. So, consider the following class:
package test;
public class Demo {
public Demo() {
System.out.println("Hi!");
}
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("test.Demo");
Demo demo = (Demo) clazz.newInstance();
}
}
As explained in its javadoc, calling Class.forName(String)
returns the Class
object associated with the class or interface with the given string name i.e. it returns test.Demo.class
which is affected to the clazz
variable of type Class
.
Then, calling clazz.newInstance()
creates a new instance of the class represented by this Class
object. The class is instantiated as if by a new
expression with an empty argument list. In other words, this is here actually equivalent to a new Demo()
and returns a new instance of Demo
.
And running this Demo
class thus prints the following output:
Hi!
The big difference with the traditional new
is that newInstance
allows to instantiate a class that you don't know until runtime, making your code more dynamic.
A typical example is the JDBC API which loads, at runtime, the exact driver required to perform the work. EJBs containers, Servlet containers are other good examples: they use dynamic runtime loading to load and create components they don't know anything before the runtime.
Actually, if you want to go further, have a look at Ted Neward paper Understanding Class.forName() that I was paraphrasing in the paragraph just above.
EDIT (answering a question from the OP posted as comment): The case of JDBC drivers is a bit special. As explained in the DriverManager chapter of Getting Started with the JDBC API:
(...) A
Driver
class is loaded, and
therefore automatically registered
with theDriverManager
, in one of two
ways:
by calling the method
Class.forName
. This explicitly loads
the driver class. Since it does not
depend on any external setup, this way
of loading a driver is the recommended
one for using theDriverManager
framework. The following code loads
the classacme.db.Driver
:Class.forName("acme.db.Driver");
If
acme.db.Driver
has been written so that loading it causes an
instance to be created and also callsDriverManager.registerDriver
with that
instance as the parameter (as it
should do), then it is in theDriverManager
's list of drivers and
available for creating a connection.
- (...)
In both of these cases, it is the responsibility of the newly-loaded
Driver
class to register itself by callingDriverManager.registerDriver
. As mentioned, this should be done automatically when the class is loaded.
To register themselves during initialization, JDBC driver typically use a static initialization block like this:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
Calling Class.forName("acme.db.Driver")
causes the initialization of the acme.db.Driver
class and thus the execution of the static initialization block. And Class.forName("acme.db.Driver")
will indeed "create" an instance but this is just a consequence of how (good) JDBC Driver are implemented.
As a side note, I'd mention that all this is not required anymore with JDBC 4.0(added as a default package since Java 7) and the new auto-loading feature of JDBC 4.0 drivers. See JDBC 4.0 enhancements in Java SE 6.
What is the difference between the new operator and Class.newInstance()?
The new
operator creates a new object of a type that's known statically (at compile-time) and can call any constructor on the object you're trying to create. It's the preferred way of creating an object - it's fast and the JVM does lots of aggressive optimizations on it.
Class.forName().newInstance()
is a dynamic construct that looks up a class with a specific name. It's slower than using new
because the type of object can't be hardcoded into the bytecode, and because the JVM might have to do permissions checking to ensure that you have the authority to create an object. It's also partially unsafe because it always uses a zero-argument constructor, and if the object you're trying to create doesn't have a nullary constructor it throws an exception.
In short, use new
if you know at compile-time what the type of the object is that you want to create. Use Class.forName().newInstance()
if you don't know what type of object you'll be making.
What is the difference between using .newInstance() and not using?
In modern Java, neither of these is needed.
The reason for using Class.forName
in "the good old days" was that it would run the type initialization code, which would register the driver with JDBC. You don't need to create a new instance of the driver though, so your first example was never required.
However, these days it isn't required - DriverManager
uses the standard service provider mechanism to find drivers. I'd be surprised to see any production-quality drivers that didn't support this now.
In other cases where you might see code calling Class.forName()
with or without newInstance()
, the two are separate calls:
Class.forName(String)
is a static method which finds/loads aClass
object with the specified fully-qualified name... just as if you'd usedFoo.class
at compile-time, but without knowing the nameFoo
Class.newInstance()
is an instance method which creates a new instance of the class represented by theClass
object which is the target of the method, calling the parameterless constructor. SoFoo.class.newInstance()
is a little bit likenew Foo()
- except again, you don't need to knowFoo
at compile-time (e.g. if you've obtained aClass
reference viaClass.forName
, or accepted it as a method parameter)
Difference between calling a class constructor and using Class.forName().newInstance
A a = new A();
Calls the new
operator and the constructor of A
directly, where A
is mentioned in the source text and has therefore already been loaded and initialized.
A a = (A) Class.forName("A").newInstance();
- look to see if
A
has already been loaded - load it if necessary
- initialize it if necessary
- locate the no-args constructor via reflection
- call the
new
operator and the no-args constructor via reflection - typecast the result to
A
Class.forname( name ).newInstance() vs name.class.newInstance : Difference in usage perspective
The simplest solution is to use
new Loadable();
if the class is know at compile time and you expect it to be available at runtime. Note: this will throw a NoClassDefError
at runtime if it is not available.
If you are not sure it will be available a runtime, you might use
Class.forName("classload.Loadable").newInstance();
as it is clearer as to which exceptions will be thrown.
The problem with
classload.Loadable.class.newInstance()
is that it's not particularly useful in either context.
Note: Class.newInstance()
has a known issue were it will throw checked exceptions which you don't know about. i.e. if the Constructor throws a checked exception it won't be wrapped and the compiler can't tell what will be thrown.
What to use instead of Class.newInstance()?
To quote Java 9's javadoc:
The call
clazz.newInstance()
can be replaced by
clazz.getDeclaredConstructor().newInstance()
Java 9 replace Class.newInstance
These two calls invoke the same constructor, the zero-argument constructor:
klass.newInstance()
klass.getDeclaredConstructor().newInstance()
Both perform the same run-time check to verify the caller's access, if the constructor is not public. The only difference is that #2 wraps any checked exceptions instead of directly throwing. Otherwise they are identical and you can replace one with the other.
But this is different:
klass.getConstructor().newInstance()
because it can only return a public constructor. It throws a NoSuchMethodException
if the constructor is not public.
So you can't change it to getConstructor()
unless you know the constructor is public.
Fix to Java newInstance() deprecated
Thanks for the excellent suggestions
I have applied the recommendations in the following way to make it a little easier to read
Class<?> transClass = config.getTransport();
Transport t = (Transport) transClass.getDeclaredConstructor().newInstance();
t.setConfig(this);
difference between Class.forName( Something ) and Class.forName( Something ).newInstance();
Class.forName("Somthing");
just loads the class in memory
Class.forName("Somthing").newInstance();
loads the class in memory and creates an instance of the class represented by the loaded Class
.
What is the difference between canonical name, simple name and class name in Java Class?
If you're unsure about something, try writing a test first.
I did this:
class ClassNameTest {
public static void main(final String... arguments) {
printNamesForClass(
int.class,
"int.class (primitive)");
printNamesForClass(
String.class,
"String.class (ordinary class)");
printNamesForClass(
java.util.HashMap.SimpleEntry.class,
"java.util.HashMap.SimpleEntry.class (nested class)");
printNamesForClass(
new java.io.Serializable(){}.getClass(),
"new java.io.Serializable(){}.getClass() (anonymous inner class)");
}
private static void printNamesForClass(final Class<?> clazz, final String label) {
System.out.println(label + ":");
System.out.println(" getName(): " + clazz.getName());
System.out.println(" getCanonicalName(): " + clazz.getCanonicalName());
System.out.println(" getSimpleName(): " + clazz.getSimpleName());
System.out.println(" getTypeName(): " + clazz.getTypeName()); // added in Java 8
System.out.println();
}
}
Prints:
int.class (primitive):
getName(): int
getCanonicalName(): int
getSimpleName(): int
getTypeName(): int
String.class (ordinary class):
getName(): java.lang.String
getCanonicalName(): java.lang.String
getSimpleName(): String
getTypeName(): java.lang.String
java.util.HashMap.SimpleEntry.class (nested class):
getName(): java.util.AbstractMap$SimpleEntry
getCanonicalName(): java.util.AbstractMap.SimpleEntry
getSimpleName(): SimpleEntry
getTypeName(): java.util.AbstractMap$SimpleEntry
new java.io.Serializable(){}.getClass() (anonymous inner class):
getName(): ClassNameTest$1
getCanonicalName(): null
getSimpleName():
getTypeName(): ClassNameTest$1
There's an empty entry in the last block where getSimpleName
returns an empty string.
The upshot looking at this is:
- the name is the name that you'd use to dynamically load the class with, for example, a call to
Class.forName
with the defaultClassLoader
. Within the scope of a certainClassLoader
, all classes have unique names.- the canonical name is the name that would be used in an import statement. It might be useful during
toString
or logging operations. When thejavac
compiler has complete view of a classpath, it enforces uniqueness of canonical names within it by clashing fully qualified class and package names at compile time. However JVMs must accept such name clashes, and thus canonical names do not uniquely identify classes within aClassLoader
. (In hindsight, a better name for this getter would have beengetJavaName
; but this method dates from a time when the JVM was used solely to run Java programs.)- the simple name loosely identifies the class, again might be useful during
toString
or logging operations but is not guaranteed to be unique.- the type name returns "an informative string for the name of this type", "It's like
toString
: it's purely informative and has no contract value". (as written by sir4ur0n)
Also you can commonly reference the Java Language Specification documentation for these types technical Java API details:
- Here's the Java 11 Specification on this subject matter: https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7
Example 6.7-2.
andExample 6.7-2.
goes overFully Qualified Names
andFully Qualified Names v. Canonical Name
respectively
Related Topics
Only Using @JSONignore During Serialization, But Not Deserialization
Selenium 2.53 Not Working on Firefox 47
How to Specify the Schema When Connecting to Postgres with Jdbc
Java Socket Why Server Can Not Reply Client
Call an Executable and Pass Parameters
Where Is Java_Home on MACos Mojave (10.14) to Lion (10.7)
How to Pass a Parameter to a Java Thread
How to Get a Unique Computer Identifier in Java (Like Disk Id or Motherboard Id)
What Should I Set Java_Home Environment Variable on MACos X 10.6
A Simple Scenario Using Wait() and Notify() in Java
How to Change Jdk Version for an Eclipse Project
Java8 Lambdas VS Anonymous Classes
Dealing with "Xerces Hell" in Java/Maven
What Is the Solution for the N+1 Issue in JPA and Hibernate
Maven Modules + Building a Single Specific Module
Does Assigning Objects to Null in Java Impact Garbage Collection