[转载] 详解Java中的泛型

参考链接: Java中具有泛型的有界类型

1、什么是泛型 

 

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。 

2、一个小例子 

 

import java.util.ArrayList;

import java.util.List;

 

public static void main(String[] args) {

 

        List list = new ArrayList();

        list.add("hello");

        list.add("hallo");

        list.add(1);

        for (int i = 0; i < list.size(); i++) {

            String str = (String) list.get(i);

            System.out.println(str);

        }

    }

上面的程序:  编译阶段正常,而运行时会出现异常 

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 

存在的问题:  当把一个对象收入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,对象变成了Object类型,但其运行时类型任然为其本身类型。强制转换时,容易出现异常,正如程序中把Integer转为String失败。 

解决方法:  通过使用泛型来使集合能够记住集合内元素各类型 

将上面的代码用泛型来实现 

import java.util.ArrayList;

import java.util.List;

 

public class Main {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();

        list.add("hello");

        list.add("hallo");

        list.add(1);

        for (int i = 0; i < list.size(); i++) {

            String str = list.get(i);

            System.out.println(str);

        }

    }

这时,编译错误,无法运行 

Error:(13, 13) java: 对于add(int), 找不到合适的方法

    方法 java.util.Collection.add(java.lang.String)不适用

      (参数不匹配; int无法转换为java.lang.String)

    方法 java.util.List.add(java.lang.String)不适用

      (参数不匹配; int无法转换为java.lang.String) 

通过List,直接限定了list集合中只能含有String类型的元素,从而在取得集合中的元素时无须进行强制类型转换,编译器可以确定集合中存的都是String类型。 

3、泛型的特性 

 

Java中的泛型,只在编译阶段有效。 

在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。 

泛型信息不会进入到运行时阶段。 

4、泛型的使用 

 

在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。 

以几个小例子来分析一下 

(1) 泛型类 

public class ArrayList<E>

extends AbstractList<E>

implements List<E>, RandomAccess, Cloneable, Serializable 

用泛型类声明与建立对象 

ArrayList<String> list = new ArrayList<String>(); 

JDK7之后可以写成: 

ArrayList<String> list = new ArrayList<>(); 

(2) 泛型接口 

...

public interface Comparator<T>{

    int compare(T o1, T o2);

    ...

使用方法 

public class StringComparator implements Comparator<String>{

    @Override

