泛型Genericity

简介
泛型Genericity是程序语言的一种特性(不单是java中独有)。是指在强类型程序设计语言(例如:java)中,允许程序员在写程序时写一些可变部分,但是在使用时,必须明确类型。这么做可以提高代码复用性,从而提高开发效率。
类泛型实战
简单用法

package com.aaa.genericity.class1;

import java.util.Date;

/**
 * @FileName: Person
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/20 15:12
 * @Version: 1.0.0
 */
//<A> 可以是任意字符,但必须大写,只起到占位符的作用   泛指任意类型
// 类型如果是基本数据类型,必须是封装类(不能写int,需要写Integer)
public class Person <A>{
    //写程序时,不确定A是什么类型
    private  A name;

   /* private String name;
    private Date name;
    private Integer name;*/


    public void printName() {
        System.out.println(name);
    }

    public Person(A name) {
        this.name = name;
    }

    public A getName() {
        return name;
    }

    public void setName(A name) {
        this.name = name;
    }
}

复杂用法
泛型类

package com.aaa.genericity.class2;

/**
 * @FileName: Person
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 8:54
 * @Version: 1.0.0
 */
public class Person <A,B,C,D,E>{

    private A a;
    private B b;
    private C c;
    private D d;
    private E e;


    /**
     * 打印信息
     */
    public void printMsg(){
        System.out.println(a+" "+b+" "+c+" "+d+" "+e);
    }

    public Person(A a, B b, C c, D d, E e) {
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a= a;
    }

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public C getC() {
        return c;
    }

    public void setC(C c) {
        this.c = c;
    }

    public D getD() {
        return d;
    }

    public void setD(D d) {
        this.d = d;
    }

    public E getE() {
        return e;
    }

    public void setE(E e) {
        this.e = e;
    }
}

测试

package com.aaa.genericity.class2;

import com.aaa.genericity.entity.Dept;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 8:57
 * @Version: 1.0.0
 */
public class Test {
    public static void main(String[] args) {
        // 泛型类
        //Integer=int    Character=char
        Person<String,Integer,Double,Boolean,Character> person = new Person<>("aaa", 1, 2.2, true, 'a');
        person.printMsg();
        //在使用float或者short的时候,需要使用包装类     后面填充值时,注意一定是float和short类型
        Person<Long, Dept,Double,Float,Short> person1 = new Person<>(11l, new Dept(), 2.2, 2.2f, Short.valueOf("1"));
        person1.printMsg();
    }
}

方法泛型实战
需求
把一个整型数组转换了list
实战
方法泛型代码

package com.aaa.genericity.method;

import java.util.ArrayList;
import java.util.List;

/**
 * @FileName: ProjectUtil
 * @Description: 为项目提供很多通用方法   //Hutools 工具类
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:07
 * @Version: 1.0.0
 */
public class ProjectUtil {


    /**
     * 通用的数组转List方法
     * @param tArray
     * @return
     * @param <T>
     */
    //<T> 定义后面集合或者参数中使用的泛型的标识
    public  static <T> List<T> arrayToList(T[] tArray){
        //判断数组是否为空
        if(tArray==null||tArray.length==0){
            return null;
        }
        //定义返回集合
        List<T> tList = new ArrayList<>();
        //循环遍历数组,将数组中的元素添加到list中    
        for (T t : tArray) {
            tList.add(t);
        }
        return tList;
    }

    //后面还有其他方法
}

测试

package com.aaa.genericity.method;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:12
 * @Version: 1.0.0
 */
public class Test {
    public static void main(String[] args) {
        Integer[] integerArray = {1,2,3,4,5};
        List<Integer> integerList = ProjectUtil.arrayToList(integerArray);
        System.out.println(integerList);

        String[] stringArray = {"a","b","c","d","e"};
        List<String> stringList = ProjectUtil.arrayToList(stringArray);
        System.out.println(stringList);


        Date date = new Date();
        // 获取时间戳  从1970年到现在的毫秒数
        long time = date.getTime();
        Date date1 = new Date(time + 1000);
        Date date2 = new Date(time + 2000);
        Date[] dateArray = {date,date1,date2};
        /*List<Date> dateList1 = Arrays.asList(dateArray);
        System.out.println(dateList1);*/
        List<Date> dateList = ProjectUtil.arrayToList(dateArray);
        System.out.println(dateList);
    }
}

