Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "dynamically" cast an instance of Object type into its specific data type?

public Object foo(int opt){
  if (opt == 0) return new String();
  else if (opt == 1) return new Integer(1);
  else if (opt == 2) return new Double(1);
  else if ...
  .. and many more
}

public void doSomething(String s){..}
public void doSomething(Integer i){..}
public void doSomething(Double d){..}
... and many more doSomething method

public static void main(String[] args){
  ...
  Object o = foo(x); //x is a value obtained during runtime, e.g. from user input

  //now I want to call doSomething method
  // (1)
  if (o instanceof String) doSomething((String) o);
  else if (o instanceof Integer) doSomething((Integer) o);
  else if (o instanceof Double) doSomething((Double) o);
  ...
  // (2)
}

Is there any better way to simplify statements enclosed by (1) ... (2)?
Does Java Reflection help?

like image 533
Pahlevi Fikri Auliya Avatar asked Apr 11 '11 05:04

Pahlevi Fikri Auliya


People also ask

How do you cast dynamic type in Java?

You can do dynamic casting by calling a method which takes a parameter of the type you want to change your current type to. Take this for example: public class Example{ Example e1=new Example(); private Object obj=new Object(); e1.

Which is used for casting of object to a type or a class?

Type Casting is a feature in Java using which the form or type of a variable or object is cast into some other kind of Object, and the process of conversion from one type to another is called Type Casting.

Which keyword is used to cast an object into another type?

You convert an Object variable to another data type by using a conversion keyword such as CType Function.

How do you dynamically name an object in Java?

To create an object dynamically from the class name, you need to use a reflection. If the fully-qualified name of a class is available, it is possible to get the corresponding Class using the static method Class. forName(). However, This cannot be used for primitive types.


2 Answers

The best way to handle this efficiently and cleanly is to have foo return a holder class for the object.

abstract class Holder<T> {
    private final T object;

    protected Holder(T object) { this.object = object; }
    public T get() { return object; }
    public abstract void doSomething();
}

public Holder foo(int opt) {
    if (opt == 0) return new Holder<String>("") {
        public void doSomething() { }
    };
    else if (opt == 1) return new Holder<Integer>(1) {
        public void doSomething() { }
    };
    else if (opt == 2) return new Holder<Double>(1.0) {
        public void doSomething() { }
    };
    // many more
}

public static void main(String... args) throws IOException {
    Holder h  = foo(x); //x is a value obtained during runtime, e.g. from user input

    //now I want to call doSomething method
    h.doSomething();
}
like image 86
Peter Lawrey Avatar answered Sep 21 '22 19:09

Peter Lawrey


Basically you want overload resolution performed at execution time - you're not going to be able to do that very simply.

In some cases, the visitor pattern can help, but I don't think it would here. I think you're stuck with either the code that you've got here, or reflection. I've never been as keen on the visitor pattern as some of my colleagues - it always feels a little messy - but it's worth a thought.

Could you make foo call the right doSomething overload instead of just returning the value? That's the bit of code which knows what's being constructed - if you could pass it an object to call doSomething on with the appropriate overload, you'd end up with the type-specific logic all in one place.

In Java 7 it's possible that invokedynamic will be useful in this sort of situation - certainly the dynamic type in C# 4 would help - but I haven't looked into invokedynamic enough to say for sure.

like image 28
Jon Skeet Avatar answered Sep 20 '22 19:09

Jon Skeet