Java泛型详解

Java泛型详解,必须掌握 点击上方“猿码天地”,选择“设为星标”回复”666“获取新整理的面试文章1. 泛型概述泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。Java 泛型(ge... 阅读详情
java泛型的了解

        java泛型是1.5的新特性,我们先通过一个例子来简单了解一下泛型。

泛型了解:

//在java 1.5之前,集合是这样处理的。
List c1 = new ArrayList();
c1.add("abc");
c1.add(1);
String s1 = (String) c1.get(0);
String s2 = (String) c1.get(1);
        在编译的时候,这样是可以编译通过的,在java1.5之前,但是,在运行的时候会出现错误,因为List中存储的是object,是开发者自己做的类型转化,如上述代码,就把Integer转化成了String。
而在java1.5之后,我们可以这样做。
//在java 1.5之后
List<String> c1 = new ArrayList<String>();
c1.add("abc");
c1.add(1);
        这样,使用泛型后,编译的时候是有错误的,说了里面只能存String,结果存了Integer。
    
        简单总结一下:没有使用泛型的时候,只要是对象,不管是什么类型,都可以存储进同一个集合,使用泛型集合后,可以将集合中的元素限定为某一种类型,这样更安全。在从集合中取元素的时候,不需要进行强制转化,编译器已经知道了集合中存的是什么类型。
进一步了解泛型:

        泛型的一些术语介绍:

        ArrayList<E>    ArrayList<String>

        整个ArrayList<E>称为泛型类型。中间这个<E>称为类型变量,(类型参数)

        整个ArrayList<String>称为参数化的类型,String称为实际类型参数或者类型参数的实例。

        ArrayList称为原始类型。

泛型的一些思考:

        一:

        这样看来,泛型让运行过程中可能出现的错误在编译的过程中暴露出来,更加安全的使用集合,那么,泛型是不是就可以说是给编译器用的,因为,编译器会提示我们写的代码是不是安全的。如果编译完之后,这个泛型还有作用吗?
List<String> c1 = new ArrayList<String>();
List<Integer> c2 = new ArrayList<Integer>();
System.out.println(c1.getClass() == c2.getClass());
        看一下打印结果:
true
        这说明上面的c1和c2是同一份字节码,因此看来,泛型在编译过后,已经不存在了,这就是“去类型化”。

        既然,字节码中已经没有了类型信息的限制,那通过反射,就可以往集合中放入其它类型的实例了。看一下如下代码:

List<String> c1 = new ArrayList<String>();
try {
Method method = c1.getClass().getMethod("add", Object.class);
method.invoke(c1, 123);
Object object = c1.get(0);
System.out.println(object);
} catch (Exception e) {
e.printStackTrace();
}
打印结果:
123
        并没有报错,存的是Object,取的是Object。通过去类型化的特性,在只能存string的集合中存了c1.由此,更证明了泛型在编译完之后就消失了,泛型是给编译器看的。

        二:

        参数化类型和原始类型的兼容性:

//可以编译通过
List<String> c1 = new ArrayList();
//可以编译通过
List c2 = new ArrayList<String>();
//不可以编译通过
List<String> c3 = new ArrayList<Object>();
//不可以编译通过
List<Object> c3 = new ArrayList<String>();
        这个很好理解,现在有了泛型,那么前辈们写的代码我们还要继续使用,如一个方法一直返回一个ArrayList,现在来个一个参数化类型,能不能调用这个函数,当然可以,同样,你传递一个参数化的类型,原来接收一个集合,也应该可以使用。 因为,泛型是给编译器用的,编译器肯定兼容之前的,肯定能通过了。参数化类型是不考虑继承关系的,所以,第三种和第四种写法是错误的。
泛型的通配符:

        在api文档中,经常会看到这样的“<?>”这样的问号在类的后面跟着。先通过一个需求来了解问号。

        定义一个方法,可以打印任意List集合中的元素。(List<Integer>,List<String>......)这样的参数化类型都可以打印。

public void print(List<?> list){
for (Object object : list) {
System.out.println(object);
}
}
        ? 就是通配符,代表任意类型参数。小例子:
public void method1(Collection<Object> c){
//可以编译通过,add的是Object
c.add("abc");
c.add(123);
//错误,前面说过,参数化类型是不考虑继承的。所以,错误
c = new ArrayList<String>();
}
public void method2(Collection<?> c){
//并没有声明具体类型就放String?错误
c.add("abc");
//把一个?(可以匹配任意类型),让它类型参数实例为String
c = new ArrayList<String>();
}
        泛型中通配符的扩展。
        1:限定通配符的上边界
List<? extends Number> list = new ArrayList<Integer>();

        2;限定通配符下边界
//正确
List<? super Integer> list1 = new ArrayList<Number>();
//错误
List<? super Integer> list2 = new ArrayList<String>();
//正确,可以把一个类型给?
List<?> list1 = new ArrayList<Number>();
//错误,不可以把一个?给一个具体类型
List<Number> list2 = new ArrayList<?>();
自定义泛型:

        java的泛型是从c++泛型借鉴过来的,但没有c++的强大,但java还是尽可能的去模仿c++的泛型。

        同样,看一个需求,写一个方法,可以实现2个数的相加,但类型不同,先看看c++的实现

template<class T>
T add(T x,T y){
return (T)x+y;
}
        在看看java的实现。
/**
* 如何定义一个类型,返回值之前,并紧挨着返回值。
*/
public <T> T add(T x,T y){
// The operator + is undefined for the argument type(s) T, T
// 对于T来说,可能没有+这个操作。因此,在java中不能实现c++这样的功能,但仍然了解了java中泛型在方法上的使用。
// return (T)x+y;
return null;
}
泛型的类型推断:

        在上面的add方法中,尝试着这样的调用。

add(1, 2);
add(1, 2.0);
add(1, "abc");
        这样的调用,是不会出错的,既然参数类型是都是T,然而第2个一个是int,一个是float,第三个一个是int,一个是String都没有报错。通过编辑器自动生成返回值看看。
Integer add = add(1, 2);
Number add2 = add(1, 2.0);
Object add3 = add(1, "abc");
        由此可以推断,类型推断中,取了2个参数的共同父类,当作了实际类型参数。
        类型推断的传播性:如下
public static <T> void copy(Collection<T> c,T[] a) {
}
//错误
copy(new ArrayList<Float>(), new Integer[10]);
        既然类型变量取了父类,为什么这里没有取Number?原因是在对ArrayList参数化的时候,已经指定了T就是Float,这就是类型推断的传播性。
        简单总结一下:
        a:在返回值或者参数列表中的一个参数中使用了参数变量,那么传递的参数类型就是实际类型参数。
        b:在参数列表中多个地方使用了参数变量,在实际调用的过程中,如果传递一样的,很好判断,如果不一样,就会取几个的最大交集,如(Float,Integer,则实际类型参数就是Number)
        c:在参数列表多个地方和返回值都使用了,会根据返回值的类型来确定实际类型参数。
        d:传播性。
自定义泛型方法&自定义泛型类

    1:自定义泛型方法。如上面的add方法一样。

    例子:写一个方法,可以交换一个数组中的2个位置上的值。

public static <T> void swap(T[] arr,int x,int y){
T temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
        试着使用swap这个方法。
//正确
swap(new String[]{"aaa","bbb"},0, 1);
swap(new Integer[]{111,222},0, 1);
//错误
swap(new int[]{1,2}, 0, 1);
        注意:泛型的实际类型不能是基本数据类型。因为,数组本来就是一个对象了,不会进行自动装箱,所以这里会报错。并且,数组中的元素不能使用参数化类型。如:
//正确
ArrayList[] a1 = new ArrayList[10];
//错误:Cannot create a generic array of ArrayList<String>
ArrayList<String>[] a2 = new ArrayList<String>[10];
        类型变量也可以表示异常。
public static <T extends Exception> void method() throws T{
try {
} catch (Exception e) {
throw (T)e;
}
}
        如果有多个类型变量,可以在<>中指出多个,用逗号隔开。如Map集合。

        2:自定义泛型类 

public class GenericStudy<T> {
 
}
        这样,就可以在方法中使用泛型类型了,因为在实际中,毕竟对一个类的操作希望对应的都是某一种类型,并不是多个,那么就可以在类上定义了,注意:静态方法不能使用这个类型参数,因为对象还没有?哪里来的类型参数实例?静态方法,就自己在方法上定义了。
获取类型参数实例:

        由于泛型的去类型化,在编译成字节码后已经看不到这个到底是什么类型了?如何获取?

public void apply(List<String> l){
}
try {
Method method = GenericStudy.class.getMethod("apply", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
Type type = parameterizedType.getActualTypeArguments()[0];
Type rawType = parameterizedType.getRawType();
System.out.println(rawType+":"+type);
} catch (Exception e) {
e.printStackTrace();
}
}
 打印结果:
interface java.util.List:class java.lang.String


知识推理——TransE(知识表示、知识嵌入) 知识图谱嵌入/表示方法 TransE 阅读详情

相关推荐

dxf-viewer 查看器

dxf-viewer SDK 的示例,它是一个基于 Three.js 和 Vue3 构建的基于 WebGL 的 BIM 模型查看器。它用于查看 DWG/DXF/PDF 文件。面积测量 - 角度测量 -标记。

qq_25547755的博客 866

Java 中的泛型详解

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参列表,普通方法的形参列表中,每个形参的数据类型是确定的,而变量是一个参数。在调用普通方法时需要传入对应形参数据类型的变量(实参),若传入的实参与形参定义的数据类型不匹配,则会报错。那参数化类型是什么?以方法的定义为例,在方法定义时,将方法签名中的形参的数据类型也设置为参数(也可称之为类型参数),在调用该方法时再从外部传入一个具体的数据类型和变量。

XuChaofafa的博客 1704

GO与KEGG富集分析实战:从差异基因到功能注释

本文详细介绍了GO与KEGG富集分析的完整实战流程,从差异基因列表出发,通过基因ID转换、核心分析到结果可视化,系统阐述了如何将基因数据转化为生物学洞察。文章重点讲解了使用R语言clusterProfiler包进行GO和KEGG富集分析的具体步骤、参数设置及常见问题解决方案,并强调了结果解读与生物学故事构建的方法,帮助研究者深入理解差异基因的集体功能倾向。

weixin_29291863的博客 918

Java泛型详解:Java泛型集合、泛型类、泛型方法、泛型的使用

在 Java 1.5 之前没有泛型,通常需要使用强制类型转换的方式将一种数据类型转换为另一种数据类型,这种转换要求开发者对实际参数的类型具有可预知性。对于强制类型转换错误的情况,编译器可能不会提示错误,但是在运行时会出现异常,这是一个安全隐患。 为了解决这一隐患,从 Java 1.5 开始提供了泛型。泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。本节将详...

jijiangpeng的博客 7443

CentOS7环境下搭建 rsyslog 日志服务器,rsyslog+loganalyzer

1.系统环境部署 ip hostname 192.168.200.182 web 192.168.200.184 rsyslog-mysql 关闭防火墙、selinux、下载epel源 [root@web ~]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/f

sehn_的博客 3754

【VisualStdio】手把手教你做一个上位机(1)控件设计布局

网上有很多形形色色的制作上位机教程,有些写的挺好的,但是过于单调。

m0_73409202的博客 5435

Java 泛型详解

首先在没有泛型之前,一旦把一个对象丢进java集合中,集合就会忘记对象的类型,把所有对象当成Object类型来处理。当程序从集合中取出对象时,就需要进行强制类型转换,这种强制类型转换不仅代码臃肿,而且容易引起ClassCastException异常。 public class ListErr { public static void main(String[]

zsm653983的专栏 2419

电赛2024年H题智能小车基于MSPM0G3507主控MCU(利用8路灰度加上MPU6050的解决方式)

最后我觉得这个项目最重要的部分还是陀螺仪的精准度,如果一个陀螺仪的精准度高,这个项目就十分简单了,像mpu6050这种陀螺仪精准度就稍微差了一点,他有个最严重的问题就是温漂,偏航角会随着温度变化为变化,这一点在跑发挥项一的时候十分关键的,因为这个只差基督就会导致车子跑偏,导致无法完成 整个项目。如果条件足够的话建议可以换一个好一点的陀螺仪,然后就是灰度如果没有条件同样也可以换成红外。以上就是本次项目的一些小建议。

weixin_60991529的博客 6243

【 java 泛型】详解java泛型

java泛型可以提高java程序的类型安全,提高程序的可靠性,并且在开发中也较常用,因此还是要简单学习一下!

阿牛的博客 2069

【ROS学习笔记】13.ROS中的坐标管理系统

文章目录1 机器人中的坐标变换2 TF功能包TF坐标变换如何实现?TF的一个小案例3 小程序:小海龟跟随实验打开小程序查看当前的TF树坐标相对位置关系可视化1(tf_echo)坐标相对位置关系可视化2(rviz) 本节学习ROS中的坐标管理系统。 (部分图摘自:b站【古月居】古月·ROS入门21讲) 1 机器人中的坐标变换 机器人运动学的核心,描述任意两个坐标系之中任意两个向量之间的变换,可以用一个4×4的变换矩阵(Transformation Matrices)来描述它的平移和旋转变化。 变换矩阵中有包括

takedachia的博客 4338

PX4从放弃到精通(二十二):日志

文章目录前言一、下载日志二、ulog转CSV三、利用flightplot软件分析PX4的ulog日志1 windos安装2 ubuntu18.04安装四、使用PlotJuggler分析PX4日志五、设置日志记录条件六、添加自定义日志消息 前言 PX4 1.10以上固件 QGC 一、下载日志 将飞控链接地面站,在下图页面点击“刷新”,即可看到保存的日志(前提是要有TF卡) 选择需要下载的日志,点击右侧的“下载”,然后选择目录即可进行下载,如果想擦除所有的日志,可以点击右侧的“擦除全部” 二、ulog转CS

超维空间科技的博客 6796

java泛型详解

java泛型详解

weixin_52385232的博客 2554

使用Matlab与V-REP联合仿真

在Matlab中,我们可以使用V-REP提供的远程API(Application Programming Interface)来连接到V-REP仿真环境。为了连接Matlab与V-REP,我们需要在Matlab中添加V-REP的远程API函数库。你可以根据具体的需求编写Matlab脚本来控制V-REP场景中的机器人,并进行系统建模和仿真。一旦成功连接到V-REP,我们可以使用Matlab来控制V-REP场景中的机器人。在本文中,我们将介绍如何使用Matlab与V-REP进行联合仿真,并提供相应的源代码。

HackMasterX的博客 1854

java泛型详解_Java泛型详解

一. 泛型概念的提出(为什么需要泛型)?首先,我们看下下面这段简短的代码:1 public classGenericTest {23 public static voidmain(String[] args) {4 List list = newArrayList();5 list.add("qqyumidi");6 list.add("co...

weixin_39553705的博客 240

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java泛型详解_java 泛型详解

1 普通泛型class Point{// 此处可以随便写标识符号,T是type的简称private T var ;// var的类型由T指定,即:由外部指定public T getVar(){// 返回值的类型由外部决定return var ;}public void setVar(T var){// 设置的类型也由外部决定this.var = var ;}};public class Gener...

weixin_42165018的博客 184

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【Android架构师java原理专题详解】一;泛型原理详解

前言;本篇为【Android架构师java原理专题详解】第一篇;泛型原理。后面会分享完整系列原理详解笔记,包括反射,多线程,JVM,虚拟机,序列化等重要知识点。有兴趣可以持续关注谢谢java知识是作为Android开发的语言基础,虽然之前又推出了kotlin,但是基于以下原因我们还是需要好好牢牢掌握java:1)SDK还是改成java,kotlin也需要编译成为java运行;...

weixin_34293059的博客 150

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

java 泛型详解(普通泛型、 通配符、 泛型接口,泛型数组,泛型方法

Java代码Java代码Java代码Java代码Java代码Java代码Java代码。

2401_84619530的博客 1531

JAVA泛型详解

泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分贝成为泛型类、泛型接口、泛型方法。Java语言引入泛型的好处就是安全简单。      在Java SE 1.5之前,没有泛型的情况下,通过堆类型Object的引用来实现参数的“任意化”,这样做的缺点就是要进行显式的强制类型转换,而这种转换要求开发者

cdy的博客 公众号:Android开发吹牛皮 522
上一篇: Looper介绍
下一篇: AndroidStudio使用gradle打包并实现多渠道打包
arplay
博客等级 码龄12年 0粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值