0

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?

8
  • 4
    Why won't you use a simple generic class? Commented May 21, 2016 at 19:13
  • Why Storage storage = new Storage(StorageItem.class, new StorageItem(1234)); instead of StorageItem storageItem = new StorageItem(1234);? Commented May 21, 2016 at 19:15
  • Change class Storage { ... and private Object value to class Storage<T> { ... resp. private T value; and you're all set. Commented May 21, 2016 at 19:15
  • I'd like to avoid directly casting the Object type if it can be done automatically for me. Since Storage knows what class it should cast itself too, I'm not sure if a method could be written to Auto Cast to the Class that was passed into the Storage object. Please see my recent updates above. Commented May 21, 2016 at 20:12
  • What you're asking to do here can't be done: there is no way that the compiler can know that row.get(0) is an instance of a "StorageItem-bearing" Storage, rather than a "String-bearing" Storage. Commented May 21, 2016 at 20:19

2 Answers 2

6

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;
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Not only is much less hacking required, it also works with generic types, like List<String>, for which no non-raw class instance exists.
1

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.

6 Comments

"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". Exactly, unless Storage knows what concrete type to cast it to. You can see that I passed in the Concrete type. So, Storage now knows that SOMETHING to cast it to. See my updates I recently posted. What I may be trying to do may not be possible. But, that's why I'm asking, since I don't know if there is a way. =)
@JasonF the compiler doesn't know the type of the stored object, but the stored object knows its own type, which you can retrieve using getClass(). Bear in mind that casting doesn't create a new object - it just says to the compiler "you think this is an Object, but trust me, I know it's a String". In other words, object == (String) object is true, assuming object.getClass() == String.class.
@ AndyT, BTW thanks for your input on this. Right, casting doesn't create an new Object. The only way getItemCount() will be callable, is if the Object was understood to be of type StorageItem. You can see how I'm using the getValue call above. If the getValue can auto cast to the StorageItem, then getItemCount() would be callable. How this can be done or IF this can be done is not known to me in Java. If it can be done in some way, then how? If not, then why?
"If not, then why?" Because that's the way that Java's type system works.
Ok, so you are saying there's no way for getValue() in Storage to be written that will Auto Cast the Object to the Class type that Storage is storing. If it can't be done, it can't be done. It's why I'm asking =)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.