泛型?的用法
注意事项
?和T有啥区别:?代表未知类型,不能用于类泛型或者方法泛型,只能在参数或者返回值中使用。T代表一种类型,可以任意地方使用。

用法
需求
遍历并打印集合
代码

package com.aaa.genericity.wh;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @FileName: PrintList
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:35
 * @Version: 1.0.0
 */
//public class PrintList<?> { //不能用于类泛型
public class PrintList {

    //泛型方法  ?不可用
    /*public <?> void printList1(List<?> list){
        System.out.println("打印集合元素");
    }*/
    public void  printList(List<?> list){
        System.out.println("打印集合元素");
        if(list!=null&&list.size()>0) {
            for (Object o : list) {
                System.out.println(o);
            }
        }else {
            System.out.println("集合为空!");
        }
    }

    public static void main(String[] args) {
        PrintList printList = new PrintList();
        List<String> list = Arrays.asList("aaa","bbb","ccc");
        printList.printList(list);

        List<Integer> integerList =new ArrayList<>();
        integerList.add(11);
        integerList.add(22);
        integerList.add(33);
        integerList.add(44);
        printList.printList(integerList);

    }
}

泛型?在继承中的用法
上界通配符
语法:List<? extends T>:代表T本身或者T的子孙类
下界通配符
语法:List<? super T>:代表T本身或者T的父类
实战
需求
某主人喂养一群宠物,宠物之间有继承关系
代码
编写宠物类,并有继承关系
大猫

package com.aaa.genericity.wh1;

/**
 * @FileName: BigCat
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:55
 * @Version: 1.0.0
 */
public class BigCat {

    /**
     * 吃方法
     */
    public void eat(){
        System.out.println("大猫吃大鱼");
    }
}

中猫

package com.aaa.genericity.wh1;

/**
 * @FileName: BigCat
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:55
 * @Version: 1.0.0
 */
public class MediumCat extends BigCat{

    /**
     * 吃方法
     */
    public void eat(){
        System.out.println("中猫吃中鱼");
    }
}

小猫

package com.aaa.genericity.wh1;

/**
 * @FileName: BigCat
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:55
 * @Version: 1.0.0
 */
public class SmallCat extends MediumCat{

    /**
     * 吃方法
     */
    public void eat(){
        System.out.println("小猫吃小鱼");
    }
}

小小猫

package com.aaa.genericity.wh1;

/**
 * @FileName: BigCat
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:55
 * @Version: 1.0.0
 */
public class TinyCat extends SmallCat{

    /**
     * 吃方法
     */
    public void eat(){
        System.out.println("小小猫吃小小鱼");
    }
}

编写主人类,编写喂养方法

package com.aaa.genericity.wh1;

import java.util.List;

/**
 * @FileName: Master
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 9:59
 * @Version: 1.0.0
 */
public class Master {
      //主人名字
      private  String name;

    public Master(String name) {
        this.name = name;
    }

    /**
     * 喂养宠物
     * @param catList
     */
    //上界通配符例子
    //public  void  feed(List<? extends MediumCat> catList){
    //下界通配符例子
    public  void  feed(List<? super MediumCat> catList){
        System.out.println("主人" + name + "开始喂养宠物!");
        if(catList!=null&&catList.size()>0){
            for (Object o : catList) {
                //因为BigCat的父类是Object 所以这里需要强转
               BigCat bigCat =  (BigCat)o;
               bigCat.eat();
            }
        }
    }
}

测试

package com.aaa.genericity.wh1;

import java.util.ArrayList;
import java.util.List;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 10:02
 * @Version: 1.0.0
 */
