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. spring中classpath

    http://blog.csdn.net/wlwlwlwl015/article/details/48134763 Maven 项目的 classpath 理解 applicationContext. ...

  2. 使用Java API方式连接HDFS Client测试

    IDEA中新建Maven工程,添加POM依赖, 在IDE的提示中, 点击 Import Changes 等待自动下载完成相关的依赖包. <?xml version="1.0" ...

  3. 创建一个vue 项目 必备的几个插件

    第一步npm安装 首先:先从nodejs.org中下载nodejs 打开控制命令行程序(CMD),node -v 检查是否正常 使用淘宝NPM 镜像 npm  install  -g  cnpm  - ...

  4. ios MQTT协议的实际应用

    1,创建单视图项目,pod search mqtt找到一个库,然后在项目目录下pod init 出Podfile 2,pod install 安装mqtt库 3,主要代码: #import " ...

  5. 【leetcode】414. Third Maximum Number

    problem 414. Third Maximum Number solution 思路:用三个变量first, second, third来分别保存第一大.第二大和第三大的数,然后遍历数组. cl ...

  6. Deploy Descriptor

    之前我们在编写HelloWorld项目时,在WEB-INF目录下创建了一个web.xml文件.这个文件叫做部署描述文件,每个Servlet应用程序的部署描述文件的名称都是web.xml.Web容器在启 ...

  7. C# EasyHook MessageBox 示例(极简而全)

    完整代码,原创无藏私,绝对实用.Windows10 X64 下调试通过,对 w3wp.exe, sqlserver.exe,notepad.exe,iexporer.exe 注入后,长时间运行稳定,未 ...

  8. BSS, DATA, TEXT, HEAP, STACK

    BSS, block start segment, static memory, to store the global data which are not initialized. DATA, d ...

  9. java多线程同步器

    Java中多线程开发时,离不开线程的分工协作,常用的多线程的同步器有如下几种: 1.CountDownLatch 应用场景:等待一组线程任务完成后在继续执行当前线程. 用法:定义一个CountDown ...

  10. 兼容ie,火狐的判断回车键js脚本

    var event = window.event || arguments.callee.caller.arguments[0]; var keycode = event.keyCode || eve ...