Java泛型05 : 泛型使用的8个限制_在使用泛型时有哪些限制-程序员宅基地

技术标签: Java泛型  Java泛型学习实例  类型转换安全隐患  限制  类型擦除  

超级通道: Java泛型学习系列-绪论

本章主要对Java泛型使用的8个限制进行说明。

1.Java泛型不能使用基本类型

java的基本类型:boolean,char,float,double,byte,int,short,long。
使用基本类型的泛型会编译报错,代码如下:

List<int> list = new List<int>();// 编译前类型检查报错

分析:因为泛型在编译时,会进行类型擦除,最后只保留原始类型。而原始类型只能是Object类及其子类,当然不能使用基本数据类型。

2.Java泛型不允许进行实例化

错误代码如下:

<T> void test(T t){
    
    t = new T();//编译前类型检查报错
}

通过类型擦除,上面的泛型方法会转换为如下的原始方法:

void test(Object t){
	t = new Object();
}

而,实际使用中,实参t一般情况下都是Object的子类,此时t = new Object();相当于:

Integer t = 1;
t = new Object();

而Object肯定无法转换成Integer的。Java泛型为了防止此类类型转换错误的发生,禁止进行泛型实例化
当然,与类型擦除一样,可以通过Java反射实现泛型的实例化,但是不建议这么做。这里就不给出代码了,有兴趣的可以自己尝试。

3.Java泛型不允许进行静态化

参考下面的代码:

    /**
     * <p>Title: 3.Java泛型不允许进行静态化</p>
     * @author 韩超 2018/2/23 11:25
     */
    static class Demo<T>{
    
        private static T t;// 编译前类型检查报错

        // 编译前类型检查报错
        public static T getT() {
    
            return t;
        }
    }

原因:静态变量在类中共享,而泛型类型是不确定的,因此编译器无法确定要使用的类型,所以不允许进行静态化
备注:这里的静态化针对的对象是泛型变量,并不是泛型方法。感谢@ZYC_July的意见。

4.Java泛型不允许直接进行类型转换(通配符可以)

示例代码如下:

List<Integer> integerList = new ArrayList<Integer>();
List<Double> doubleList = new ArrayList<Double>();
//不能直接进行类型转换,类型检查报错
//integerList = doubleList;

我们已知,在编译阶段,两者都会经过类型擦除变为ArrayList,那为什么不能进行类型强制转换呢?
因为这违背了Java泛型设计的初衷:降低类型转换的安全隐患
integerList内存储的是Integer类型的元素,doubleList 是存储的是Double类型的元素,如果不限制类型转换,很容易产生ClassCastException异常。


Java泛型不允许直接进行类型转换,但是通过通配符可以实现类型转换(不建议这么做)
代码如下:

static void cast(List<?> orgin, List<?> dest){
    
    dest = orgin;
}
public static void main(String[] args){
    
    List<Integer> integerList = new ArrayList<Integer>();
    List<Double> doubleList = new ArrayList<Double>();
    //通过通配符进行类型转换
    cast(doubleList,integerList);
}

关于通配符的相关知识,会在下一章节解析学习。

5.Java泛型不允许直接使用instanceof运算符进行运行时类型检查(通配符可以)

直接使用instanceof运算符进行运行时类型检查:

List<String> stringList = new ArrayList<String >();
//不能直接使用instanceof,类型检查报错
//LOGGER.info(stringList instanceof ArrayList<Double>);

我们可以通过通配符的方式进行instanceof运行期检查(不建议)

//通过通配符实现运行时验证
LOGGER.info(stringList instanceof ArrayList<?>);

result:

2018-02-23 14:33:20 INFO  GenericAttentionDemo:71 - true

6.Java泛型不允许创建确切类型的泛型数组(通配符可以)

创建确切类型的泛型数组如下:

//类型检查报错
//Demo6<Integer>[] iDemo6s = new Demo6<Integer>[2];

我们可以通过通配符的方式创建泛型数组(不建议)

//通过通配符实现泛型数组
Demo6<?>[] iDemo6s = new Demo6<?>[2];
iDemo6s[0] = new Demo6<Integer>(1);
iDemo6s[1] = new Demo6<String >("hello");
for (Demo6 demo6 : iDemo6s){
    
    LOGGER.info(demo6.getT().getClass().toString() + " : " + demo6.getT());
}

reuslt:

2018-02-23 14:58:01 INFO  GenericAttentionDemo:97 - class java.lang.Integer : 1
2018-02-23 14:58:01 INFO  GenericAttentionDemo:97 - class java.lang.String : hello