public class Test {
    public static void main(String[] args) {
        //实例化主任类
        Master master = new Master("华安");
        //实例化大猫集合
        List<BigCat> bigCatList =new ArrayList<>();
        //实例化大猫
        BigCat bigCat1 = new BigCat();
        BigCat bigCat2 = new BigCat();
        BigCat bigCat3 = new BigCat();
        bigCatList.add(bigCat1);
        bigCatList.add(bigCat2);
        bigCatList.add(bigCat3);
        //喂养
        master.feed(bigCatList);

        //实例化中猫集合
        List<MediumCat> mediumCatList =new ArrayList<>();
        //实例化中猫
        MediumCat mediumCat1 = new MediumCat();
        MediumCat mediumCat2 = new MediumCat();
        MediumCat mediumCat3 = new MediumCat();
        mediumCatList.add(mediumCat1);
        mediumCatList.add(mediumCat2);
        mediumCatList.add(mediumCat3);
        //喂养
        master.feed(mediumCatList);

        //实例化小猫集合
        List<SmallCat> smallCatList =new ArrayList<>();
        //实例化小猫
        SmallCat smallCat1 = new SmallCat();
        SmallCat smallCat2 = new SmallCat();
        SmallCat smallCat3 = new SmallCat();
        smallCatList.add(smallCat1);
        smallCatList.add(smallCat2);
        smallCatList.add(smallCat3);
        //喂养
        //master.feed(smallCatList);

        //实例化小小猫集合
        List<TinyCat> tinyCatList =new ArrayList<>();
        //实例化小小猫
        TinyCat tinyCat1 = new TinyCat();
        TinyCat tinyCat2 = new TinyCat();
        TinyCat tinyCat3 = new TinyCat();
        tinyCatList.add(tinyCat1);
        tinyCatList.add(tinyCat2);
        tinyCatList.add(tinyCat3);
        //喂养
        //master.feed(tinyCatList);
    }
}

测试结论:上界能喂养中猫,小猫和小小猫;
下界能喂养大猫,中猫。

综合实战
需求
学习了反射,注解和泛型,拿三个技术编写一个类ORM(对象关系映射)框架(ORM框架的代表hibernate和mybatis,mybatis-plus)。模仿和hirbernate和mybatis-plus很类似!
例如:根据Dept查询 List ,根据传入参数dept对象中的属性值动态拼接sql
Dept dept =new Dept();
dept.setDeptNo(101) 查询时,查询编号为101的部门
dept.setDeptName("开") 查询时,查询名字中含有开的
或者 dept.setDeptName("开,部") 查询时,会查询部门名称中含有开或者部
条件没有就查询全部
并返回List。 List 可以是任意表的数据。
准备工作
数据库使用:db_qy178
** 项目中加入mysql的驱动jar包**

 <dependencies>
        <!--masql驱动包-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.32</version>
        </dependency>
    </dependencies>

编写自定义注解

package com.aaa.demo.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @FileName: Table
 * @Description:ORM的接口上使用的的注解
 * @Author: zhz
 * @CreateTime: 2024/11/21 10:59
 * @Version: 1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

    //库名称
    String dbName() default "mysql";
    //表名
    String tableName() default "user";
}

package com.aaa.demo.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @FileName: Column
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 11:01
 * @Version: 1.0.0
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    //数据库的列名称
    String name() default "";
}

编写实体类

package com.aaa.demo.entity;

import com.aaa.demo.anno.Column;
import com.aaa.demo.anno.Table;

/**
 * @FileName: Dept
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 11:04
 * @Version: 1.0.0
 */
@Table(dbName = "db_qy178", tableName = "tb_dept")
public class Dept {

    @Column(columnName = "dept_no")
    private Integer deptNo;
    @Column(columnName = "dept_name")
    private String deptName;
    @Column(columnName = "loc")
    private String loc;


    public Integer getDeptNo() {
        return deptNo;
    }

    public void setDeptNo(Integer deptNo) {
        this.deptNo = deptNo;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }
}

编写公共的DAO接口

package com.aaa.demo.dao;

import java.util.List;

