Génériques Java (y compris les applications de génériques + réflexion)

Introduction aux génériques

Java generics ( generics) est une nouvelle fonctionnalité introduite dans JDK 5. Les génériques fournissent un 编译时类型安全检测机制mécanisme qui permet aux programmeurs de détecter les types illégaux au moment de la compilation.

L'essence des génériques est 参数化类型que le type de données manipulées est spécifié comme un 参数. Le type spécifique n'est spécifié que lorsque l'objet est créé ou que la méthode est appelée.

Effacement de type

La première condition préalable à une compréhension correcte des concepts génériques est la compréhension 类型擦除.

Pour plus d'informations sur l'effacement de type, vous pouvez consulter cet article: «L'effacement de type générique Java et les problèmes causés par l'effacement de type»

Qu'est-ce que c'est 类型擦除?

Le type générique de 伪泛型Java est dû au fait que toutes les informations génériques seront effacées lors de la compilation Java. Les génériques de Java sont essentiellement implémentés au niveau du compilateur, et le bytecode généré ne contient pas les informations de type dans les génériques.

  • Lorsque vous utilisez des génériques, ajoutez des paramètres de type et les paramètres seront supprimés lors de la compilation du compilateur. Ce processus est appelé 类型擦除.

Par exemple List<String>, les types définis dans le code deviendront après compilation. ListLes informations de type attachées par le type générique sont invisibles pour la JVM. La JVM ne voit que la liste. Le compilateur Java trouvera autant que possible les erreurs possibles au moment de la compilation, mais il est toujours incapable de générer des exceptions de conversion de type au moment de l'exécution. L'effacement de type est également 模板机制une différence importante entre les génériques de Java et l' implémentation C ++ .

Caractère générique

Pour plus d'informations sur les jokers dans les génériques Java, vous pouvez consulter cet article: "Parlons des jokers T, E, K, V, dans les génériques Java ?

Les jokers couramment utilisés sont: T, E, K, V ,?

  • ? Représente un type Java incertain
  • T Représente un type Java spécifique (Type)
  • K, VReprésentent respectivement la valeur clé dans la valeur clé Java
  • E Représente l'élément

Trois façons d'utiliser les génériques

Les médicaments génériques sont généralement trois 泛型类façons: 泛型接口, 泛型方法,.

Classe générique

Cela Tpeut être écrit comme n'importe quel identificateur. Des paramètres communs tels que T, E, K et V sont souvent utilisés pour représenter des génériques.

Lors de l'instanciation d'une classe générique, vous devez spécifier le type spécifique de T.

public class Generic<T>{
    
     

    private T key;

    public Generic(T key) {
    
     
        this.key = key;
    }

    public T getKey(){
    
     
        return key;
    }
}

Instanciez la classe générique:

Generic<Integer> genericInteger = new Generic<Integer>(123456);

Interface générique

public interface Generator<T> {
    
    
    public T method();
}
  1. Implémentez une interface générique sans spécifier le type:
class GeneratorImpl<T> implements Generator<T>{
    
    
    @Override
    public T method() {
    
    
        return null;
    }
}
  1. Implémentez une interface générique, spécifiez le type:
class GeneratorImpl<T> implements Generator<String>{
    
    
    @Override
    public String method() {
    
    
        return "hello";
    }
}

Méthode générique

public static <E> void printArray(E[] inputArray){
    
             
    for(E element : inputArray){
    
            
      	System.out.printf( "%s ", element );
    }
    System.out.println();
}

utilisation:

// 创建不同类型数组: Integer, Double 和 Character
Integer[] intArray = {
    
     1, 2, 3 };
String[] stringArray = {
    
     "Hello", "World" };
printArray(intArray); 
printArray(stringArray); 

Avantages des génériques

Les avantages de l'utilisation de génériques sont:

  1. Le code est plus concis, pas besoin de forcer la conversion de type

  2. Le programme est plus robuste, il n'y a aucun avertissement lors de la compilation, et aucune ClassCastExceptionexception lors de l'exécution

  3. Améliorez la réutilisabilité du code, par exemple: dans un proxy dynamique, les génériques peuvent proxy toute classe qui doit être proxy

