Question Pourquoi les classes wrapper n'ont-elles pas un supertype commun?


Y a-t-il une raison particulière derrière  classes wrapper (java.lang.Integer, java.lang.Boolean, ...) n'ayant pas de supertype commun?


Je demande parce que ce serait très pratique d'avoir (par exemple) WrapperType::getType fonction le long du classique Object::getClass qui retournerait la classe du type primitif.

Plus précisément, le contexte appelle des constructeurs via une réflexion où vous n'avez que le Class<T> et les paramètres Object[]

Par exemple:

public static <T> T createInstance(Class<T> clz, Object... params) throws Exception

Pour obtenir le constructeur, je peux obtenir les types de paramètres via:

Class<?>[] c = Arrays
        .stream(params)
        .map(Object::getClass)
        .toArray(Class<?>[]::new);
return clz.getConstructor(c).newInstance(params);

mais cela échouera bien sûr avec des constructeurs comme String::new(char[], int, int);

Si ce supertype existait, je pourrais faire:

.map( o -> o.getClass().isPrimitive() ? ((WrapperType) o).getType() : o.getClass() )

Je suppose qu'il y a une raison particulière java les développeurs ne l'ont pas implémenté.


10
2018-04-26 13:26


origine


Réponses:


Les concepteurs Java ne sont probablement pas trop abstraits dans leurs décisions et ne peuvent trouver beaucoup de similitudes entre les types numériques (par ex. Integer) et les types non numériques (par ex. Boolean) pour les regrouper par une super-classe.

Bien que tous les types numériques s'étendent Number qui représente vraiment "les valeurs numériques convertibles en types primitifs byte, double, float, int,long, short".

En fait, toutes les classes wrapper ont une interface commune Comparable<T> (par exemple. Comparable<Integer> pour Integer).


1
2018-04-26 13:49



Je peux voir à quel point cela serait pratique, mais en termes d'abstraction, ce serait un gros désordre. Disons que vous avez les enveloppes Integer et Double avec les autres dans cette famille, ils ont java.lang.Number comme leur super. Cependant, il n'y a pas de relation sémantique entre eux et un booléen (en tenant compte des influences).

Mais pour des raisons d'argumentaires, considérons qu'ils sont tous dans un grand seau et sont des Wrappers, sont-ils toujours des nombres?

Compte tenu de l'aversion historique des langues pour l'héritage multiple, le fait d'avoir des numéros rendrait beaucoup plus de scène si vous deviez choisir.

Après le grand changement révolutionnaire des capacités linguistiques avec SE 8, nous sommes désormais en mesure d’avoir plusieurs héritages via des interfaces tout en utilisant des implémentations standard pour de tels cas. Et si l'on analyse plus avant, ils concluront, dans un raisonnement logique, que ces cas nécessitent des contrats et non des héritages; ainsi, même si cela est fait, ce serait un travail pour les interfaces.

Compte tenu du fait qu’il s’agit d’un moyen solide d’appliquer cela, et que Wrappers serait un moyen très général de le faire, nous pouvons voir que c’est mieux de ne pas l’avoir. Bien que ce soit maintenant possible, il y a des raisons historiques et sémantiques pour lesquelles ce n'était pas le cas, du moins en tant que super classe. L'abstraction est la clé ici. Mais rien ne vous empêche d'insérer une usine dans votre pipeline ou d'implémenter l'interface mentionnée.

Buttom line, les facteurs clés sont:

  1. Abstraction: c'est un contrat qui ressemble plus à une relation is-a
  2. Histoire: génériques et héritage multiple à travers des interfaces
  3. Imaginez la taille de l'héritage trois si nous accepterions cas comme: c'est d'abord un wrapper, ensuite un nombre ou un booléen.

1
2018-04-26 13:50