7.Java泛型不允许定义泛型异常类或者catch异常(throws可以)

直接看代码:

/**
  * <p>Title: 7.Java泛型不允许定义泛型异常类</p>
  *
  * @author 韩超 2018/2/23 15:07
  */
//    static class Apple<T> extends Exception {
    
//    }

//    static class Orange<T> extends Throwable {
    
//    }

 /**
  * <p>Title: 7.Java泛型不允许捕获一个泛型异常</p>
  *
  * @author 韩超 2018/2/23 15:09
  */
 //7.Java泛型:可以throws泛型类型
 <T extends Exception> void test7(T t,Class<T> tClass) throws T {
    
     try {
    
         //...
//        } catch (T t) {//不允许捕获一个泛型类型的异常
     } catch (Exception e) {
    //不允许捕获一个泛型类型的异常
         //...
     }
 }

为什么Java泛型不允许定义泛型异常类?为什么不允许捕获一个泛型异常?先看下面的代码:

//假设可以定义泛型异常类
try{
    
	//。。。
}catch(MyException<Integer> e){
    
	//。。。
}catch(MyException<Double> e){
    
	//。。。
}

上面的代码,进行类型擦除时会去掉Integer和Double信息,形成如下代码:

try{
    
	//。。。
}catch(MyException e){
    
	//。。。
}catch(MyException e){
    
	//。。。
}

同时catch两个一样的异常,肯定不能通过编译。
Java泛型为了避免这种错误的产生,不允许定义泛型异常类或者catch异常。

总结:

  • Java泛型:不允许定义泛型异常类(直接或间接扩展Throwable类)
  • Java泛型:不允许捕获一个泛型异常
  • Java泛型:可以以异常类作为边界
  • Java泛型:可以throws泛型类型

8.Java泛型不允许作为参数进行重载

代码如下:

/**
 * <p>Title: 8.Java泛型不允许作为参数进行重载</p>
 * @author 韩超 2018/2/23 15:32
 */
static class Demo8<T>{
    
    void test(List<Integer> list){
    }
    //不允许作为参数列表进行重载
    //void test(List<Double> list){}
}

为什么呢?
因为类型擦除之后,两个方法是一样的参数列表,这种情况无法重载。

9.总结

Java泛型其实还有其他的使用限制,这里不再赘述。
我们在理解Java泛型的使用限制时,应该首先用心理解下面两点:

  1. Java泛型的设计初衷:降低类型转换的安全隐患,而非为了实现任意化
  2. Java泛型的实现原理:类型擦除
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hanchao5272/article/details/79352321

智能推荐

vue中使用webVideoCtrl播放海康插件_海康威视divplugin 浮层问题-程序员宅基地

文章浏览阅读2.2k次。<template> <div class="video-player"> <div id="divPlugin" class="divPlugin" ref="divPlugin" v-if="plugin"> </div> <!-- <div class="down" v-else> <a href="http://jbfsys.oss-cn-bei.._海康威视divplugin 浮层问题

Android 9 (P)之init进程启动源码分析指南之三_exec_start update_verifier_nonencrypted-程序员宅基地

文章浏览阅读3.6k次,点赞7次,收藏10次。      Android P之init进程启动源码分析指南之三前言  在前面的篇章Android P之init进程启动源码分析指南之一和Android P之init进程启动源码分析指南之二讲解了init进程经过前面两个阶段以后,已经建立了相关的文件系统,属性系统,SELinux安全策略系统。但是我们知道init进程做的远远不止这些,还要启动一些Android的native service系统服务及其其他相关的操作,但是如果都是像属性系统和SELinux系统那样一行行代码去做,显得有点杂乱繁琐,而且_exec_start update_verifier_nonencrypted

关联规则--Apriori算法_apriori关联规则算法-程序员宅基地

文章浏览阅读2w次,点赞17次,收藏199次。啤酒与尿布的故事:在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,超市也因此发现了一个规律,在购买婴儿尿布的年轻的父亲们中,有30%~40%的人同时要买一些啤酒。超市随后调整了货架的摆放,将尿布和啤酒放在一起,因此,明显增加了销售额。_apriori关联规则算法

JS如何在正则表达式中插入变量_js正则表达式怎么加入一个变量中的字符-程序员宅基地

文章浏览阅读2.9k次。JS如何在正则表达式中插入变量的值_js正则表达式怎么加入一个变量中的字符

省级森林防火应急指挥系统_如何在电脑上安装森林防火指挥系统-程序员宅基地