public class ServiceProxy<T> implements InvocationHandler {
    
    
  	private T target;
  	public ServiceProxy(T target) {
    
    
        this.target = target;
    }
}

Application générique

  1. Lors de l'exploitation d'une collection

La raison pour laquelle divers types d'objets peuvent être stockés dans le conteneur est à cause de l'introduction de génériques

List lists = new ArrayList<String>();
  1. Lorsqu'il est utilisé dans les composants de base

Parce que l'exigence des composants est d'atteindre un certain degré de polyvalence et de prendre en charge différents types, et la caractéristique des génériques est que les types spécifiques ne sont clarifiés que lors de la création d'objets ou de l'appel de méthodes. Peut se référer SpringData JPAau JpaRepositorylibellé:

public interface JpaRepository<T, ID> extends 
  PagingAndSortingRepository<T, ID>, QueryExampleExecutor<T> {
    
    
  	List<T> findAll();
  	List<T> findAll(Sort sort);
  	List<T> findAllById(Iterable<ID> ids);
  	<S extends T> List<S> saveAll(Iterable<S> entities);
  	void flush();
   	<S extends T> S saveAndFlush(S entity);
   	void deleteInBatch(Iterable<T> entities);
   	void deleteAllInBatch();
   	T getOne(ID id);
  
   	@Override
   	<S extends T> List<S> findAll(Example<S> example);
  
   	@Override
   	<S extends T> List<S> findAll(Example<S> example, Sort sort);
}

De plus, dans le composant, il est également indissociable de Java 反射机制, généralement反射+泛型

Donnez un autre exemple pratique

Par exemple, il est nécessaire d'agréger certains champs de certaines tables de base de données. L'instruction SQL est

select sum(column1),sum(column2) from table group by field1,field2

Les besoins sumet les group bycolonnes sont transmis par la propre entreprise de la partie, tandis que la table SQL est en fait notre champ POJO, POJO entrant et attribue certainement une seule entreprise peut réellement écrire POJO mort sur les paramètres, mais si le paramètre est défini sur générique, vous pouvez améliorer la réutilisabilité du code.

Après avoir obtenu le paramètre, obtenez la valeur spécifique de son champ par réflexion, et vous pouvez faire l'accumulation. Des exemples de code spécifiques sont les suivants:

// 传入需要 group by 和 sum 的字段名
public cacheMap(List<String> groupByKeys, List<String> sumValues) {
    
    
  	this.groupByKeys = groupByKeys;
  	this.sumValues = sumValues;
}

private void excute(T e) {
    
    
  
    // 从pojo 取出需要group by 的字段 list
    List<Object> key = buildPrimaryKey(e);

    // primaryMap 是存储结果的Map
    T value = primaryMap.get(key);

    // 如果从存储结果找到有相应记录
    if (value != null) {
    
    
        for (String elem : sumValues) {
    
    
          // 反射获取对应的字段,做累加处理
            Field field = getDeclaredField(elem, e);
            if (field.get(e) instanceof Integer) {
    
    
                field.set(value, (Integer) field.get(e) + (Integer) field.get(value));
            } else if (field.get(e) instanceof Long) {
    
    
                field.set(value, (Long) field.get(e) + (Long) field.get(value));
            } else {
    
    
                throw new RuntimeException("类型异常,请处理异常");
            }
      	}
        // 处理时间记录
        Field field = getDeclaredField("updated", value);
        if (null != field) {
    
    
            field.set(value, DateTimeUtils.getCurrentTime());
        }
    } else {
    
    
      	// group by 字段 第一次进来
        try {
    
    
            primaryMap.put(key, Tclone(e));
            createdMap.put(key, DateTimeUtils.getCurrentTime());
        }catch (Exception ex) {
    
    
         	 	log.info("first put value error {}" , e);
        }
    }
}

Référence: https://mp.weixin.qq.com/s/fL6cMjSNAX_fZ7wFBJO80Q

Je suppose que tu aimes

Origine blog.csdn.net/weixin_44471490/article/details/111658775
conseillé
Classement