/**
 * @FileName: PublicDao
 * @Description: 公共接口
 * @Author: zhz
 * @CreateTime: 2024/11/21 11:10
 * @Version: 1.0.0
 */
public interface PublicDao {

    /**
     * 通用查询接口
     * @param t  传入的任意类对象
     * @return  传入实体的结合
     * @param <T>
     */
    public <T>  List<T>  executeQuery(T t);
}

编写DAO实现类

package com.aaa.demo.dao.impl;

import com.aaa.demo.anno.Column;
import com.aaa.demo.anno.Table;
import com.aaa.demo.dao.PublicDao;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @FileName: PublicDaoImpl
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 11:13
 * @Version: 1.0.0
 */
public class PublicDaoImpl implements PublicDao {

    //定义常量   不再发生改变
    private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/db_qy178?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=Asia/Shanghai&allowPublicKeyRetrieval=true";
    private static final String USER_NAME = "root";
    private static final String PASSWORD = "root";

    /**
     * 封装获取Connection方法
     * @return
     */
    public static Connection getMyConnection()  {
        try {
            //加载驱动
            Class.forName(DRIVER_CLASS);
            //获取Connection并返回
            return  DriverManager.getConnection(URL, USER_NAME, PASSWORD);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //有任何异常,返回空
        return null;
    }
    /**
     * 统一关闭资源封装方法
     * 后打开的先关闭 ,每个都处理异常,上面的关闭失败不影响下面关闭
     * @param connection
     * @param statement
     * @param resultSet
     */
    public static  void closeAll(Connection connection, Statement statement, ResultSet resultSet){
        try {
            if(resultSet!=null){
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if(statement!=null){
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if(connection!=null){
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public <T> List<T> executeQuery(T t) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //假如要查询全部数据  根据传入的t对象(dept) 使用反射拿到库名,表名 就可以拼接查询全部的语句
            //获取t的class对象 (例如 dept的class对象)
            Class<?> clazz = t.getClass();
            //判断是否含有@Table注解
            if(clazz.isAnnotationPresent(Table.class)){
                //获取注解对象
                Table table = clazz.getAnnotation(Table.class);
                //获取库名和表名
                String dbName = table.dbName();
                String tableName = table.tableName();
                //拼接sql语句
                String sql = "select * from "+dbName+"."+tableName+" where 1=1 ";
                //判断传入的对象t的属性是否有值,如果有值,就拼接where条件
                StringBuilder executeSql = new StringBuilder(sql);
                //获取t的所有属性  //deptNo  deptName loc
                Field[] declaredFields = clazz.getDeclaredFields();
                //循环
                for (Field declaredField : declaredFields) {
                    //定义列名称
                    String columnName = "";
                    //判断属性是否含有@Column注解
                    if(declaredField.isAnnotationPresent(Column.class)){
                        //获取注解对象
                        Column column = declaredField.getAnnotation(Column.class);
                        //获取注解对象中的columnName
                        columnName = column.columnName();
                    }
                    //让私有属性可以访问
                    declaredField.setAccessible(true);
                    //获取属性值
                    Object fieldValue = declaredField.get(t);
                    //判断是否有值
                    if(fieldValue!=null){
                        //select  * from db_qy178.tb_dept where 1=1
                        //判断fieldValue是什么类型
                        if(fieldValue instanceof Integer){ //判断是否是整数类型
                            //拼接where条件
                            executeSql.append(" and "+columnName+" = "+fieldValue);
                        }else if (fieldValue instanceof String){//判断是否是字符串类型
                            String s = fieldValue.toString();
                            //判断字符串是否为空,如果为空,就忽略 不拼接 如果不空,就判断字符串中是否含有逗号
                            if (s.length()>0){
                                if(s.contains(",")) {
                                    //拼接开始括号
                                    executeSql.append(" and (");
                                    //分割字符串
                                    String[] sArray = s.split(",");
                                    //循环拼接
                                    for (String s1 : sArray) {
                                        executeSql.append(" "+columnName + " like '%" + s1 + "%' or");
                                    }
                                    //从字符串开始截取到长度-2
                                    String substring = executeSql.substring(0, executeSql.length() - 2);
                                    //重新拼接
                                    executeSql = new StringBuilder(substring);
                                    executeSql.append(")");
                                }else {
                                    executeSql.append(" and "+columnName+" like '%"+fieldValue+"%'");
                                }
                            }
                        }/*else if (fieldValue instanceof Double){//判断是否是浮点类型
                        }else if (fieldValue instanceof Date){
                        }*/
                    }
                }
                //拼接完了sql  执行sql
                System.out.println("要执行的sql为:"+executeSql);
                //获取Connection
                 connection = getMyConnection();
                //获取执行sql对象
                 preparedStatement = connection.prepareStatement(executeSql.toString());
                //执行sql
                 resultSet = preparedStatement.executeQuery();
                //获取元数据信息
                ResultSetMetaData metaData = preparedStatement.getMetaData();
                //获取列数
                int columnCount = metaData.getColumnCount();
                //定义返回结果
                List<T> tList =new ArrayList<>();
                //定义泛型对象
                T t1 = null;
                //遍历结果
                while (resultSet.next()){
                    //实例化一个新的
                    t1 = (T) clazz.newInstance();
                    for (int i = 1; i <= columnCount; i++) {
                         //获取列名  select dept_no,dept_name,loc from tb_dept
                        String columnName = metaData.getColumnName(i);
                        //获取属性名  dept_no->deptNo
                        String fieldName = stringFirstLetterToUpperCase(columnName);
                        //获取列对象
                        Field declaredField = clazz.getDeclaredField(fieldName);
                        //让私有属性可以访问
                        declaredField.setAccessible(true);
                        //反射给列赋值
                        declaredField.set(t1,resultSet.getObject(columnName));
                    }
                    //添加到集合
                    tList.add(t1);
                }
                return tList;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeAll(connection,preparedStatement,resultSet);
        }
        return null;
    }

    /**
     * 字符串转换
     * @param columnName user_name_aaa_bbb
     * @return  userNameAaaBbb
     */
    public static String stringFirstLetterToUpperCase(String columnName) {
        //判断columnName是否含有_
        //没有直接返回
        if(!columnName.contains("_")){
            return columnName;
        }
        //存在就转换  user_name_aaa_bbb=["user","name","aaa","bbb"]
        String[] columnNameArray = columnName.split("_");
        //拼接字符串  stringBuilder="user"
        StringBuilder stringBuilder =new StringBuilder(columnNameArray[0]);
        for (int i = 1; i < columnNameArray.length; i++) {
            //第1次  columnNameArray[1]=name
            //第2次  columnNameArray[2]=aaa
            //第3次  columnNameArray[2]=bbb
            //...
            String newString  = columnNameArray[i].substring(0,1).toUpperCase()+columnNameArray[i].substring(1);
            stringBuilder.append(newString);
        }
        return  stringBuilder.toString();
    }
    public static void main(String[] args) {
        String executeSql="select * from tb_dept where 1=1 and ( dept_name like '%开%' or dept_name like '%部%' or";
        String substring = executeSql.substring(0,executeSql.length() - 2);
        System.out.println(substring);
    }
}

测试

package com.aaa.demo.test;

import com.aaa.demo.dao.PublicDao;
import com.aaa.demo.dao.impl.PublicDaoImpl;
import com.aaa.demo.entity.Dept;

import java.util.List;

/**
 * @FileName: PublicDaoTest
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/21 12:00
 * @Version: 1.0.0
 */
public class PublicDaoTest {
    public static void main(String[] args) {
        //实例化dao
        PublicDao publicDao =new PublicDaoImpl();
        //实例化参数
        Dept dept =new Dept();
        //dept.setDeptNo(11);
        //dept.setDeptName("开,部");
        dept.setDeptName("开");
        //执行
        List<Dept> deptList = publicDao.executeQuery(dept);
        System.out.println(deptList);
    }
}

posted on 2024-12-29 16:03  小木不痞  阅读(37)  评论(0)    收藏  举报

导航