Reputation: 23
Let's say you're making a general reflection class. You're given the name of the class in string format: So you do Class.forName(class_name) to get the class name.
Next step would be to get the constructor and you can do Class.forName(class_name).getConstructor(null) assuming that there isn't any args.
How do you now get an instance of this? You would have to downcast but what do you downcast to? class_name name = (what goes here) Class.forName(class_name).getConstructor(null).newInstance(null)
I tried to put in the class_name in the parenthesis class_name name = (class_name) Class.forName(class_name).getConstructor(null).newInstance(null) but getting an error. Well not compiling.
Update: Only thing known is that the constructor doesn't have any args, and instance doesn't have parameters. So you can pass null to both.
Upvotes: 0
Views: 4938
Reputation: 12665
What you're asking for is impossible.
If you load the class using Class.forName(someClassName)
, it means you do not know at compile time what the class will be, you will only know it at runtime (when the value of someClassName
will be defined).
That means, you can't code based on that specific type (because if you want to have typed code at compile time, then you should know the exact type at compile time and that's not your case).
However, even though you can only declare your instance as Object obj = ...
instead of SomeClassName obj = ...
(which I understand is what you wanted to do), be reassured that your obj
will actually be an instance of SomeClassName
at runtime, even if the compiler doesn't know it yet.
If you add more details about what you're trying to do (I mean why do you need to cast the reflected instance to the specific type), then I can complete my answer to address your exact concern.
EDIT To answer to the questions in the comments:
so inherently Java knows that it's a Foo class but it'll just return a generic Object because it wants to be sure that it's correct?
No. When coding there are two phases: compile-time and run-time. The compile-time is the moment when the code is compiled into an executable. The run-time is the moment when the code is executed.
Take the initial expression of your question:
Object obj = Class.forName(class_name).getConstructor().newInstance();
When does the variable class_name
take a concrete value? Well, that's at runtime (when the code runs).
That means, there is simply no way that the compiler can ever know what the return of this instruction will be, not until the time the code is executing, before it can only say that it will be an Object
(because in Java, everything is an Object
).
But again, at runtime, if you're passing the name of the class Foo
, the the instance will be a Foo
(assuming of course that the reflective operation works correctly).
the only time you cast is when you know what class your dealing with. But then what is the point of ever casting it?
That's correct, you can only cast when you know what to cast into. And there is a sure point about casting.
Let's take a very simple example.
Imagine that you have a String
object, like String str = "something that is a string";
.
Knowing that str
is a String
, you can call methods that belong to the class String
, for example:
str.split(" "); //<-- valid because str is a String
str.replace("o", "c"); //<-- valid because str is a String
Now, imagine that str
is a String
, but it's declared as Object
:
Object str = "something that is a string";
Even though str
is concretely a String
, you won't be able to use that code anymore:
str.split(" "); //<-- INVALID: the class Object doesn't have a method .split()
str.replace("o", "c"); //<-- INVALID: the class Object doesn't have a method .replace()
So if that was the case, you would cast str
into a String
and you would be able to do what you were doing:
Object str = "something that is a string";
String str2 = (String) str;
str2.split(...);
str2.replace(...);
etc.
And of course, the cast is only possible when Object str
is actually a String
, if it was (for example) an Integer
, that would have raised a ClassCastException
.
So why do you need to cast? Because at compile time, you need to write code against a specific object, and for that you need to cast to access the methods and properties correctly.
Upvotes: 2
Reputation: 10127
The classes Class
and Constructor
provide everything
you need to accomplish your goal.
Class.forName(String)
you get the Class
object.getConstructors()
method you get an array of
Constructor
objects (representing the declarations of the
constructors).Class.getConstructors()
.getParameterTypes()
method of any of these
Constructor
s you get an array of Class
objects
(the types of the formal parameters of a constructor).Constructor.getParameterTypes()
.constructor.newInstance(param1, param2, ...)
.Example: with this code
Class<?> clazz = Class.forName("java.util.HashMap");
System.out.println(clazz);
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(" constructor: " + constructor);
Class<?>[] parameterTypes = constructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(" parameterType: " + parameterType);
}
}
you get all constructors of java.util.HashMap
and their parameter types:
class java.util.HashMap
constructor: public java.util.HashMap(int)
parameterType: int
constructor: public java.util.HashMap(int,float)
parameterType: int
parameterType: float
constructor: public java.util.HashMap(java.util.Map)
parameterType: interface java.util.Map
constructor: public java.util.HashMap()
Upvotes: 0