Java Auto Cast un objet


Je me demande s'il existe un moyen de convertir automatiquement un objet en un type en stockant le type de classe avec l'objet? Je pensais que c'était possible avec Java, mais peut-être pas.

Par exemple:

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);
    }
}

Un exemple d'utilisation:

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
}

Évidemment, l'appel getValue() dans Storage est un appel pseudocode, mais il est juste là pour fournir l'idée de ce que je voudrais faire.

Existe-t-il de toute façon un appel getValue () qui sera automatiquement lancé vers la classe tapée stockée dans le Classe de stockage. Encore une fois, l'idée est que la classe de stockage sait à quoi elle doit servir. Ou y a-t-il de toute façon cela peut être fait du tout?

StorageItem n'est qu'un exemple simple. Ici, il stocke juste un int à des fins de discussion. Cependant, cela pourrait être plus complexe.

Un autre exemple d'utilisation, serait de stocker l'objet de stockage dans une liste.

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));

Ensuite, on peut y accéder de la manière suivante.

//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(); 

Si getValue () n'a renvoyé qu'un objet, j'aurais pour toujours lancer manuellement sur l'objet spécifique. Au lieu de cela, si je peux stocker la classe cast dans l'objet de stockage, le stockage a suffisamment d'informations pour savoir à quoi convertir automatiquement l'objet lors de l'appel getValue ().

Si cela est faisable en Java est la réponse à la question que je cherche. Et si oui, comment?

Author: JasonF, 2016-05-21

2 answers

Cela ferait - il l'affaire? Beaucoup moins de piratage est nécessaire:

class Storage<T> {

    private T value;

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

    public T getValue() {
        return value;
    }
}
 6
Author: Balázs Édes, 2016-05-21 19:15:27

Je ne vois pas vraiment le problème que vous essayez de résoudre ici. la réponse de @bali182 vous donne un moyen "générique" de stocker une référence - mais stocker la référence elle-même est tout simplement plus facile.

Considérez ce qui se passe si vous mettez deux instances Storage, contenant des références de type différent, dans une collection:

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

Alors: qu'est-ce que SOMETHING? Eh bien, il doit être ?, car c'est le seul type qui satisfait les deux éléments.

Maintenant, lorsque vous parcourez la liste pour les récupérer, vous devez les traiter comme Object:

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

Parce que vous ne savez pas, en général, quel est le type de la référence stockée pour un élément donné. Le type concret de object sera le type concret de l'élément - String et Integer, pour la liste ci - dessus-mais vous ne pouvez pas utiliser ces différents types sans utiliser certains moyens pour détecter ce type (par exemple if (object instanceof String)).

Il aurait simplement été plus facile si les références étaient stockées directement dans le liste:

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

Vous devrez toujours faire quelque chose pour détecter le type concret d'objet; vous le faites simplement sans la couche supplémentaire d'indirection.


Bien que l'exemple ci-dessus concerne des types non liés, il est toujours plus facile de le faire avec les références directes si elles sont du même type:

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

Maintenant, vous n'avez rien à faire pour connaître le type concret (vous pourriez , si les éléments étaient d'une classe non finale, et que vous vouliez en gérer certains sous-classes spécialement), mais vous avez toujours évité d'avoir à déréférencer Storage.getValue() pour obtenir une valeur que vous pourriez avoir directement à la place.

 1
Author: Andy Turner, 2016-05-21 20:07:34