Recommandé (gratuit) : Tutoriel Java Basic
La réflexion est une technique avancée en Java et est largement utilisée dans divers projets open source. Par exemple, Spring, Tomcat, Jetty et d'autres projets utilisent tous largement la réflexion.
En tant que programmeurs Java, si nous utilisons bien la réflexion, nous pouvons non seulement améliorer notre niveau technique, mais aussi développer de meilleurs projets.
Cependant, même si de nombreuses personnes ont entendu parler de la réflexion, ils ne savent pas où elle doit être utilisée.
Alors, commençons par le travail réel et utilisons la réflexion pour convertir l'objet en structure de données de MongoDb. Après avoir compris cet exemple, vous comprendrez comment la réflexion est utilisée.
Dans le système de commerce électronique, certaines données doivent être enregistrées dans MongoDb pour améliorer les performances des requêtes. Mais avant cela, nous devons d'abord convertir les données en structure MongoDb, c'est-à-dire convertir les objets Java en documents.
Par exemple, si les informations de commande doivent être stockées dans MongoDb, l'objet de commande doit être converti en document.
Mais de cette façon, chaque classe d'entité doit développer une méthode 2Doc(). Cette méthode n'a aucun contenu technique, elle place simplement différents champs dans le document. Et une fois qu'il y a trop de champs, vous écrirez du mauvais code si vous ne faites pas attention. Vous pouvez le sentir.
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:订单转doc public Document order2Doc(Order order) { Document doc = new Document(); doc.put("id", order.getId()); doc.put("userId", order.getUserId()); doc.put("orderNo", order.getOrderNo()); doc.put("amount", order.getAmount()); doc.put("createTime", order.getCreateTime()); doc.put("updateTime", order.getUpdateTime()); // 省略无数put... return doc; } }
De plus, nous devons récupérer les données de MongoDb et reconvertir le document en objet Java. Vous pouvez le ressentir à nouveau.
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:doc转订单 public Order doc2Order(Document doc) { Order order = new Order(); order.setId((Long) doc.get("id")); order.setUserId((Long) doc.get("userId")); order.setOrderNo((String) doc.get("orderNo")); order.setAmount((BigDecimal) doc.get("amount")); order.setCreateTime((String) doc.get("createTime")); order.setUpdateTime((String) doc.get("updateTime")); // 省略无数set... return order; } }
Une seule classe de commande est si gênante, sans compter qu'il existe plusieurs classes de ce type, et les projets ont toujours de nouvelles exigences. Si un champ est modifié, vous aurez de gros problèmes, et vous pourriez en avoir. pour retourner l'ensemble du projet à nouveau.
Par conséquent, afin de réduire les erreurs, ces deux méthodes de conversion doivent être optimisées, et cette optimisation utilise deux fonctionnalités avancées de Java : la réflexion et les génériques. Afin de donner à chacun une compréhension plus intuitive, je vais le diviser en deux itérations de version.
La première version utilise la réflexion pour simplifier la méthode de conversion des classes d'entités ;La deuxième version utilise des génériques et la réflexion pour extraire les classes d'outils MongoDb
Ensuite, passons à l'étape ; par étape~
Dans la première version de l'itération, nous simplifierons les deux méthodes de conversion des classes d'entités.
Commençons par convertir un objet Java en document, en prenant encore une fois la classe Order comme exemple.
D'abord, on obtient toutes les informations des champs de la classe de commande par réflexion ; puis, on utilise une boucle pour parcourir ces champs ; enfin, dans la boucle, on libère les droits d'accès des champs et on met les champs ; dans le Document.
public class Order { // ...省略无数字段 public Document order2Doc(Order order) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = order.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(order)); } return doc; } }
Vous pouvez voir qu'après la transformation par réflexion, le code est beaucoup plus simple. Peu importe le nombre de champs d’un objet ou le nombre d’opérations de mise à écrire, cela peut être fait avec seulement ces quelques lignes de code. La conversion d'objets Java en structures MongoDb semble moins lourde.
En suivant cette idée, transformons la deuxième méthode, convertissons le document en objet Java.
public class Order { // ...省略无数字段 public Order doc2Order(Document doc) throws Exception { Order order = new Order(); for (String key : doc.keySet()) { // 获取字段 Field field = order.getClass().getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(order, doc.get(key)); } return order; } }
D'abord, on utilise une boucle pour parcourir le Document ; dans la boucle, on utilise la réflexion pour obtenir les champs correspondants, puis on libère les droits d'accès des champs, et on fixe la valeur du Document aux champs de l'objet.
À ce stade, nous avons utilisé la réflexion pour simplifier la méthode de conversion des deux classes d'entités, et la première version de l'itération est pratiquement terminée. Le travail restant consiste à copier, coller et remodeler chaque classe.
Cependant, après cette itération, même si beaucoup de travail a été réduit, il reste encore de nombreux endroits déraisonnables.
Tout d’abord, il y a encore beaucoup de code en double. Chaque classe d'entité dispose de deux méthodes de conversion, mais la logique de base de ces deux méthodes est la même, il n'est donc pas nécessaire de les copier partout.
Ensuite, ce n'est pas une fonction que les classes d'entités devraient entreprendre. Les classes d'entités sont uniquement responsables de la conservation temporaire des données et ne sont responsables d'aucune fonction de persistance. L'endroit où vous stockez les données et la structure de données dans laquelle elles doivent être converties n'ont rien à voir avec les classes d'entités.
Autrement dit, il faut faire une deuxième itération.
Pour faire simple, les génériques sont un style ou un paradigme. Vous n'avez pas besoin de spécifier le type de paramètre spécifique au début, mais utilisez. Déterminez ensuite le type de paramètre.
Si vous combinez génériques et réflexion, cela peut nous aider à réduire beaucoup de code en double.
Voyons, comment faire la deuxième itération ?
Commencez par convertir les objets Java en documents. Nous déclarons d'abord une méthode générique ; puis, par réflexion, obtenons toutes les informations sur les champs de la classe générique, puis utilisons une boucle pour parcourir ces champs et enfin, dans la boucle, mettons les champs dans le document ;
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数时,指定一个泛型参数 public static <T> Document obj2Doc(T obj) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(obj)); } return doc; } }
Après l'ajout de génériques, le code en double a été considérablement réduit et les classes d'entités n'ont plus besoin d'écrire des méthodes 2Doc()
distinctes. Lorsque vous l'utilisez, appelez simplement MongoDbUtils.obj2Doc()
.
En suivant la même idée, nous continuons à transformer la deuxième méthode, convertir un document en objet Java.
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数必须是 Class,但这个 Class 是泛型参数,不限制类型 public static <T> T doc2Obj(Document doc, Class<T> clazz) throws Exception { // 实例化泛型对象 T obj = clazz.newInstance(); for (String key : doc.keySet()) { // 获取字段 Field field = clazz.getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(obj, doc.get(key)); } return obj; } }
首先,我们定义实例化一个泛型对象;然后,我们使用循环遍历 Document;最后,在循环中,使用反射获取相应的字段,把 Document 的值设置到泛型对象的字段里。
第二版的迭代就基本完成了。我们在第一版迭代的基础上,加入了泛型,得到了一个工具类 MongoDbUtils
,这个工具类得到结果和以前完全一样,你可以看下测试代码。
public static void main(String[] args) throws Exception { Order order = new Order(); order.setId(0L); order.setUserId(0L); order.setOrderNo("1"); order.setAmount(new BigDecimal("0")); order.setCreateTime("2"); order.setUpdateTime("3"); System.out.println("原始数据:" + order); Document document = MongoDbUtils.obj2Doc(order); System.out.println("转换doc数据:" + document); Order order1 = MongoDbUtils.doc2Obj(document, Order.class); System.out.println("转换java数据:" + order1); } 运行结果: 原始数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3) 转换doc数据:Document{{id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3}} 转换java数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3)
这样一来,我们就不用保留实体类上的转换方法了,剩下的工作就是删代码。
MongoDb 和 Java 对象的互相转换就完成了。我们做了两次迭代,第一次迭代利用了反射,把大量手动 set/get 操作给去掉了;第二次迭代在原来的基础上,加入了泛型的应用,又去掉了一堆重复代码。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!