Java: how can I dynamically cast a variable from one type to another?

I would like to do dynamic casting for a java variable, the cast type is stored in another variable.

this is regular casting:

String a = (String) 5; 

this is what i want:

  String theType = 'String'; String a = (theType) 5; 

Is it possible? And if so, how? thank!

Update

I am trying to populate the hashMap class that I got.

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 is that some of the class variables are double, and if the number 3 is received, it sees it as Integer and I have a type problem.

+54
java casting dynamic-cast
Jan 24 '10 at 14:11
source share
13 answers

As for your update, the only way to solve this problem in Java is to write code that covers all cases with a lot of if and else and instanceof expressions. What you are trying to do looks as if it was used for programming with dynamic languages. In static languages, what you are trying to do is almost impossible, and you probably would have taken a completely different approach to what you are trying to do. Static languages ​​are not as flexible as dynamic ones :)

Good examples of Java best practices are the BalusC answer (i.e., ObjectConverter ) and the Andreas_D answer (i.e. Adapter ) below.




It doesn't make sense in

 String a = (theType) 5; 

type a statically linked to String , so there is no point in dynamically casting to this static type.

PS: The first line of your example can be written as Class<String> stringClass = String.class; but still you cannot use stringClass to convert variables.

+10
Jan 24 '10 at 14:17
source share

Yes, you can use Reflection

 Object something = "something"; String theType = "java.lang.String"; Class<?> theClass = Class.forName(theType); Object obj = theClass.cast(something); 

but this does not make much sense, since the resulting object must be stored in a variable of type Object. If you need the be variable of a given class, you can simply apply it to this class.

If you want to get the given class, for example Number:

 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 in doing this, you can just point to Number.

Casting an object does not change anything; it is just a compiler way. The only reason that does something like this is to check if the object is an instance of this class or any subclass of it, but it is best done using instanceof or Class.isInstance() .

Update

according to the latest update , the real problem is that you have an Integer in your HashMap that must be assigned to Double. What you can do in this case is to check the type of the field and use the xxxValue() methods for the 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 ​​the wrong type on the map)

+81
Jan 24 '10 at 14:35
source share

To do this, you need to write an ObjectConverter . This is doable if you have both the object you want to convert and you know the target class to which you want to convert. In this particular case, you can get the target class Field#getDeclaringClass() .

You can find an example of such an ObjectConverter . This should give you a basic idea. If you want more conversion features, just add additional methods to it with the desired argument and return type.

+19
Jan 24 '10 at 14:29
source share

You can do this using the Class.cast() method, which dynamically passes the provided parameter to the type of class instance that you have. To get an instance of a class for a specific field, you use the getType() method in the corresponding field. I gave an example below, but note that it does not account for all error handling and should not be used without changes.

 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); } } 
+11
Jan 24
source share

This works and there is even a common template for your approach: Adapter template . But, of course, (1) this does not work to cast java primitives to objects, and (2) the class must be adapted (usually by implementing a user interface).

With this template, you can do something like:

 Wolf bigBadWolf = new Wolf(); Sheep sheep = (Sheep) bigBadWolf.getAdapter(Sheep.class); 

and the getAdapter method in the Wolf class:

 public Object getAdapter(Class clazz) { if (clazz.equals(Sheep.class)) { // return a Sheep implementation return getWolfDressedAsSheep(this); } if (clazz.equals(String.class)) { // return a String return this.getName(); } return null; // not adaptable } 

A special idea for you is impossible. You cannot use a String value for casting.

+4
Jan 24 '10 at 14:29
source share

Your problem is not the lack of “dynamic casting”. Dropping Integer to Double generally not possible. It seems you want to give a Java object of the same type, a field, possibly of an incompatible type, and ask it to somehow figure out automatically how to convert between the types.

Things like that are anathema for a strongly typed language like Java, and IMO for very good reasons.

What are you really trying to do? Everything that uses reflection looks rather suspicious.

+2
Jan 24 '10 at 14:29
source share

You can write a simple castMethod method as shown below.

 private <T> T castObject(Class<T> clazz, Object object) { return (T) object; } 

In your method you should use it as

 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()); } } } 
