栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

泛型(Generic)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

泛型(Generic)

序言

说到Java泛型,大家应该都不陌生。常用于限制Java各种容器的数据类型。它是Java JDK 1.5后增加的特性,所以已经是一个比较老的特性了。这里写这篇文章主要目的是为了给大家复习泛型的知识点。

Java泛型(Generic) 介绍

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

作用

Java泛型的主要作用有:

  1. 类型安全:编译时强类型检查,编译器可以直接验证类型假设。
  2. 消除强制类型转换:消除代码中的许多强制类型转换,使得代码可读性更高,减少出错机会。
  3. 提高代码复用性:泛型可以避免一些有相同特性且重复的代码。

至于泛型是否会带来性能问题,这个说法不一。但泛型是一个编译时的功能,增强代码可读性、复用性的收益远大于泛型进行类型转换的影响。

应用场景 泛型类
package com.hust.zhang.generic;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
public class GenericClass {
    @Getter
    private T item;
}

定义一个Java泛型类,泛型类中的成员变量的类型可以通过类对象实例化时进行约束,测试如下,

public class GenericTest {
    public static void main(String[] args) {
        GenericClass generic1 = new GenericClass<>("item");
        GenericClass generic2 = new GenericClass<>(123L);
        System.out.println(generic1.getItem().getClass().getName());//java.lang.String
        System.out.println(generic2.getItem().getClass().getName());//java.lang.Long
    }
}
泛型接口

Java泛型接口和泛型类基本类似,用过Mybatis或者Mybaits-plus的同学应该都知道使用代码自动生成工具生成的Mapper文件里baseMapper就是一个泛型接口,我拿出来一个作为示例。

package com.baomidou.mybatisplus.core.mapper;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;

public interface baseMapper extends Mapper {
    int insert(T entity);

    int deleteById(Serializable id);

    int deleteByMap(@Param("cm") Map columnMap);

    int delete(@Param("ew") Wrapper wrapper);

    int deleteBatchIds(@Param("coll") Collection idList);

    int updateById(@Param("et") T entity);

    int update(@Param("et") T entity, @Param("ew") Wrapper updateWrapper);

    T selectById(Serializable id);

    List selectBatchIds(@Param("coll") Collection idList);

    List selectByMap(@Param("cm") Map columnMap);

    T selectOne(@Param("ew") Wrapper queryWrapper);

    Integer selectCount(@Param("ew") Wrapper queryWrapper);

    List selectList(@Param("ew") Wrapper queryWrapper);

    List> selectMaps(@Param("ew") Wrapper queryWrapper);

    List selectObjs(@Param("ew") Wrapper queryWrapper);

    IPage selectPage(IPage page, @Param("ew") Wrapper queryWrapper);

    IPage> selectMapsPage(IPage page, @Param("ew") Wrapper queryWrapper);
} 

然后数据库表的接口继承baseMapper,各个数据库表接口的实现继承ServiceImpl类就具备了增删改查的基本功能了。

public class ServiceImpl, T> implements IService {

    protected Log log = LogFactory.getLog(getClass());

    @Autowired
    protected M baseMapper;

    @Override
    public M getbaseMapper() {
        return baseMapper;
    }
    //... 省略 ...
}
泛型方法

上面的栗子里其实包含了泛型类、泛型接口和泛型方法,下面再举一个单纯的泛型方法,直接打印泛型的数据类型。

    private static   void printGeneric(T t){
        System.out.println(t.getClass().getName());
    }
实际应用

下面看一个实际应用,比如以太专线和以太专网的公共属性类为以太连接。

以太连接父类:

@Data
public class EthConnection {
    private String attribute;
}

以太专线子类:

@Data
public class ELineConnection extends EthConnection{
    private String uuid;
}

以太专网子类:

@Data
public class ELanConnection extends EthConnection{
    private String uuid;
}

比如我想对以太专线和以太专网子类传入它们共有的属性,那么我得像下面这么做,

public class GenericDemo {
    public static void main(String[] args) {
        String attr = "commonAttribute";
        List eLanConnectionList = buildELanConnection(attr);
        List eLineConnectionList = buildELineConnection(attr);
        eLanConnectionList.stream().forEach(System.out::println);
        eLineConnectionList.stream().forEach(System.out::println);
    }

    private static List buildELanConnection(String attr) {
        ELanConnection connection = new ELanConnection();
        connection.setAttribute(attr);
        return Lists.newArrayList(connection);
    }

    private static List buildELineConnection(String attr) {
        ELineConnection connection = new ELineConnection();
        connection.setAttribute(attr);
        return Lists.newArrayList(connection);
    }
}

这里共有属性不多,感觉没啥,但如果它们需要传入的共有属性很多且都相同,那么重复的代码就太多了。设置共同属性的代码段可以抽取出来,如果属性不多,我下面这种做法也许显得很多余。这样设计是否合适大家可以一起品一品。

public class GenericDemo {
    private static final int ELAN_TAG = 1;
    private static final int ELINE_TAG = 2;
    public static void main(String[] args) {
        String attr = "commonAttribute";
        List eLanConnectionList = buildELanConnection(attr);
        List eLineConnectionList = buildELineConnection(attr);
        eLanConnectionList.stream().forEach(System.out::println);
        eLineConnectionList.stream().forEach(System.out::println);
    }

    private static List buildELanConnection(String attr) {
        return castELanConnection(buildConnection(attr, ELAN_TAG));
    }

    private static List buildELineConnection(String attr) {
        return castELineConnection(buildConnection(attr, ELINE_TAG));
    }

    private static List castELanConnection(List connections) {
        if (CollectionUtils.isEmpty(connections)){
            return Lists.newArrayList();
        }
        return connections.stream().map(ELanConnection.class::cast).collect(Collectors.toList());
    }

    private static List castELineConnection(List connections) {
        if (CollectionUtils.isEmpty(connections)){
            return Lists.newArrayList();
        }
        return connections.stream().map(ELineConnection.class::cast).collect(Collectors.toList());
    }
    
    private static List buildConnection(String attr, int tag) {
        if (tag == ELINE_TAG) {
            ELineConnection connection = new ELineConnection();
            addAttribute(attr, connection);
            return Lists.newArrayList(connection);
        } else if (tag == ELAN_TAG) {
            ELanConnection connection = new ELanConnection();
            addAttribute(attr, connection);
            return Lists.newArrayList(connection);
        }
        return Lists.newArrayList();
    }

    private static void addAttribute(String attr, EthConnection connection) {
        connection.setAttribute(attr);
    } 
}
C++模板(Template)

c++模板和Java泛型类似,它叫模板。以一或多个模版形参参数化,形参有以下三种:

  1. 类型模板形参。
  2. 非类型模板形参。
  3. 模板模板形参。

模板定义的实体有:类模板、函数模板、别名模板(C++11起)、变量模板(C++14起)

详细内容参看文末参考链接。

参考链接:

1、Java 泛型 | 菜鸟教程

2、模板 - cppreference.com

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号