JAVA 的泛型加大了 编程的灵活性,在配合上反射,可以让我们省去大量的重复代码,当你用 SpringBoot 整合 JPA 的时候

你会发现,你的 DAO 层只需要继承 BaseDao,在显示标明泛型的时候,你定义的接口就可以有一些常用的增删改查的方法

笔者也想实现的类似的功能,但是在使用泛型的时候发现 T.calss 的语法是不成立的,这涉及到JVM虚拟机对于泛型的擦除,

我们要怎么样拿到 T 这个泛型的字节码和实例呢?

1,其实 JDK 给我们提供了相应的方法如下:

Type type = this.getClass().getGenericSuperclass();
Type[] typeArr = ((ParameterizedType) type).getActualTypeArguments();
Class<T> mtClass = (Class<T>) (typeArr[0]);

2,以上代码我们就获得了 T 这个泛型在运行时的类型了,有了字节码,实例化,获取字段,获取注解什么的就不在话下了

3,需要注意的是,只有满足以下的申明方式,在父类 A 中才能正常使用以上方法

class A<T> {}

class B extends A<User>{}

5,这就导致我们对每个类进行操作是都需要创建一个对应的类来继承A类,好处就在于子类不需要写任何代码,

6,不知道 JDK 什么时候能实现 T.class 的功能就好了 (个人浅见)

《 二 》下面做一个简单的列子

1,声明两个注解 @KeyId  @TableName

package com.hwq.annotate;
import java.lang.annotation.*; @Documented // 是否出现在文档
@Target(ElementType.FIELD) // 作用范围,常用 FIELD 字段等上 TYPE 类上
@Retention(RetentionPolicy.RUNTIME) // 作用周期,一般为运行时
public @interface KeyID {
String value();
}
package com.hwq.annotate;
import java.lang.annotation.*; @Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
String value();
}

2,声明一个实体类,贴上自己写的注解,这里由于懒得写 get set 方法,笔者使用了 lombok 库

package com.hwq.reflex;

import com.hwq.annotate.KeyID;
import com.hwq.annotate.TableName;
import lombok.Getter;
import lombok.Setter; @Getter
@Setter
@TableName("user")
public class User { @KeyID("ID")
Integer id;
String name;
Integer sex; }

3,写一个基础类,就是那个实现公共方法的类,我在里面写了几个拼接 增删改语句 的方法, 大家主要看 getTableInfo 这个核心方法

package com.hwq.reflex;

