解析Java中的包装类和泛型

Java中的包装类和泛型

  • 一、包装类与基本类型
  • 二、泛型
    • 1、什么是泛型
    • 2、引出泛型
    • 3、泛型类的定义和使用
    • 4、擦除机制
    • 5、泛型的上界
    • 6、泛型方法
    • 7、通配符
  • 总结

一、包装类与基本类型

包装类,就是基本数据类型对应的类类型。我们已知Java中有8种基本数据类型,这些基本数据类型中除了int对应的包装类Integerchar对应的包装类Character其它包装类均为基本类型首字母大写。

装箱/装包: 把基本类型变为对应的包装类型

拆箱/拆包: 将包装类型拆箱为基本数据类型

//装箱/装包:把基本类型变为对应的包装类型
int a=10;
Integer val0 = (Integer)a;//自动装箱
Integer val1 = a;//自动装箱-->底层就是调用的是以下两个方法:Integer val2 = Integer.valueOf(a);//手动装箱
Integer val3 = new Integer(a);    //手动装箱//拆箱/拆包:将包装类型拆箱为基本数据类型
Integer value1 = 10;//这里存在自动装箱
int z = (int)value1;//自动拆箱
int a = value1;     //自动拆箱-->底层调用了以下方法:
int b = value1.intValue();//手动拆箱
double c = value1.doubleValue();//包装类的权限更大,可以拆成其它类型

一道有坑的面试题:

public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);
}

先说结论,输出结果为 truefalse.其实这道题就考察了装箱的底层原理,我们找到装箱源码:

二、泛型

1、什么是泛型

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。

2、引出泛型

需求: 实现一个类,类中包含一个数组成员可以存放任意类型的数据。

根据我们已知的知识,Object类默认为所有类的父类(包括八大基本类型的包装类),所以我们可以创建一个Object类型的数组用来容纳各种类型的数据。具体实现如下:

class MyArrays {public Object[] obj = new Object[5];public Object getPos(int pos) {return obj[pos];}public void setPos(Object val,int pos) {obj[pos] = val;}
}public class TestDemo {public static void main(String[] args) {MyArrays myArrays = new MyArrays();myArrays.setPos(6,0);myArrays.setPos("world",1);myArrays.setPos(10.5,2);int a = (int)myArrays.getPos(0);String str = (String)myArrays.getPos(1);double d = (double)myArrays.getPos(2);}
}

上面的Object数组确实可以实现什么类型的数据都能存储,但是也有一个问题:对于使用者来说,他们可能并不知道Object数组中每个下标存的到底是什么类型的数据,所以这就给使用时带来了麻烦。

结论:

所以更多情况下,我们还是希望他只能够持有一种数据类型,而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时,就需要把类型,作为参数传递,需要什么类型,就传入什么类型。

3、泛型类的定义和使用

泛型语法

			//泛型类的定义
//概念化
class 泛型类名称<类型形参列表> {// 这里可以使用类型参数
}//具体化
class ClassName<T1, T2, ..., Tn> {// 这里可以使用类型参数
}//泛型类的使用
泛型类<类型实参> 变量名 = new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象

按照上述规则,将上面引入改写:

class MyArray<T> {// 泛型数组(底层为Object)public Object[] obj = new Object[5];public void setObj(int pos,T val) {obj[pos]=val;}public T getPos(int pos) {return (T)obj[pos];}
}
//测试
public class TestDemo {public static void main1(String[] args) {MyArray<Integer> myArray = new MyArray<>();//可以推导出实例化需要的类型实参为 Integer,所以这里的<>中内容可省略myArray.setObj(0,1);myArray.setObj(1,2);myArray.setObj(2,3);int a = myArray.getPos(0);//myArray.setObj(4,"hello");//编译器会对类型检查,导致此处编译报错}
}

注解:

