java: How can I do dynamic casting of a variable from one type to another?
Solution 1
Regarding your update, the only way to solve this in Java is to write code that covers all cases with lots of
if
andelse
andinstanceof
expressions. What you attempt to do looks as if are used to program with dynamic languages. In static languages, what you attempt to do is almost impossible and one would probably choose a totally different approach for what you attempt to do. Static languages are just not as flexible as dynamic ones :)Good examples of Java best practice are the answer by BalusC (ie
ObjectConverter
) and the answer by Andreas_D (ieAdapter
) below.
That does not make sense, in
String a = (theType) 5;
the type of a
is statically bound to be String
so it does not make any sense to have a dynamic cast to this static type.
PS: The first line of your example could be written as Class<String> stringClass = String.class;
but still, you cannot use stringClass
to cast variables.
Solution 2
Yes it is possible using Reflection
Object something = "something";
String theType = "java.lang.String";
Class<?> theClass = Class.forName(theType);
Object obj = theClass.cast(something);
but that doesn't make much sense since the resulting object must be saved in a variable of Object
type. If you need the variable be of a given class, you can just cast to that class.
If you want to obtain a given class, Number
for example:
Object something = new Integer(123);
String theType = "java.lang.Number";
Class<? extends Number> theClass = Class.forName(theType).asSubclass(Number.class);
Number obj = theClass.cast(something);
but there is still no point doing it so, you could just cast to Number
.
Casting of an object does NOT change anything; it is just the way the compiler treats it.
The only reason to do something like that is to check if the object is an instance of the given class or of any subclass of it, but that would be better done using instanceof
or Class.isInstance()
.
Update
according your last update the real problem is that you have an Integer
in your HashMap
that should be assigned to a Double
. What you can do in this case, is check the type of the field and use the xxxValue()
methods of Number
...
Field f = this.getClass().getField(entry.getKey());
Object value = entry.getValue();
if (Integer.class.isAssignableFrom(f.getType())) {
value = Integer.valueOf(((Number) entry.getValue()).intValue());
} else if (Double.class.isAssignableFrom(f.getType())) {
value = Double.valueOf(((Number) entry.getValue()).doubleValue());
} // other cases as needed (Long, Float, ...)
f.set(this, value);
...
(not sure if I like the idea of having the wrong type in the Map
)
Solution 3
You'll need to write sort of ObjectConverter
for this. This is doable if you have both the object which you want to convert and you know the target class to which you'd like to convert to. In this particular case you can get the target class by Field#getDeclaringClass()
.
You can find here an example of such an ObjectConverter
. It should give you the base idea. If you want more conversion possibilities, just add more methods to it with the desired argument and return type.
Solution 4
You can do this using the Class.cast()
method, which dynamically casts the supplied parameter to the type of the class instance you have. To get the class instance of a particular field, you use the getType()
method on the field in question. I've given an example below, but note that it omits all error handling and shouldn't be used unmodified.
public class Test {
public String var1;
public Integer var2;
}
public class Main {
public static void main(String[] args) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
map.put("var1", "test");
map.put("var2", 1);
Test t = new Test();
for (Map.Entry<String, Object> entry : map.entrySet()) {
Field f = Test.class.getField(entry.getKey());
f.set(t, f.getType().cast(entry.getValue()));
}
System.out.println(t.var1);
System.out.println(t.var2);
}
}
Solution 5
You can write a simple castMethod like the one below.
private <T> T castObject(Class<T> clazz, Object object) {
return (T) object;
}
In your method you should be using it like
public ConnectParams(HashMap<String,Object> object) {
for (Map.Entry<String, Object> entry : object.entrySet()) {
try {
Field f = this.getClass().getField(entry.getKey());
f.set(this, castObject(entry.getValue().getClass(), entry.getValue()); /* <= CASTING PROBLEM */
} catch (NoSuchFieldException ex) {
log.error("did not find field '" + entry.getKey() + '"');
} catch (IllegalAccessException ex) {
log.error(ex.getMessage());
}
}
}
Comments
-
ufk about 4 years
I would like to do dynamic casting for a Java variable, the casting type is stored in a different variable.
This is the regular casting:
String a = (String) 5;
This is what I want:
String theType = 'String'; String a = (theType) 5;
Is this possible, and if so how? Thanks!
Update
I'm trying to populate a class with a
HashMap
that I received.This is the constructor:
public ConnectParams(HashMap<String,Object> obj) { for (Map.Entry<String, Object> entry : obj.entrySet()) { try { Field f = this.getClass().getField(entry.getKey()); f.set(this, entry.getValue()); /* <= CASTING PROBLEM */ } catch (NoSuchFieldException ex) { log.error("did not find field '" + entry.getKey() + '"'); } catch (IllegalAccessException ex) { log.error(ex.getMessage()); } } }
The problem here is that some of the class' variables are of type
Double
, and if the number 3 is received it sees it asInteger
and I have type problem. -
ufk over 14 yearsI hope that the updated that i posted will explain what i'm trying to do. i come from a php background so maybe this thing is not possible to achieve in java.
-
Sandeep Chauhan over 14 yearsExactly, in Java you cannot be that dynamic, see my update as well.
-
Sandeep Chauhan over 14 yearsSee BalusC's answer below, this is the length (and pain) to which you have to go...
-
srini.venigalla over 14 years@BalusC - I find the ObjectConverter code interesting, could you please describe the use cases for it?
-
BalusC over 14 yearsIt's useful in cases when convention over configuration is preferred and the source type doesn't match the target type. I have used it 2-3 years ago in my (pure for hobby purposes) ORM and MVC frameworks. Also see the leading text of the blog article.
-
BalusC over 14 yearsWhat if the entry type isn't a supertype of the field type at all? You'll then really need to convert programmatically.
-
Michael Borgwardt about 11 years@name: concerning the edit you keep suggesting: note that I am talking about not about primitive values but about the wrapper classes (signified by the capitalization and the styling as code), and casting between those is definitely not possible.
-
ruiruige1991 over 5 yearsYes, I think this answer is what the asker want. He/She just get a Class<?>, and wants to convert an instance to the class "?". By default java do not support this. But using <T> we can do this.
-
George Xavier over 4 yearsI know this is late but I think he meant [thetype] a = (thetype)some_object; which is pointless because you can just do Object a = some_object fine
-
George Xavier over 4 years@ruiruige1991 This is wrong. T in which case is a generic. Generics do nothing during runtime. (T)blah would just be (Object)blah during runtime because of type erasure. In short, generics -> compile-time, and has no effect during runtime. Since dynamic -> runtime and generics -> compile time, generics are useless.
-
George Xavier over 4 yearsYou shouldn't need to dynamically cast ever. Your formula of having a superclass with the method doSomething() and subclasses that implement the method doSomething() is one of the main purposes of OOP, polymorphism. Object foo = new Integer("1"); foo.toString() returns 1. Even though it is assigned to Object, it is an Integer, and therefore behaves as such. Running the method toString will run the Integer implementation. Polymorphism.