import com.hwq.annotate.KeyID;
import com.hwq.annotate.TableName; import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List; public class SqlHelper<T> { protected String tableName = null; // 表名
protected String id; // 主键在 实体类的 名称
protected String key; // 主键在 数据库的 名称
protected List<String> fieldList = new ArrayList<String>(); // 字段数据
Field[] fieldArr; // 反射出来的字段对象,在取值的时候有用 /**
* 获取泛型类的方法,由于 JAVA 虚拟机的泛型擦除机制,我们无法获取对应的实体类
* 该方法可以在子类明确表示实体类的情况下,获取到实体类注解以及字段
* @return
*/
private synchronized void getTableInfo() {
if (tableName == null) {
Type type = this.getClass().getGenericSuperclass();
Type[] typeArr = ((ParameterizedType) type).getActualTypeArguments();
Class<T> mtClass = (Class<T>) (typeArr[0]);
TableName table = (TableName) mtClass.getAnnotation(TableName.class); // 获取类上 @TableName 注解
tableName = table.value();
fieldArr = mtClass.getDeclaredFields();
List<String> keyList = new ArrayList<String>();
List<String> idList = new ArrayList<String>();
for (int i = 0; i < fieldArr.length; i++) {
fieldArr[i].setAccessible(true);
KeyID keyID = fieldArr[i].getAnnotation(KeyID.class); // 获取类字段上的 @KeyId 注解
if (keyID != null) {
key = keyID.value();
id = fieldArr[i].getName();
}
fieldList.add(fieldArr[i].getName()); // 获取类的所有字段
}
}
} /**
* 新增的方法
*/
public void save(T t) {
getTableInfo();
StringBuilder insertSql = new StringBuilder(192);
StringBuilder filedStr = new StringBuilder(64);
StringBuilder valueStr = new StringBuilder(64);
insertSql.append("INSERT INTO ");
insertSql.append(tableName);
filedStr.append(" (");
valueStr.append(" VALUE (");
try {
for (int i = 0; i < fieldList.size(); i++) {
String field = fieldList.get(i);
if (field == id) continue;
filedStr.append(field);
filedStr.append(",");
valueStr.append("'");
valueStr.append(fieldArr[i].get(t));
valueStr.append("',");
}
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage());
}
insertSql.append(filedStr.substring(0, filedStr.length() - 1));
insertSql.append(")");
insertSql.append(valueStr.substring(0 ,valueStr.length() - 1));
insertSql.append(")");
String sql = insertSql.toString();
System.out.println(insertSql.toString()); } /**
* 编辑的方法,根据主键编辑
*/
public void edit(T t) {
getTableInfo();
StringBuilder updateSql = new StringBuilder(192);
updateSql.append("UPDATE ");
updateSql.append(tableName);
updateSql.append(" SET ");
int count = 0;
String idValue = null;
try {
for (int i = 0; i < fieldList.size(); i++) {
Object value = fieldArr[i].get(t);
if (value == null) continue;
String field = fieldList.get(i);
if (field == id) {
idValue = value.toString();
} else {
updateSql.append(field);
updateSql.append("='");
updateSql.append(value);
updateSql.append("',");
count ++;
}
}
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage());
}
if (count == 0 || idValue == null) {
throw new RuntimeException("主键为空或实体类没有需要修改的字段");
}
String sql = updateSql.substring(0, updateSql.length() - 1);
sql += " WHERE " + key + "='" + idValue + "'";
System.out.println(sql); } /**
* 删除的方法,根据主键,单个删除
*/
public void removeById(int id) {
getTableInfo();
StringBuilder deleteSql = new StringBuilder(128);
deleteSql.append("DELETE FROM ");
deleteSql.append(tableName);
deleteSql.append(" WHERE ");
deleteSql.append(key);
deleteSql.append("=");
deleteSql.append(id);
String sql = deleteSql.toString();
System.out.println(sql);
} }

4,写一个子类继承上面的类,子类不需要任何代码,记住一定要标明泛型的具体类型

package com.hwq.reflex;

public class Service extends SqlHelper<User> {

}

5,测试类

package com.hwq.reflex;

import java.lang.reflect.Field;

public class Index {

    public static void main(String[] args) {

        Service sqlHelper = new Service();  // 记住使用继承了基类的子类,不要直接使用基类

        User user = new User();
user.setId(1);
user.setName("张三");
user.setSex(1); sqlHelper.save(user);
sqlHelper.edit(user);
sqlHelper.removeById(12);
}
}

6,运行结果

