Histoire générique Java

introduction

En raison de la précédente histoire statique Java , je vais continuer le temps Java.

objectif

Qu'il s'agisse de génériques ou de génériques, mis à part. Jetons un coup d'œil à quelques exemples simples et jouons avec les génériques en Java.

Génériques (type générique) et sécurité de type

Introduit dans jdk 1.5.

Au moment où j'écrivais ceci, Java a dit: «Veuillez mettre à jour jdk 9.0.4» et j'ai entendu dire que java10 allait être publié, il est donc devenu jdk 1.5 ... ..

Avant ça,

List lst = new ArrayList();
Map map = new HashMap();

Il semble qu'il ait été écrit dans un type brut comme celui-ci. Cela peut toujours fonctionner, mais ce n'est pas recommandé.

N'importe quel objet s'intégrera. Il s'intégrera

lst.add("sample");
lst.add(11111);

// for-chacun vaut aussi 1.5 ou plus tard
//L'itérateur est toujours brut
Iterator it = lst.iterator();
while (it.hasNext()) {
  Object o = it.next();
  System.out.print(o); // sample1111
}

Cela ne garantit pas la sécurité des moisissures. Vous devez effectuer un cast soigneusement lors de la récupération des éléments de la collection

lst.add("sample");
lst.add(11111);

Iterator it = lst.iterator();
while (it.hasNext()) {
  Object o = it.next();
  System.out.print((String) o); //sample et ClassCastException
}

De cette façon, si vous faites une erreur dans le type, que ce soit une erreur ou non, vous remarquerez l'exception uniquement à l'exécution, et le programme peut s'arrêter à un moment inattendu.

Concernant l'exception

Le ClassCastException levé lorsque la conversion échoue est une classe d'exception qui hérite de `` RuntimeException.

RuntimeException est une exception d'exécution et la gestion des exceptions incombe à l'utilisateur..


 En d'autres termes, le moment de remarquer l'erreur n'est pas au moment de la compilation, mais au moment de l'exécution suivante.


# Argument formel `` `` <E> '' ``
 Depuis jdk 1.5, l'interface `` Collection '' a évolué (?) Vers `` Collection <E> `` `` pour n'accueillir qu'un seul type.

#### **`Comme écrit dans la collection javadoc, E est"Types d'éléments de cette collection"Est-ce. `**

Il en va de même pour la List``` qui hérite de la collection, qui est maintenant List '' ``. Je n'ai pas encore décidé ce qui sera inclus, mais je vous garantis qu'un seul type sera inclus, donc je vais le mettre temporairement. C'est probablement l'E.

Ainsi, lors de la création d'une instance d'une liste, List lst = new ArrayList <> (); `` ou ... Enfin, le siège de l'argument formel est rempli, où Integer est le argument réel </ b> dans cette liste.

Opérateur diamant depuis jdk7

List lst = new ArrayList(); List lst = new ArrayList<>(); //Maintenant facultatif


 Ces interfaces génériques et leurs classes d'implémentation sont appelées <b> types génériques </ b>.

 De plus, les génériques en java peuvent être déclarés pour les classes, les interfaces, les méthodes et les constructeurs.

# Différence entre le type brut et `` <Object> ''
 Par exemple, comme le prototype List, `` List <Object> '' `` peut stocker des objets de tout type.

```java
 List<Object> objList = new ArrayList<>();
 objList.add("a");
 objList.add(1);
 objList.add(new Sample());

À ce stade, cela ne semble pas faire beaucoup de différence,

Tout d'abord, la liste de types bruts est

  private static List rawList() {
    return new ArrayList();
  }

  private static void printList(List rawList) {
    rawList.forEach(System.out::println);
  }
  public static void main(String... args) {
    printList(rawList()); //Traverser
  } 

Le compilateur ne dit rien. En d'autres termes, il n'est pas de type sécurisé car le moment où une incompatibilité de type se produit et vous remarquez qu'il est à l'exécution.

D'autre part, List '' ``

List<Object> objList = new ArrayList<String>(); //Erreur de compilation

Et

  private static List<String> strList() {
    return new ArrayList<String>();
  }

  private static void printObjList(List<Object> objList) {
    objList.forEach(System.out::println);
  }

  public static void main(String... args) {
    printObjList(strList()); //Erreur de compilation
  }

Et vice versa (?)

  private static List<Object> objList() {
    return new ArrayList<Object>();
  }

  private static void printStrList(List<String> strList) {
    strList.forEach(System.out::println);
  }

  public static void main(String... args) {
    printStrList(objList()); //Erreur de compilation
  }

Ne peux pas.

La raison en est que List <String> '' est un sous-type de List, mais pas List ''. C'est-à-dire `` List '' Il n'y a pas de relation d'héritage entre ʻet List .

Pour cette raison, les génériques sont appelés invariants </ I>.

Donc, si vous souhaitez modifier l'un des codes précédents

List<Object> objList = new ArrayList<String>(); //Erreur de compilation
List<?> someTypeList = new ArrayList<String>();

Je pense que ça va ressembler à ça.

