JasonF
JasonF

Reputation: 31

Java Auto Cast an Object

I'm wondering if there is a way to Auto Cast an Object to some type by storing the Class type along with the object? I thought this was possible with Java, but maybe not.

For example:

class StorageItem
{
    private int itemcount;

    StorageItem(int itemcount)
    {
        this.itemcount = itemcount;
    }

    int getItemCount()
    {
        return itemcount;
    }
}

class Storage
{
    private Class clazz;

    private Object value;

    public Storage(Class clazz, Object value)
    {
        this.clazz = clazz;
        this.value = value;
    }

    //Is there a way such a call can be created to automatically cast 
    //the object to the class type and return that cast type in a 
    //generic way. The idea being that Storage knows what it should
    //already be cast to. Is this possible?
    public T getValue()
    {
        return clazz.cast(value);
    }
}

A usage example:

public static void main(String[] args)
{
    //Create storage item
    Storage storage = new Storage(StorageItem.class, new StorageItem(1234));

    //The call to getValue() will automatically cast to the Class passed
    //into Storage.
    int itemcount = storage.getValue().getItemCount(); //returns 1234
}

Obviously the getValue() call in Storage is a pseudocode call, but it's just there to provide the idea as to what I would like to do.

Is there anyway to have a getValue() call that will Auto cast to the Class typed stored in the Storage class. Again, the idea is that the Storage class knows what it should be cast to. Or is there anyway this can be done at all?

StorageItem is just one simple example. Here, it just stores an int for discussion purposes. However, it could be more complex.

Another usage example, would be storing the Storage object in a list.

List<Storage> row = new ArrayList<Storage>();
row.add(new Storage(StorageItem.class, 1234));
row.add(new Storage(String.class, "Jason"));
row.add(new Storage(Integer.class, 30));
row.add(new Storage(Double.class, 12.7));

Then, these can be accessed in the following way.

//calls StorageItem's getItemCount() method
row.get(0).getValue().getItemCount(); //returns 1234

//calls String's length() method
row.get(1).getValue().length(); //returns 5

//calls Integer's intValue() method
row.get(2).getValue().intValue(); 

//calls Integer's doubleValue() method
row.get(3).getValue().doubleValue(); 

If getValue() only ever returned an Object, I would have to always cast to the specific Object manually. Instead, if I can store the cast class inside the Storage object, then Storage has enough information to know what to automatically cast the Object to on the getValue() call.

If this is doable in Java is the answer to the question I'm seeking. And if so, how?

Upvotes: 0

Views: 8822

Answers (2)

Andy Turner
Andy Turner

Reputation: 140319

I don't really see the problem that you're trying to solve here. @bali182's answer does give you a "generic" way to store a reference - but storing the reference itself is just easier.

Consider what happens if you put two Storage instances, containing differently-typed references, into a collection:

List<Storage<SOMETHING>> storages = new ArrayList<>();
storages.add(new Storage<String>("Hello"));
storages.add(new Storage<Integer>(1));

So: what is SOMETHING? Well, it has to be ?, since that is the only type which satisfies both elements.

Now, when you iterate through the list to retrieve them, you have to deal with them as Object:

for (Storage<?> storage : storages) {
  Object object = storage.getValue();
  // ...
}

because you don't, in general, know what the type of the stored reference is for any given element. The concrete type of object will be the concrete type of the element - String and Integer, for the list above - but you can't make use of these different types without using some means to detect that type (e.g. if (object instanceof String)).

It would just have been easier if the references were stored directly in the list:

List<Object> objects = new ArrayList<>();
storages.add("Hello");
storages.add(1;
for (Object object : objects) {
  // ...
}

You still would have to do something to detect the concrete type of object; you're just doing it without the extra layer of indirection.


Although the above example is for unrelated types, it's still easier to do it with the direct references if they are the same type:

List<String> objects = Arrays.asList("Hello", "World");
for (String object : objects) {
  // ...
}

Now you don't need to do anything to know the concrete type (you might, if the elements were of a non-final class, and you wanted to handle some subclasses specially), but you've still avoided needing to dereference Storage.getValue() to get at a value that you could have directly instead.

Upvotes: 1

Bal&#225;zs &#201;des
Bal&#225;zs &#201;des

Reputation: 13807

Would this do the trick? Much less hacking is required:

class Storage<T> {

    private T value;

    public Storage(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

Upvotes: 6

Related Questions