JAVA 注解,泛型,反射获取泛型,并实例化的更多相关文章

  1. JAVA基础_反射获取泛型参数类型

    我经常会想获取参数的实际类型,在Hibernate中就利用的这一点. domain: Person.java public class Person { // 编号 private Long id; ...

  2. Java注解和反射笔记

    Java注解和反射笔记 1 注解 1.1 定义 Annotation是从JDK1.5开始引入的技术 作用 不是程序本身,可以对程序作出解释 可以被其他程序(编译器等)读取 格式 @注释名,可以添加一些 ...

  3. 小白都能学会的Java注解与反射机制

    前言 Java注解和反射是很基础的Java知识了,为何还要讲它呢?因为我在面试应聘者的过程中,发现不少面试者很少使用过注解和反射,甚至有人只能说出@Override这一个注解.我建议大家还是尽量能在开 ...

  4. Java注解与反射

    概要 本文主要是总结Java注解与反射的相关知识,加深自己对Java类动态语言的理解,同时为日后学习Spring打下基础. 注解: 什么是注解 Annotation的作用 不是程序本身,但是可以对程序 ...

  5. java中使用反射获取pojo(实体)类的全部字段值

    说起反射.不得不说它实在是太强大了,通过反射就能够轻轻松松拿到各种东东,假设你想在项目中解除对某个类的依赖,能够考虑用反射. 今天跟大家分享的是通过java中的反射,获取pojo类的全部字段值. 为什 ...

  6. Java实现通过反射获取指定类的所有信息

    package com.ljy; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.l ...

  7. java中使用反射获取pojo(实体)类的所有字段值

    出处:https://developer.aliyun.com/article/239346 说起反射,不得不说它实在是太强大了,通过反射就可以轻轻松松拿到各种东东,如果你想在项目中解除对某个类的依赖 ...

  8. 关于java反射获取泛型

    public class Test<T> { private final TypeToken<T> typeToken = new TypeToken<T>(get ...

  9. Java注解和反射

    1.注解(Annotation) 1.1.什么是注解(Annotation) 注解不是程序本身,可以在程序编译.类加载和运行时被读取,并执行相应的处理.注解的格式为"@注释名(参数值)&qu ...

随机推荐

  1. 开始一个django项目的流程

    1.明确开发站点的主题,(即此站点的作用), 确定站点的各种功能,需求. 2.优先设计数据库. 数据库的设计要合理,不能想当然的设计,最好能够以表格的形式展现出来,避免以后遗忘,也避免内容的重复. 3 ...

  2. 一个class标签里面有多个属性时的提取标签

    <div class="uibox-con carpic-list03 border-b-solid">   #即这个标签同时满足三个class:“uibox”.“ca ...

  3. ipa 注入 dylib

    前些日子再github找到了一个内存修改器 DLGMemor 免越狱在app内植入修改器,感觉很不错,就尝试去看看是否可行. 用到的工具:  Xcode 10. optool 首先要做的,安装 opt ...

  4. 支付宝电脑支付沙箱配置(JAVA)

    支付宝电脑支付API地址:https://docs.open.alipay.com/270/105899/.支付宝提供了沙箱环境提供测试,具体配置步骤如下 1.先下载测试DEMO工程 下载地址:htt ...

  5. 在 Linux 平台及 IPv4 环境中构建 IPv6局域网 测试环境

    在 Linux 平台及 IPv4 环境中构建 IPv6 测试环境 1 IPv6简介 IPv6(Internet Protocol Version 6)作为 IPv4 的升级版本,它是作为一共软件升级安 ...

  6. controller向layout传值

    Yii2,layout中使用Controller的值,Controller向layout传值的两种方式. yii2中在通过Controller向layout中传值,layout中访问Controlle ...

  7. vs+qt 运行过程出现cannot run rc.exe

    刚开始,我按照网上的一堆教程在qt creator中设置了各种东西,设置完以后,运行时出现cannot run rc.exe,根据百度,将C:\Program Files (x86)\Windows ...

  8. 工作中 sql 整理(一)

    这篇文章记录关于SQL的内容,有些凌乱,是工作中点滴的积累,只能按照时间顺序,逐次记录. 一.update 关联更新 1.需求 Table A   TableB A表中的主键和B表中的主键相关联,关联 ...

  9. 全志A33 lichee Linux内核原子操作(附实测代码)

    开发平台 * 芯灵思SinlinxA33开发板 淘宝店铺: https://sinlinx.taobao.com/ 嵌入式linux 开发板交流 QQ:641395230 原子操作是指不会被线程调度机 ...

  10. Ubuntu 下解压tar.xz方法

    参考地址:https://www.cnblogs.com/baby123/p/6611169.html