    public int compare(String s1, String s2){

        return -s1.compareTo(s2);

    }

(3) 泛型方法 

public static <T> T elemof(T[] objs,int index){

    return objs[index];

使用方法 

public static String elemof(String[] objs,int index){

    return objs[index];

5、泛型的上下边界问题 

 

可以使用extends与super关键字、?类型通配符来限制泛型,并且可以结合这三者来模拟共变性与逆变性。 

共变性与逆变性 

如果B是A的子类,而Node< B >可视为一种Node< A >,则称Node具有共变性(Covariance)或者有弹性的(Flexible)。 

如果B是A的子类,而Node< A >可视为一种Node< B >,则称Node具有逆变性(Contravariance)。 

Java泛型不支持共变性与逆变性 

(1) 使用?与extends来模拟共变性 

class Fruit{}

class Apple extends Fruit{}

class RedApple extends Apple{}

 

List< ? extends Fruit > list1 = new ArrayList<Fruit>();

List< ? extends Fruit > list2 = new ArrayList<Apple>();

List< ? extends Fruit > list3 = new ArrayList<RedApple>(); 

Fruit为上界,即List< ? extends Fruit >类型的对象可以引用持有Fruit及其子类的容器。 

关于一个add方法: 

void add(List< ? extends Fruit > list, Apple a){

     list.add(a);

如果list引用的是持有RedApple类型的容器,那么将Apple类型向下转型是不安全的,所以用List< ? extends Fruit >,add方法是受到限制的,即无法向容器中添加任何实际的类型除了null。 

(2) 使用?与super来模拟逆变性 

List< ? super RedApple > list4 = new ArrayList<RedApple>();

List< ? super RedApple > list5 = new ArrayList<Apple>(); 

RedApple为下界,即List< ? super RedApple >类型的对象可以引用持有RedApple及其父类的容器。 

此时add方法是没有限制的,但是也只能是添加Jonathan及其父类型。若事先不知道List< ? super RedApple >引用的对象所持有的类型,则可以做到向上转型,而向上转型是安全的。 

6、小结 

 

泛型的本质是:参数化类型 

只在编译阶段有效,泛型使用无错误时,擦出泛型的相关信息,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法,泛型信息不会进入到运行时阶段。 

泛型可以被用在类、接口和方法中,而且可以限制泛型的上下界。 

虽然Java泛型不支持共变性与逆变性,但是?与extends可模拟共变性;?与super可模拟逆变性。 

 

参考资料 

《Java学习笔记》 林信良 

Java泛型的边界问题 

java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/540387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【初学者必读】:前端工程师的知识体系

下图是前端工程师图解&#xff1a; 前端开发的核心是HTML CSS JavaScript。本质上它们构成一个MVC框架&#xff0c;即HTML作为信息模型&#xff08;Model&#xff09;&#xff0c;CSS控制样式&#xff08;View&#xff09;&#xff0c;JavaScript负责调度数据和实现某种展现逻…

[转载] Java面试题大全(2020版)

参考链接&#xff1a; Java中的循环 发现网上很多Java面试题都没有答案&#xff0c;所以花了很长时间搜集整理出来了这套Java面试题大全&#xff0c;希望对大家有帮助哈~ 本套Java面试题大全&#xff0c;全的不能再全&#xff0c;哈哈~ 博主已将以下这些面试题整理成了一个…

使用Prometheus监控Cloudflare的全球网络

Matt Bostock在SRECON 2017欧洲大会的演讲中&#xff0c;介绍了如何使用Prometheus实现对CloudFlare分布于全球的架构和网络的监控。Prometheus是一种基于度量进行监控的工具&#xff0c;CloudFlare是一家CDN、DNS和DDoS防御&#xff08;Mitigation&#xff09;服务提供商。\\基…

[转载] Java-forEach增强for循环是值传递规则详解

参考链接&#xff1a; Java中的for-each循环 1. 引入 正如Java语法意义&#xff0c;变量的传递只有值传递&#xff0c;虽然变量分为引用变量和基本类型变量&#xff0c;前者更像C中的地址概念。 在学习Lambda表达式的时候&#xff0c;遇到了试图在增强for循环中对原链表元素重…

开始吧

2019独角兽企业重金招聘Python工程师标准>>> 写C三年有余&#xff0c;在技术方面也算小有所成。准备在这里分享一些C进阶、Python、Golang技术文章。 CSDN博客地址&#xff1a; http://blog.csdn.net/godmaycry 以后博客同步更新。 转载于:https://my.oschina.net/u…

[转载] 常用应届生Java开发笔试面试题(更新中)

参考链接&#xff1a; Java中的循环的重要事项 Java开发面试题 Java基础篇Java8大基本数据类型Java的三大特性面向对象如果让你推销一款Java产品&#xff0c;你会怎么推销呢&#xff1f;&#xff08;java的特点&#xff09;JVM与字节码JDK与JREStringBuilder和StringBuffer的区…

java/javascript 时间操作工具类

一、java 时间操作工具类 import org.springframework.util.StringUtils;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List;/*** 时间操作工具类** author zwq**/ public …

[转载] java语言程序设计-基础篇

参考链接&#xff1a; Java中的决策制定(if&#xff0c;if-else&#xff0c;switch&#xff0c;break&#xff0c;continue&#xff0c;jump) 第1章&#xff0c;计算机、程序和Java概述 包括【每个java初学者都应该搞懂的问题】 http://blog.csdn.net/haobo920/article/detai…

Exchange server 2013(十四)WSUS部署及组策略设置(2)

我们继续上一节未完的博客&#xff0c;继续我们的WSUS设置。[上一章节标题&#xff1a;Exchange server 2013(十四)WSUS部署及组策略设置(1) 网址&#xff1a;http://1183839.blog.51cto.com/blog/1173839/1182366] 首先单击自动审批,来修改审批规则,也就是说当wsus侦测到新的更…

[转载] Python中的switch语句的替代品

参考链接&#xff1a; Java中的switch语句 Python 中没有 switch语句。 一般用if-else 语句可以替代switch语句&#xff0c;今天学习了使用字典的映射来代替switch语句。Mark一下 day 8; def get_sunday(): return sunday def get_monday(): return monday def get_tues…

“□” 表情无法在 Android 设备显示? 快试试 EmojiCompact 表情兼容库

有了支持库 v26 下的 Compact 库&#xff0c;基于 API 19 及更高版本开发的应用就能获得 emoji 的向下兼容&#xff0c;再也不会看到显示失败的 “豆腐块” 啦。如要使用 EmojiCompact&#xff0c;需要在应用启动时通过下载或者打包字体来初始化库。通过集成小插件&#xff0c;…

[转载] jstl获取Parameter参数及switch使用

参考链接&#xff1a; Java中的字符串使用switch <% taglib uri"/WEB-INF/tld/c.tld" prefix"c" %> param 获取 Parameter参数 <c:choose> <c:when test"${empty param.name}"> Please enter your name. …

syslinux 制作多系统启动U盘

syslinux 制作多系统启动U盘标签&#xff1a;u盘使用 syslinux 制作多系统启动U盘 syslinux 能加载虚拟内存盘&#xff0c;能引导各种镜像文件&#xff0c;适合用于制作多系统启动U盘&#xff0c; 但是我按照网上说的步骤&#xff0c;总是不能制作成功&#xff1a; 1. 格式化…

[转载] JAVA基础----java中E,T,?的区别?

batch_size 1 layout "NHWC" target tvm.target.Target("cuda") dtype "float32" log_file "%s-%s-B%d.json" % (network, layout, batch_size)

用MATLAB结合四种方法搜寻罗马尼亚度假问题

选修了cs的AI课&#xff0c;开始有点不适应&#xff0c;只能用matlab硬着头皮上了&#xff0c;不过matlab代码全网仅此一份&#xff0c;倒有点小自豪。 一、练习题目 分别用宽度优先、深度优先、贪婪算法和 A*算法求解“罗马利亚度假问题”。具体地图我这里不给出了&#xff0c…

[转载] Java中文与ASCII码的转换

参考链接&#xff1a; 扩展Java中的原始转换 今天在研究Java中编码的时候&#xff0c;看到了Java中ascii码的强大。写了一个CoderUtils.java&#xff0c;以后会扩展它。 package com.xingxd.study.test; import java.io.File; import java.io.FileWriter; import java.io.I…

[转]Paul Adams:为社交设计

为社交设计 Strong, Weak, and Temporary Ties by Paul Adams on 2010/04/09 PS&#xff1a;作者Paul Adams Facebook全球品牌体验总监 电话和手机聚集十亿用户用了15年的时间&#xff0c;而Facebook只用了9个月。我们看到越来越多的人开始用在线社交网络&#xff0c;这种网络好…

[转载] Java中日期格式转换

参考链接&#xff1a; Java中的类型转换和示例 Code: /** * 字符串转换为java.util.Date<br> * 支持格式为 yyyy.MM.dd G at hh:mm:ss z 如 2002-1-1 AD at 22:10:59 PSD<br> * yy/MM/dd HH:mm:ss 如 2002/1/1 17:55:00<br> * yy/MM/dd HH:…

Android Framework中的Application Framework层介绍

Android的四层架构相比大家都很清楚&#xff0c;老生常谈的说一下分别为&#xff1a; Linux2.6内核层&#xff0c;核心库层&#xff0c;应用框架层&#xff0c;应用层。我今天重点介绍一下应用框架层Framework。 Framework层为我们开发应用程序提供了非常多的API&#xff0c;我…

[转载] java注释

参考链接&#xff1a; Java注释 Java注释 java中注释有三种&#xff1a;这些都称之为java doc标记&#xff0c;含义如下&#xff1a; java中注释有三种&#xff1a; 单行注释 //注释的内容&#xff0c;多行注释 /…注释的内容…/&#xff0c;文档注释 /**…注释的内容….*/。…