+2
May 04 '16 at 7:29
source share

Do not do this. Instead, just create a properly parameterized constructor. The set and types of connection parameters are fixed in any case, so there is no point in doing this all dynamically.

+1
Jan 24
source share

For what it's worth, most scripting languages ​​(like Perl) and non-static compile-time languages ​​(like Pick) support an automatic dynamic String sequence for (relatively arbitrary) objects. This MAY be implemented in Java, as well as without loss of type safety and the good materials that statically typed languages ​​provide WITHOUT the unpleasant side effects of some other languages ​​that do evil with dynamic casting. An example of Perl that calls up some dubious math:

 print ++($foo = '99'); # prints '100' print ++($foo = 'a0'); # prints 'a1' 

In Java, this is better done (IMHO) using a method that I call cross-casting. With cross-casting, reflection is used in the lazy cache of constructors and methods that are dynamically detected using the following static method:

 Object fromString (String value, Class targetClass) 

Unfortunately, no built-in Java methods, such as Class.cast (), will do this for String for BigDecimal or String for Integer or any other conversion where there is no supporting class hierarchy. For its part, the goal is to provide a fully dynamic way to achieve this goal - for which I do not think the previous link is the right approach - the need to encode every transformation. Simply put, an implementation is just different from the string if it is legal / possible.

Thus, the decision is a simple reflection seeking public members:

STRING_CLASS_ARRAY = (new class [] {String.class});

a) Member = targetClass.getMethod (method.getName (), STRING_CLASS_ARRAY); b) Member = targetClass.getConstructor (STRING_CLASS_ARRAY);

You will find that all primitives (Integer, Long, etc.) and all the basics (BigInteger, BigDecimal, etc.) and even java.regex.Pattern are covered by this approach. I used this with considerable success in production projects where there are a huge number of arbitrary values ​​of String values, where a more stringent check is required. In this approach, if there is no method or when the method is called, an exception is thrown (since this is an invalid value, such as non-numeric input in BigDecimal or illegal RegEx for the template), which provides a check specific to the logic of the target class.

There are some disadvantages:

1) You need a good understanding of reflection (this is a bit complicated, not for beginners). 2) Some of the Java classes and truly third-party libraries (surprises) are incorrectly encoded. That is, there are methods that take one string argument as input and return an instance of the target class, but this is not what you think ... Consider the Integer class:

 static Integer getInteger(String nm) Determines the integer value of the system property with the specified name. 

The above method really has nothing to do with integers as objects that combine ints primitives. Reflection will find this as a possible candidate for creating Integer from String incorrectly compared to decode, valueof and constructor members, which are suitable for most arbitrary String conversions, where you really don't control your input, but just want to know if an integer is possible .

To fix this, looking for methods that throw exceptions is a good start, because invalid input values ​​that instantiate such objects should throw an exception. Unfortunately, implementations differ depending on whether the exceptions are declared checked or not. Integer.valueOf (String) throws a NumberFormatException thrown exception, but Pattern.compile () exceptions were not found while looking for reflections. Again, this dynamic cross-casting approach does not fail, I think this is a very non-standard implementation for declaring exceptions in object creation methods.

If someone wants to get more detailed information about how this was implemented, let me know, but I think this solution is much more flexible / extensible and with less code, without losing the good parts of type safety. Of course, it’s always better to “know your data”, but as many of us find, we are sometimes only recipients of unmanaged content and should do everything possible to use it properly.

Greetings.

+1
Jun 27 '11 at 16:59
source share

So this is an old post, but I think I can add something to it.

