Reputation: 755
I am struggling to understand the use of class.forName. Actually i am working on a project and i have a field that accepts a string. The classpath! I pass this string in the class.forName- no exception... so class.forName can find the specified class. After that I want to call the specified class. But here comes my problems. First of all do I have to separate the String in order to take the name of the class... right? Also, if i do this
Class requestedClass = Class.forName(path);
AClass newClassInstance = (AClass)requestedClass.newInstance();
i have an exception InstantiationException, as some parameters have to be passed in the constructor of the class. Is there any solution for this? It sounds more sensible to me to use if statement and call the respective class, but in case of a lot of possible classes this approach would be a nightmare. Thank you!
Upvotes: 3
Views: 2243
Reputation: 2030
See the following example,
When you call, Class.forName("PQR") here, the class PQR is loaded into memory, and the static block inside PQR is automatically executed.
package com.hello;
class PQR
{
static // static block
{
System.out.println("in static block");
}
}
public class Abc
{
public static void main(String[] args) throws Exception
{
Class.forName("com.hello.PQR");
}
}
Note: com.hello is just the package name.
Upvotes: 0
Reputation: 11815
Another big use you'll see for this is loading JDBC drivers. This is probably the first use of Class.forName that most java programmers encounter. What you'll see is this:
Class.forName("oracle.jdbc.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:...");
What happens here is that when the OracleDriver class is loaded (via Class.forName), it contains a class initialization block something like this (it's probably more complicated but illustrates the point). This block gets run as part of the class loading process.
public class OracleDriver {
static {
DriverManager.registerDriver(new OracleDriver());
}
}
Then when you call DriverManager.getConnection, it can ask all the registered drivers if they are capable of handling the url which has been given (the code is more involved, but i'll simplify it a bit):
for (Driver driver : registeredDrivers) {
if (driver.acceptsURL(url)) {
// use this driver
}
}
As far as your instantiation issues, the Class.newInstance() method will always call the no-arg constructor, and throws an exception if it does not exist. If you want a specific constructor, you use the "getConstructor" method on the class itself. For instance if you want a constructor which takes a String and a Long:
Class clazz = ...; // figure out which class here
Constructor c = clazz.class.getConstructor(String.class, Long.class);
Object o = c.newInstance("foo", new Long(1L));
Upvotes: 2
Reputation: 39990
You can call a parameterised constructor via reflection by using Class.getConstructor()
:
class Foo {
public Foo(String bar) {
System.out.println("bar = " + bar);
}
}
Class<?> fooCls = Class.forName("Foo");
Constructor<?> fooCtor = fooCls.getConstructor(String.class);
Foo foo = (Foo) fooCtor.newInstance("BAR");
If the class you need to instantiate doesn't have a no-args constructor, and you can't figure out what parameters to pass to it, you're out of luck. (This would be a severe flaw in your design too. If a method needs to instantiate one out of N classes, it should be possible to instantiate all classes the same way, whether it be a constructor signature or a factory method.)
Upvotes: 1
Reputation: 3377
As it has been pointed out it is very useful because you can load classes that have not been there at compile time such as plugins or extensions.
There is a simple solution for your problem. Simple fetch the constructor you are searching for and provide the expected arguments. E.g.:
MyClass a = (MyClass) Class.forName("com.test.MyClass")
.getConstructor(new Class[] { String.class }).newInstance("Test");
Upvotes: 1
Reputation: 81724
It's useful because it lets you specify a class to load that didn't exist when your code was compiled. The applet
tag in HTML uses this to load subclasses of java.applet.Applet
. Web servers use this to load Java servlets and other web components. EJB containers, Spring containers, and many other programs use this method to load components. If you use Eclipse or NetBeans, these IDEs load plugins by using Class.forName()
-- this lets them load the new plugins that are created every day.
The key to all of this magic is inheritance`. You need to be able to treat the created object as an instance of an interface or a parent class -- i.e.,
Applet applet = (Applet) Class.forName(theNameOfSomeAppletClass).newInstance();
Then you can read theNameOfSomeAppletClass
from an HTML file (for example) and create an instance of the class, even though your code has never heard of it.
Most of the time, plugin APIs simply specify that you should give your plugin class a no-argument constructor. But java.lang.Class
has a getConstructors()
method which lets you get Constructor
objects, which in turn let you instantiate a class by passing arguments to its constructor, if you really need to.
Upvotes: 4