  1. 类名后的 < T > 代表占位符,表示当前类是一个泛型类,T是类型形参(引用类型),一般使用一个大写字母表示,常用的名称有:
    (1) E 表示 Element
    (2) K 表示 Key
    (3) V 表示 Value
    (4) N 表示 Number
    (5) T 表示 Type
    (6) S, U, V 等等 - 第二、第三、第四个类型
  2. 测试代码中,类型后加入 < Integer > 指定当前容器类型为Integer.
  3. int a = myArray.getPos(0);不需要进行强制类型转换.
  4. myArray.setObj(4,"hello");编译报错,是因为上面已指定类当前的类型为Integer,编译器会帮我们进行类型检查.
  5. 泛型只能接受类,所有的基本数据类型必须使用包装类!
  6. MyArray<Integer> myArray = new MyArray<>();当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写.
  7. 错误定义方式T[] ts = new T[5];不能new泛型类型的数组.

4、擦除机制

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。对于泛型的编译这里我们就点到为止,目前先了解泛型有这样一个机制,想要真正理解泛型是需要时间和知识的打磨的!

5、泛型的上界

语法

class 泛型类名称<类型形参 extends 类型边界> {...
}

例如:

//代表将来指定的参数E类型一定是实现了Comparable这个接口的
class Alg<E extends Comparable<E>> {}//E是Number的子类或者E是Number本身
class Alg2<E extends Number> {}

使用场景: 实现一个泛型类,包含一个求数组最大值的方法。

分析: 由于类型形参E是一个引用类型,我们知道引用类型数值比较是不能直接使用大于小于号的,而是需要使用compareTo()比较方法,使用此方法又需要实现Comparable接口,而此时如果不使用泛型上界的话,最终E会被擦除为Object导致不能使用compareTo()方法,所以需要使用泛型上界E extends Comparable<E>

class Alg<E extends Comparable<E>> {//如果不使用泛型上界会导致E被擦除为Object,后面public E findMax(E[] array) {E max = array[0];for (int i = 1; i < array.length; i++) {if (max.compareTo(array[i])<0) {max = array[i];}}return max;}
}
//测试
public class TestDemo {Alg<Integer> alg = new Alg<>();Integer[] array = {5,2,7,100,3,6,9};int max = alg.findMax(array);System.out.println(max);
}

6、泛型方法

语法

方法限定符 [static] <类型形参列表> 返回值类型 方法名称(形参列表) { ... }

使用泛型方法改写上述求最大值泛型类:

class Alg2 {//这里将其改写成静态的方法public static  <E extends Comparable<E>> E findMax(E[] array) {E max = array[0];for (int i = 1; i < array.length; i++) {if(max.compareTo(array[i])<0) {max=array[i];}}return max;}
}
//测试
public class TestDemo {public static void main(String[] args) {Integer[] array1 = {1,2,3,4,5};Integer[] array2 = {6,7,8,9,10};int max2 = Alg2.<Integer>findMax(array2);//可以使用类型推导省略<>int max1 = Alg2.findMax(array1);System.out.println("array1的最大值为:"+max1);System.out.println("array2的最大值为:"+max2);}

7、通配符

? 用于在泛型的使用,即为通配符

在"?"的基础上又产生了两个子通配符:

(1)? extends 类:设置通配符上限

<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类

(2)? super 类:设置通配符下限

<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型

特别注意: 使用 ? 通配符时,无法对泛型类型进行具体化操作,即不能将具体类型赋值给 ?。因此,在使用 ? 通配符的地方,只能进行读取操作(获取或比较),而不能进行写入操作(添加或修改)。这是为了保证类型安全性。

总结

到这里本文就结束了,或许读完本文你对泛型的理解还是萌萌懂懂,不过这都没关系,本篇文章的主要目的是能够对泛型在语法层面有一个基本的认知,想要真正理解泛型是需要时间和知识的打磨的!

到此断断续续的JavaSE也就告一段落了,总的来说Java的语法没有那么多弯弯绕绕,重点在于理解“面向对象”的概念。当然了JavaSE对于整个编程星球来说也只是一块敲门砖。路漫漫其修远兮,吾将上下而求索,我们下期再见喽!

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

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

相关文章

分布式协议与算法——Paxos算法

目录 Paxos算法Basic Paxos算法三种角色如何达成共识&#xff08;协商过程&#xff09;小结&#xff1a; Multi-Paxos算法关于 Multi-Paxos 的思考领导者优化Basic PaxosChubby 的 Multi-Paxos 实现小结 参考 Paxos算法 Paxos论文 Paxos Made Simple 、author&#xff1a;Lesli…

MongoDB创建用户 、数据库、索引等基础操作

MongoDB的权限认证是相对来说比较复杂的&#xff0c;不同的库创建后需要创建用户来管理。 本机中的MongoDB是docker 启动的&#xff0c;所以先进入docker的镜像中 docker exec -it mongodb bash 这样就进入到了镜像MongoDB中&#xff0c;然后输入命令连接MongoDB数据库 注…

省电模式稳定电压显示IC32×4 LCD显示驱动芯片

简述 VK1C21A是一个点阵式存储映射的LCD驱动器&#xff0c;可支持最大128点&#xff08;32SEGx4COM&#xff09; 的LCD屏&#xff0c;也支持2COM和3COM的LCD屏。单片机可通过3/4个通信脚配置显示参数和发 送显示数据&#xff0c;也可通过指令进入省电模式。具备高抗干扰&a…

【SpringBoot】| ORM 操作 MySQL(集成MyBatis)

目录 一&#xff1a;ORM 操作 MySQL 1. 创建 Spring Boot 项目 2. MapperScan 3. mapper文件和java代码分开管理 4. 事务支持 一&#xff1a;ORM 操作 MySQL 使用MyBatis框架操作数据&#xff0c; 在SpringBoot框架集成MyBatis&#xff0c;使用步骤&#xff1a; &#x…

漫画 | TCP/IP之大明邮差

后记&#xff1a; 1973年&#xff0c;卡恩与瑟夫开发出了网络中最核心的两个协议&#xff1a;TCP协议和IP协议&#xff0c;随后为了验证两个协议的可用性&#xff0c;他们做了一个实验&#xff0c;在多个异构网络中进行数据传输&#xff0c;数据包在经过近10万公里的旅程后到达…

Python爬虫在框架下的合规操作与风险控制

大家好&#xff01;作为一名专业的爬虫代理供应商&#xff0c;我今天要和大家分享一些关于Python爬虫在法律框架下的合规操作与风险控制的知识。随着互联网的发展&#xff0c;数据爬取在商业和研究领域扮演着重要的角色&#xff0c;但我们也必须遵守相关法律和规定&#xff0c;…

【小程序】Canvas 画布分享海报

成品效果图 可以通过切换下面图片形成不同的海报背景分享图 <template><view>// type"2d"必须加<canvas type"2d" :style"{width:Artwidth px,height:Artheight px, margin:0 auto}" canvas-id"firstCanvas"id&quo…

神码ai伪原创【php源码】

大家好&#xff0c;小编为大家解答python必备常用英语词汇笔记的问题。很多人还不知道python中常用的英语单词&#xff0c;现在让我们一起来看看吧&#xff01; 火车头采集ai伪原创插件截图&#xff1a; 一.什么是注释 注释是对一段代码的解释&#xff0c;不参与程序运行&…

信息安全技术工业控制系统安全控制应用指南学习笔记

工业控制系统安全控制基线 根据工业控制系统在国家安全、经济建设、社会生活中的重要程度&#xff0c;遭到破坏后对国家安全、社会秩序、公共利益以及公民、法人和其他组织的合法权益的危害程度等&#xff0c;结合信息安全等级保护标准划分及实施效果分析&#xff0c;结合工业…

Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权)

一.Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权) 本次测试使用数据库实例SqlServer2008r2版 错误详细&#xff1a; 标题: Microsoft SQL Server Management Studio ------------------------------ 还原数据库“Mvc_HNHZ”时失败。 (Microsoft.SqlServer.…

Android 开发者选项日志存储路径

android开发者选项中存在两个item是关于系统日志的。 1.日志记录器缓冲区大小 2.在设备上永久存储日志记录器数据 一个是用来设置缓冲区大小&#xff0c;一个是用来日志存储开关及过滤。 通过分析 system/core/logcat/logcatd.rc mkdir /data/misc/logd 0770 logd log 日志的…

机器学习参数调优

手动调参 分析影响模型的参数&#xff0c;设计步长进行交叉验证 我们以随机森林为例&#xff1a; 本文将使用sklearn自带的乳腺癌数据集&#xff0c;建立随机森林&#xff0c;并基于泛化误差&#xff08;Genelization Error&#xff09;与模型复杂度的关系来对模型进行调参&…