<?>En ce qui concerne, je voudrais l'organiser dans le wild card suivant.



# Différence entre les génériques et la séquence

## La séquence est covariante
 C'est une continuation de l'histoire selon laquelle les génériques sont immuables.
 En ce qui concerne la nature de la covariance, nous avons parlé de la «relation d'héritage» plus tôt, mais avec un tableau, vous pouvez faire quelque chose comme ça.

```java
  private static void printAry(Object[] objAry) {
    Arrays.stream(objAry).forEach(System.out::println);
  }

  private static String[] strAry(String[] strAry) {
    return strAry;
  }

  printAry(strAry(new String[]{"a", "b", "c"}));

S'il existe une relation d'héritage entre String et Object (String est un sous-objet de Object), la relation d'héritage est également appliquée entre String [] et Object [].

En d'autres termes

Object[] objAry = new String[10];
objAry[0] = 1; 

J'essaye de stocker un type invalide, mais je ne le remarque pas au moment de la compilation.

Gomme générique (type de suppression)

  • Réalisation
    Le tableau connaît déjà le type d'élément au moment de l'exécution et s'exécutera avec ce type.

  • Impossible de se matérialiser
    D'autre part, les génériques sont implémentés par gomme (les informations sur le type d'élément sont effacées au moment de l'exécution) une fois qu'elles sont vérifiées au moment de la compilation. Une information est perdue au moment de l'exécution par rapport au moment de la compilation.
    Cela nous a permis d'ajouter des génériques à un type brut existant, même pour une collection de types bruts antérieure à jdk 1.5.

Conception générique

Tuple Un tapple est une structure de données qui peut stocker plusieurs éléments différents dans l'ordre.

Pair.java


public class Pair<V, W> {
  private final V v;
  private final W w;

  Pair(V v, W w) {
    this.v = v;
    this.w = w;
  }

  V getV() {
    return v;
  }

  W getW() {
    return w;
  }
}
Pair<String, Integer> tuple2 = new Pair<>("toilet-score", 100);

String v = tuple2.getV();
Integer w = tuple2.getW();
  
System.out.println(v + w);

En développant le type d'utilisation de la paire qui stocke et récupère deux types de données hétérogènes de base, tels que

TupleUtils.java


public class Tuple {
  public static class Tuple2<A, B> {
    private final A a;
    private final B b;

    public Tuple2(A a, B b) {
      this.a = a;
      this.b = b;
    }

    public A getA() {
      return a;
    }

    public B getB() {
      return b;
    }
  }

  public static class Tuple3<A, B, C> extends Tuple2<A, B> {
    private final C c;

    public Tuple3(A a, B b, C c) {
      super(a, b);
      this.c = c;
    }

    public C getC() {
      return c;
    }
  }

  // Tuple4, Tuple5 ... 
}

(Ajout de la classe interne statique pour la polyvalence, modification de l'accesseur pour chaque constructeur en public) Je pense que vous pouvez créer une classe d'utilitaire taple générique qui peut stocker trois, quatre ou plusieurs types de données de manière sécurisée.

Empruntez la sagesse de nos prédécesseurs

En tant que modèle plus fiable et diversifié, la bibliothèque existe déjà, donc la célèbre est Commons Lang Pair etc. .

Par contre, bien qu'il soit petit, il est volontairement fourni d'un type à dix types (!) Avec une configuration simple javatuples: github officiel Voir aussi .

Concernant les javatuples, personnellement, je pensais qu'un taple qui n'a qu'un seul type appelé Unit a commencé, et à partir de là, il a une belle forme d'héritage ... mais il en a deux types. Il était intéressant de noter que la classe Tuple était l'axe et que l'Unité était héritée de Tuple.

Caractère générique

En tant qu'extension de l'histoire précédente, les génériques sont immuables.Le pseudotype <T> '' garantit qu'il y aura un certain type, mais c'est un type qui hérite du type T. List <Object> '' et List '' `` n'ont pas de relation d'héritage. Autrement dit, ce n'est pas flexible.

Par conséquent, au même moment que Generics (jdk 1.5), un joker apparaîtra.

Caractère générique sans limite <?>

Si vous souhaitez utiliser des génériques mais que vous n'avez pas encore décidé des paramètres de type réels, passez ? '' Au type temporaire <E> ``.

//Parce que T ne peut pas être résolu,Erreur de compilation
List<T> someList = new ArrayList<String>(); 

//Parce que vous essayez de le stocker avant que le type réel ne soit décidé,Erreur de compilation
List<?> anotherList = new ArrayList<>(); anotherList.add("a"); 

// OK
List<?> theOtherList = new ArrayList<String>(); theOtherList.add("a"); 

Bordure générique (limite supérieure) <? Étendre T> ``

// OK.Integer est le sous-nombre de Number-class.
List<? extends Number> myList = new ArrayList<Integer>();  

 // OK.Long est le sous de Number-class.
List<? extends Number> yourList = new ArrayList<Long>();  

//Parce que Object est un type qui dépasse Number,Erreur de compilation
List<? extends Number> someList = new ArrayList<Object>();

Bordure générique (limite inférieure) <? Super T> ``

//Parce que Long n'est pas une classe superordonnée d'Integer,Erreur de compilation
List<? super Integer> suNumList2 = new ArrayList<Long>(); 

// OK.Number est une classe superordonnée d'Integer. 
List<? super Integer> suNumList = new ArrayList<Number>();

Interface fonctionnelle et génériques

Voici les principales interfaces fonctionnelles introduites dans jdk 1.8. Interface fonctionnelle javadoc , mais une méthode abstraite C'est une interface qui n'a que.

Ce qui suit fait partie de l'interface Function contenue dans java.util.Objects```.

