class testMe{
void show(){
System.out.println("Hello");
}
}
public class ClassloadersExample {
public static void main(String args[]) {
ClassLoader c = ClassloadersExample.class.getClassLoader(); //Line 1
try {
Class c1 = c.loadClass("test.testMe"); // Line 2
Constructor a[] = c1.getDeclaredConstructors();
for (Constructor constructor : a) {
testMe m = (testMe)constructor.newInstance();
m.show();
}
Constructor con[] = testMe.class.getDeclaredConstructors(); // Line 6
for (Constructor constructor : con) {
constructor.setAccessible(true);
testMe t = (testMe)constructor.newInstance();
t.show();
}
}
catch(Exception e){
System.out.println("exception");
}
}
}
I am testing above code. Both give me the same result. I am trying to understand the difference between line 1,2 and line 6. I can achieve the same result by both the approaches.
There is no functional difference. As you have discovered, there are various ways to get a Class
object and to instantiate instances of that class. They all lead to the same result, however.
In general, until needed otherwise, always:
getClass()
for obtaining a Class
Class<Foo> cl = Foo.class;
Class<? extends Foo> cl = fooInstance.getClass();
new
keyword for instantiating instances
Foo f = new Foo();
new
keyword.Off the top of my head, these are the ways I can think of to get a Class
object:
Class<Foo> cl = Foo.class;
getClass()
on an instance
Class<? extends Foo> cl = fooInstance.getClass();
Class.forName(String)
Class<?> cl = Class.forName("some.package.Foo");
Class.forName("some.package.Foo", true, currentClassLoader)
ClassLoader.loadClass(String)
Class<?> cl = classLoader.loadClass("some.package.Foo");
Class
. If the Class
has already been loaded then that loaded instance will be returned.All the above will get the Class
object that represents some.package.Foo
. In all likelihood (I'm not 100% certain), methods 1, 2, and 3 all end up delegating to method 4 eventually.
You'll notice that the generic signatures of the Class
objects (the <>
parts) are different depending on the way you get the Class
. Methods 1 and 2 know what type the Class
will be at compile-time and so can return a Class
with the appropriate generics. Whereas methods 3 and 4 have no idea what type the Class
will represent at runtime and therefore return a Class<?>
(?
is a wildcard).
Something to note about method 3. As I mentioned above, Class.forName(String)
is shorthand for Class.forName(String, boolean, ClassLoader)
where the boolean
will be true
and the ClassLoader
will be the current ClassLoader
. The boolean
parameter determines whether or not the Class
is initialized. To initialize a class means (among other things?) initializing all the static
variables and running the static
initializers. So while methods 1, 2, and 4 will not initialize the Class
, method 3 will. If you don't want method 3 to initialize the Class
you'll need to use the longer version and make the boolean
parameter false
.
The link in the question comments talk about why you would use methods 3 or 4.
Once again off the top of my head, these are the ways I can think of to instantiate objects:
new
keyword
Foo f = new Foo();
Class.newInstance()
Foo f = fooClass.newInstance();
Constructor
objectsConstructor
objects
Foo f = fooClass.getConstructor().newInstance();
The major difference here is how each method creates an instance. The first method simply uses the new
keyword. The 2nd and 3rd methods use reflection. Reflection is useful when you don't know the types at compile-time but should be avoided until needed.
Method 3 uses Class.getConstructor(Class<?>... paramterTypes)
. Since I'm passing an empty array of parameter types the returned Constructor
is a no-arg constructor. This would fail if the class does not have a no-arg constructor.
Your use of getDeclaredConstructors()
simply returns all the constructors and then you pick the one you want and call newInstance
. The example I gave in 3 bypasses this by going straight for the public no-arg constructor. Using getDeclaredConstructors()
will also give you the non-public constructors (i.e. protected
, package
, and private
). This can allow you to call a non-public constructor you wouldn't otherwise be able to. But this is only if you have the available access to call the constructor; you'll need things like permission from any installed SecurityManager
and (if using Java 9+) the package that the class is in must be reflectively-accessible (opens
) to your module.