文章浏览阅读645次。监控指挥中心兼顾监控室、值班室、设备室、调度指挥室等,按功能分区,合理布局。主要功能是远程监看多个监控点传来的图像,必要时对前端摄像头进行控制、视频录像和火情报警,把图像传输到上级管理部门及林业局各级领导办公室,便于随时了解火情,进行指挥调度等。_如何在电脑上安装森林防火指挥系统

网络(三)之VTP的原理及配置(cisco)_vtp配置实验原理-程序员宅基地

文章浏览阅读3.5k次,点赞3次,收藏19次。VTP的原理及配置本期我们主要讲一下思科设备特有的一种VLAN中继协议,也被称为虚拟局域网干道协议。在现实的运用十分广泛,主要实现vlan之间的同步。什么是VTPVTP(VLAN Trunking Protocol):是VLAN中继协议,也被称为虚拟局域网干道协议。它是思科私有协议。作用是十几台交换机在企业网中,配置VLAN工作量大,可以使用VTP协议,把一台交换机配置成VTP Server..._vtp配置实验原理

随便推点

牛津大学VGG团队提出:改进遮挡检测的Tri-Layer插件 | BMVC 2022-程序员宅基地

文章浏览阅读1.4k次。点击下方卡片,关注“CVer”公众号AI/CV重磅干货,第一时间送达作者:Championchess |已授权转载(源:知乎)编辑:CVerhttps://zhuanlan.zhihu.com/p/575588904点击进入—>CV微信技术交流群A Tri-Layer Plugin to Improve Occluded Detection项目主页:https://www.robot..._a tri-layer plugin to improve occluded detection

Java Web学习(7):JSP基础语法_java web构建一个主题网站进一步掌握jsp的基础语法-程序员宅基地

文章浏览阅读2.6k次。一个JSP页面可以被分为以下几部份: 1)静态数据,如HTML; 2)JSP指令,如include指令; 3)JSP脚本元素和变量; 4)JSP动作; 5)用户自定义标签; 一静态数据 静态数据在输入文件中的内容和输出给HTTP响应的内容完全一致。此时,该JSP输入文件会是一个没有内_java web构建一个主题网站进一步掌握jsp的基础语法

Mybatis学习之路04_数据库加密连接_java mybaits 访问使用加密数据库密码-程序员宅基地

文章浏览阅读319次。主要思想:写一个数据加密工具类,将加密后的用户名、密码放在外部属性配置文件中(这里我们放在db.properties里),在创建SqlseetionFacroty时,将外部数次那个文件中的用户名和密码取出来,并解密,再通过Properties类中的setProperty方法,将解密后的参数放进db.properties里(但db.properties文件里并没有被改变),然后通过SqlSessio..._java mybaits 访问使用加密数据库密码

【MoveIt2-humble】入门教程(翻译自官方文档)二:在 RViz 中实现可视化_moveit2教程-程序员宅基地

文章浏览阅读1.9k次,点赞4次,收藏14次。本系列教程共四节,环境为:Ubuntu22.04ros2-humbleMoveIt2-humble官方文档上的教程,从moveit1的melodic到moveit2的foxy基本一致,但是从最新的humble开始有了很大的变化,其中之一便是 lambda表达式 的广泛使用。本节为教程的第二节,会介绍一个工具(moveit_visual_tools),它能够通过在 rviz 中呈现可视化,从而帮助你更容易理解你的 Moveit 应用在做什么。前提是需要先完成之前内容,可以看我的这篇博文:https://_moveit2教程

struts2 从一个action到另一个action传参的问题!_action用?传参-程序员宅基地

文章浏览阅读790次。 //针对订单修改之后返回当条订单 HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(ServletActionContext.HTTP_REQUEST); request.setAttri..._action用?传参

智能安防赛道上,云从科技是展翅高飞还是落地成盒-程序员宅基地

文章浏览阅读159次。不久前,一幅由人工智能所作的《埃德蒙·贝拉米》画像在纽约佳士得以43.25万美元(约为300万人民币)的高价拍出,拍出价格远高与同场的毕加索作品。此次事件的爆出,在给人们带来“一幅由人工智能所作的画像竟然能拍出如此天价”感叹的同时,也让市场感受到CV作为人工智能领域的重要领域之一,其在市场上的商业化落地范围在不断扩大。近年来,随着行业的快速发展与技术的逐渐成熟,市场上涌现出不少计算机视觉企业,..._南京宇旷则然信息技术有限公司

推荐文章

热门文章

相关标签