Function.java


@FunctionalInterface
public interface Function<T, R> {
    /**
     * Applies this function to the given argument. 
     *Accepte l'argument donné.
     * 
     * @param t the function argument 
     *Paramètres t Argument de fonction
     * 
     * @return the function result 
     *Résultat de la fonction de retour
     */
    R apply(T t);

    // omit 
}

Ces interfaces de fonction, telles que Function BiFunction Consumer Supplier ... Je n'ai pas encore décidé du type, mais j'accepte quelque chose Encore une fois, le type n'a pas encore été décidé, mais il représente une structure qui renvoie quelque chose en conséquence.

IntSupplier getAsInt()Certaines méthodes, telles que les méthodes, ont décidé à l'avance que la valeur de retour est uniquement de type int, mais en gros, vous pouvez voir que nous essayons de la rendre flexible en utilisant des génériques..



# Jeu de type générique et méthode I-Generics
 C'est un sous-titre étrange, mais c'est comme un mémo de jeu.

 L'autre jour, j'ai créé un algorithme.
 C'est une fonction O (N) qui accepte une liste qui ne se soucie pas du type d'élément, traite la liste et retourne une autre liste contenant les résultats de l'opération.


#### **`Something.java`**
```java

  private static List<Object> doSomething(List<Object> list) {

    List<Object> result = new ArrayList<>();

    //En traitement

    return result;
  }

Mais

Something.java


  public static void main(String[] args) {
   List<String> strListA = Arrays.asList("c", "a", "b", "b", "c", "a", "d", "b"); 
  
   List<Object> strListB = Arrays.asList("c", "a", "b", "b", "c", "a", "d", "b");

   // List<Object>Pas de liste<String>Erreur de compilation à passer
   doSomething(strListA).forEach(System.out::print);
   
   doSomething(strListB).forEach(System.out::print);
  }

Je n'ai pas aimé le fait que tous les paramètres de type de liste passés aux paramètres soient limités au type d'objet. Par exemple, si vous ajoutez une méthode qui génère une liste qui n'accepte que des nombres et que vous souhaitez la passer en paramètre, c'est un peu gênant.

Something.java


  private static List<Number> makeNumberList(Number...nums) {
    List<Number> list = new ArrayList<>();
    for (Number num : nums) list.add(num);
    return list;
  }

Something.java


  public static void main(String[] args) {
   doSomething(makeNumberList(1, 2, 3, 4, 1)).forEach(System.out::print); //Erreur de compilation
  }

Alors changez <Objet> '' en <T> ''. ~~ Ajout d'un jeton de type afin que le type puisse être vérifié au moment de la compilation. ~~

Remarques (ci-dessus, ligne d'annulation)

//Classe littérale Kral vers méthodeEn passant doSomething(List list, Class type)

//Il est possible de transmettre des informations de type lors de l'exécution doSomething(someList, Integer.class)

 J'essayais de le compiler uniquement lorsque le paramètre de type et le jeton de type correspondent, mais je l'ai mis en attente car l'utilisation du type dans la méthode a été perdue lors du processus de modification.



#### **`Something.java`**
```java

  private static <T> List<T> doSomething(List<T> list) {
    
    List<T> result = new ArrayList<>();
    
    //En traitement
    
    return result;
  }

Essayez d'inclure le type de nombre et ses types subordonnés dans la méthode qui crée la liste de types de nombre ...

Something.java


  private static <T extends Number> List<T> makeNumberList(T...args) {
    List<T> list = new ArrayList<>();
    for (T arg : args) list.add(arg);
    return list;
  }

Something.java


  public static void main(String[] args) {
    List<Integer> someList = makeNumberList(5, 1, 2, 3, 3, 4, 3, 1, 2, 4, 5);
    doSomething(someList).forEach(System.out::print);
  }

Cela vous permet de passer une liste autre que `` List '' en tant que paramètre.

La fin

Pour une raison quelconque, je m'inquiétais des génériques. D'une manière étrange, je m'inquiétais de quelque chose comme "un outil magique flexible et sûr pour le type qui est soudainement tombé dans un monde qui était sûr du type mais pas si sûr" (que dites-vous). C'est possible.

En écrivant moi-même, il y avait beaucoup de choses comme celle-ci ambiguë, ou je ne le savais pas, alors faites-le moi savoir dès que vous trouvez des erreurs.

référence

Java 2e édition efficace Oracle Java docs

  • https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.2
  • https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html#package.description

c'est tout

Recommended Posts