You can always do something like this:

 package com.dyna.test; import java.io.File; import java.lang.reflect.Constructor; public class DynamicClass{ @SuppressWarnings("unchecked") public Object castDynamicClass(String className, String value){ Class<?> dynamicClass; try { //We get the actual .class object associated with the specified name dynamicClass = Class.forName(className); /* We get the constructor that received only a String as a parameter, since the value to be used is a String, but we could easily change this to be "dynamic" as well, getting the Constructor signature from the same datasource we get the values from */ Constructor<?> cons = (Constructor<?>) dynamicClass.getConstructor(new Class<?>[]{String.class}); /*We generate our object, without knowing until runtime what type it will be, and we place it in an Object as any Java object extends the Object class) */ Object object = (Object) cons.newInstance(new Object[]{value}); return object; } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { DynamicClass dynaClass = new DynamicClass(); /* We specify the type of class that should be used to represent the value "3.0", in this case a Double. Both these parameters you can get from a file, or a network stream for example. */ System.out.println(dynaClass.castDynamicClass("java.lang.Double", "3.0")); /* We specify a different value and type, and it will work as expected, printing 3.0 in the above case and the test path in the one below, as the Double.toString() and File.toString() would do. */ System.out.println(dynaClass.castDynamicClass("java.io.File", "C:\\testpath")); } 

Of course, this is not dynamic casting, as in other languages ​​(e.g. Python), because java is a statically typed language. However, this may solve some cases when you really need to load some data in different ways, depending on some identifier. In addition, the part where you get the constructor with the String parameter can probably be more flexible since this parameter is passed from the same data source. That is, from the file you get the signature of the constructor that you want to use, and the list of values ​​that will be used, so you, for example, the first paragraph, are a string, with the first object, exposing it as a string, the next object is Integer and etc., but some of them are executed during the execution of your program, you first get a File object, then Double, etc.

Thus, you can take these cases into account and perform dynamic casting on the fly.

Hope this helps anyone as it continues to appear in a Google search.

+1
Nov 07
source share

It recently seemed to me that I should have done this too, but then I found another way that might make my code tidier and use better OOP.

I have many classes of sisters, each of which implements a specific doSomething() method. To access this method, I had to first have an instance of this class, but I created a superclass for all my sibling classes, and now I can access this method from the superclass.

Below I show two ways of alternative methods of "dynamic casting".

 // Method 1. mFragment = getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum)); switch (mUnitNum) { case 0: ((MyFragment0) mFragment).sortNames(sortOptionNum); break; case 1: ((MyFragment1) mFragment).sortNames(sortOptionNum); break; case 2: ((MyFragment2) mFragment).sortNames(sortOptionNum); break; } 

and my current method,

 // Method 2. mSuperFragment = (MySuperFragment) getFragmentManager().findFragmentByTag(MyHelper.getName(mUnitNum)); mSuperFragment.sortNames(sortOptionNum); 
0
Aug 16 '13 at 21:09
source share

I just thought that I would publish something that I found very useful and might be possible for those who have similar needs.

The next method is the method that I wrote for my JavaFX application to avoid the need for actuation and also to avoid writing if the instance of object x is an instance of object b each time the controller returns.

 public <U> Optional<U> getController(Class<U> castKlazz){ try { return Optional.of(fxmlLoader.<U>getController()); }catch (Exception e){ e.printStackTrace(); } return Optional.empty(); } 

The declaration of the method to get the controller was

 public <T> T getController() 

Using the type U passed to my method through the class object, it can be redirected to the get get controller of the method to tell it which type of object should be returned. An optional object is returned if the wrong class is specified and an exception is thrown, in which case an empty optional element is returned, which we can check.

This is what the last method call looked like (if it contains a return optional object, the Consumer object

 getController(LoadController.class).ifPresent(controller->controller.onNotifyComplete()); 
0
May 7 '15 at 1:04
source share

Try this for Dynamic Casting. It will work !!!

  String something = "1234"; String theType = "java.lang.Integer"; Class<?> theClass = Class.forName(theType); Constructor<?> cons = theClass.getConstructor(String.class); Object ob = cons.newInstance(something); System.out.println(ob.equals(1234)); 
0
Apr 27 '17 at 2:33 on
source share



All Articles