八分钟“手撕”包装类与泛型

目录

一、包装类

基本数据类型和对应的包装类

装箱和拆箱

【思考题】 

二、泛型

什么是泛型 

引出泛型

怎么定义泛型和使用泛型

裸类型(Raw Type)

擦除机制

额外,注意下列代码: 

泛型的上界

泛型的接口应用 

泛型方法 


一、包装类

简单来说:为了服务泛型,把基本类型做成一个引用类型。

基本数据类型和对应的包装类

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

总结:除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。

装箱和拆箱

public class Type {public static void main(String[] args) {int i=10;double d=1.0;//显式装箱Integer i1=Integer.valueOf(i);Double d1=Double.valueOf(d);//隐式装箱Integer i2=i;Double d2=d;//显式拆箱int i3=i1.intValue();double d3=d2.doubleValue();//隐式拆箱int i4=i1;double d4=d1;System.out.println(i1);System.out.println(d1);}
}
//执行结果
10
1.0

从上面代码中,可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制 也就是自动(隐式) 装 / 拆箱 

小小的思考: 

对于Integer来说,这是个类(引用类型),为什么能直接打印值呢?而不是地址呢?

答:在Integer源码里面,它自己实现了重写toString()方法,可以直接输出值。

【思考题】 

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);
}
//执行结果
true
false

为什么两次打印会不一样呢? 

答:在Integer这个包装类中,Integer可以允许的值是-128~127如果输入的值在这个区间以内,就直接返回区间的值;也就是说128超出了这个范围,这时候会new一个新的Integer出来,那让我们看看下面源码是怎么写的:

所以说上述的思考题中,128超出了这个区间,new出的两个空间,这时候他们的地址都是不一样的,==比较的是地址,所以返回false。

二、泛型

什么是泛型 

泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化

引出泛型

实现一个类:

类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值? 

思路:

1. 我们以前学过的数组,只能存放指定类型的元素,

例如:int[] array = new int[10]; String[] strs = new String[10];

2. 所有类的父类,默认为Object类。数组是否可以创建为Object?

代码如下:

class MyArray{Object[] array=new Object[10];public Object getPos(int pos){return this.array[pos];}public void setPos(int pos,Object x){this.array[pos]=x;}
}
public class Test {public static void main(String[] args) {MyArray myArray=new MyArray();myArray.setPos(0,10);myArray.setPos(1,2);myArray.setPos(2,"hello");String s1=myArray.getPos(2);//编译报错String s2=(String)myArray.getPos(2);//需要强转}
}
//执行结果
java: 不兼容的类型: java.lang.Object无法转换为java.lang.String

这时我们会有两个问题:

1.这个数组中又有String又有int是不是太混乱了;

2.强转可行,那每次我都需要强转是不是太麻烦了

我期望的是:

你能接收我指定类型的数据,传什么你能放什么,还可以直接使用。

你上面的代码实现的只是:

Object不能把类型作为参数传递,它只是能接收任何类型的数据,毕竟不管是什么类型,都需要强转。

虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。意义:数据类型参数化,编译时自动进行类型检查和转换

简单来说,泛型就是来优化上面那个代码的,让它能统一放进你想放的类型,还不需要强制类型转化。解决了上面两个问题。

怎么定义泛型和使用泛型

class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}

所以根据语法,我们可以写出下列代码:

package demo2;//<T>代表的这是一个泛型类(有<>都是泛型)
class MyArray<T>{Object[] array=new Object[10];//1//除了上面这一条代码,把下列所有Object替换成Tpublic T getPos(int pos){return (T)this.array[pos];}public void setPos(int pos,T x){this.array[pos]=x;}
}
public class Test {public static void main(String[] args) {/* MyArray后面加个<>,里面放的是你要存放的类型,而后面MyArray的<>,里面可以不写,编译器可以自动判断 */MyArray<Integer> myArray=new MyArray<>();//2myArray.setPos(1,2);myArray.setPos(2,3);\int ret=myArray.getPos(1);//3myArray.setPos(3,"hello");//4,这时候会编译报错String s=(String) myArray.getPos(3);//强转都不行}
}
//执行结果
java: 不兼容的类型: java.lang.String无法转换为java.lang.Integer

1. 类名后的代表占位符,表示当前类是一个泛型类  

 了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:

  • E 表示 Element
  • K 表示 Key
  • V 表示 Value
  • N 表示 Number
  • T 表示 Type
  • S, U, V 等等 - 第二、第三、第四个类型

2. 注释1处,不能new泛型类型的数组 

T[] ts = new T[5];//是不对的

3. 注释2处,类型后加入指定当前类型。注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

4. 注释3处,不需要进行强制类型转换

5. 注释4处,代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行类型检查。   

裸类型(Raw Type)

裸类型是一个泛型类但没有带着类型实参,例如 MyArrayList 就是一个裸类型。

MyArray list = new MyArray();

 注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制。

擦除机制

那么,泛型到底是怎么编译的? 

通过命令:javap -c 查看字节码文件,所有的T都是Object。 

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。 

Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。 

提出问题:

1、那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?

答:我编译的时候不知道你的T是谁,我是在擦除机制擦完之后才知道你的T是谁。所以当我new一个对象时,我必须知道T是谁,它必须有一个具体的类型。否则它语法都无法通过。

2、类型擦除,一定是把T变成Object吗? 

答:在Java中,类型擦除是指在泛型代码编译过程中,编译器将所有泛型类型参数替换为其上界或Object类型。(下个知识点)

额外,注意下列代码: 

class MyArray<T>{public T[] array=(T[])new Object[10];public T getPos(int pos){return (T)this.array[pos];}public void setPos(int pos,T x){this.array[pos]=x;}
//返回这个数组public T[] getArray(){return array;}
}
public class Test {public static void main(String[] args) {MyArray<String> myArray=new MyArray<>();myArray.setPos(1,"hello");String[] s=myArray.getArray();//运行出错}
}
//执行结果
Exception in thread "main" java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.lang.String; ([Ljava.lang.Object; and [Ljava.lang.String; are in module java.base of loader 'bootstrap')

为什么这里会报错呢,报的类型转换异常(强转都不行)

问题:既然T的本质是Object,Object又是所有类的父类,那Object给到子类,为什么不行呢?

答:Object是String的父类没错,但是这里是个数组,Object[]就不是String[]的父类了。

泛型的上界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。 

class 泛型类名称<类型形参 extends 类型边界> {
...
}
//示例
public class MyArray<E extends Number> {
...
}

 只接受 Number 的子类(或者Number自己)型作为 E 的类型实参

MyArray<Integer> l1; // 正常,因为 Integer 是 Number 的子类型
MyArray<String> l2; // 编译错误,因为 String 不是 Number 的子类型error: type argument String is not within bounds of type-variable E
MyArrayList<String> l2;
^
where E is a type-variable:
E extends Number declared in class MyArrayList

 了解: 没有指定类型边界 E,可以视为 E extends Object

泛型的接口应用 

class findMax<T extends Comparable<T>>{public T find(T[] arr){T max=arr[0];for (int i = 1; i < arr.length; i++) {if(arr[i].compareTo(max)>0){max=arr[i];}}return max;}
}
public class Test {public static void main(String[] args) {findMax<Integer> findMax=new findMax<>();Integer[] arr={1,4,6,2,1,3};System.out.println(findMax.find(arr));}
}

 T必须是实现了Comparable接口的,而<T>是Comparable也要是泛型。

泛型方法 

class method{public<T extends Comparable> T find(T[] arr){T max=arr[0];for (int i = 1; i < arr.length; i++) {if(arr[i].compareTo(max)>0){max=arr[i];}}return max;}
}
public class Test {public static void main(String[] args) {findMax<Integer> findMax=new findMax<>();Integer[] arr={1,4,6,2,1,3};System.out.println(findMax.find(arr));}
}

 相当于:把接口应用那个方法直接拿起来用,但是要在方法的前面加上<T extends Comparable>

在方法那里加上Static就是静态的泛型方法,使用的时候用类名调用就好了。

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

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

相关文章

HNCTF_RE复现(一)

baby_python hnctf.yuanshen.life:33276 网页打不开&#xff0c;只能 nc 连接远程服务器。 运行没有回显 利用pickletools库进行反编译为字节码&#xff08;不知道为什么&#xff09; # Python 3.10.12 from pickle import loads import pickletools main b"\x80\x04ct…

windows快速计算文件的SHA256数值的步骤

在文件路径打开cmd窗口 输入命令 用Windows自带的certutil命令来计算一个文件的校验值1&#xff1a; certutil支持的算法有&#xff1a;MD2 MD4 MD5 SHA1 SHA256 SHA384 SHA512。 certutil的使用方法非常简单&#xff0c;只需要执行“certutil -hashfile 文件名 校验值类型”…

分享我经常用的一个图片下载插件,不会写爬虫代码也能随意下载图片

更多精彩内容在公众号。 ImageAssistant&#xff08;图片助手&#xff09;是一款专为Chrome浏览器设计的扩展程序&#xff0c;它具备强大的网页图片处理功能。以下是关于ImageAssistant的一些主要特点和功能&#xff1a; 批量下载图片&#xff1a;ImageAssistant的核心功能之一…

HackTheBox-Machines--Bank

文章目录 0x01 信息收集0x02 文件上传漏洞利用0x03 权限提升方法一&#xff1a;SUID提权方法二&#xff1a;配置不当提权 Bank 测试过程 0x01 信息收集 1.端口扫描 发现 ssh(22)、DNS(53)、HTTP(80) 端口 nmap -sC -sV 10.129.29.200访问 80 端口&#xff0c;页面为Apache2 U…

免费、无限量出图!字节跳动旗下这款国产AI工具,居然这么好用!(强烈推荐)

文章首发于公众号&#xff1a;X小鹿AI副业 大家好&#xff0c;我是程序员X小鹿&#xff0c;前互联网大厂程序员&#xff0c;自由职业2年&#xff0c;也一名 AIGC 爱好者&#xff0c;持续分享更多前沿的「AI 工具」和「AI副业玩法」&#xff0c;欢迎一起交流~ 之前X小鹿一直在各…

软考--试题六--抽象工厂模式(Abstract Factory)

抽象工厂模式(Abstract Factory) 意图 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定他们具体的类 结构 适用性 1、一个系统要独立于它的产品的创建、组合和表示时 2、一个系统要由多个产品系统中的一个来配置时 3、当要强调一系列相关的产品对象的设…

Python中使用C扩展详解

文章目录 1. Python/C API示例2. Cython示例3. ctypes关于C扩展的进一步讨论安全性和兼容性性能优化策略调试C扩展发布和分发C扩展 应用实例&#xff1a;加速矩阵乘法运算1. 准备C扩展代码2. 编译C扩展3. 在Python中使用C扩展 在Python中&#xff0c;使用C扩展是一种提高程序性…

Leetcode - 130双周赛

目录 一&#xff0c;3142. 判断矩阵是否满足条件 二&#xff0c;3143. 正方形中的最多点数 三&#xff0c;3144. 分割字符频率相等的最少子字符串 四&#xff0c;3145. 大数组元素的乘积 一&#xff0c;3142. 判断矩阵是否满足条件 本题题意&#xff0c;满足每一列的数全部…

【Linux系统编程】第十九弹---进程状态(下)

​​​​​​​ ✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、僵尸进程 2、孤儿进程 3、运行状态 4、阻塞状态 5、挂起状态 6、进程切换 总结 1、僵尸进程 上一弹…

网工路由基础——动态路由协议(RIP)

一、动态路由协议的分类 1.按工作区域分类&#xff1a; 动态路由协议按用途分类可以分为内部网关协议&#xff08;IGP&#xff09;和外部网关协议&#xff08;EGP&#xff09;。一个Internet网可以被分成多个域或多个自治系统&#xff0c;各自治系统通过一个核心路由器…

基于语义感知的对象草图绘制

摘要 抽象是素描的核心&#xff0c;因为线条画的简单和最小化特性。抽象涉及识别对象或场景的基本视觉属性&#xff0c;这需要语义理解和对高级概念的先验知识。因此&#xff0c;抽象表现对艺术家来说是具有挑战性的&#xff0c;对机器来说更是如此。我们提出了CLIPasso&#…

软考--试题六--访问者模式(Visitor)

访问者模式(Visitor) 意图 表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作 结构 适用性 1、一个对象的结构包含很多类对象&#xff0c;他们有不同的接口&#xff0c;而用户想对这些对象实施一些依赖于其具体类的操…

STL <string>--------String的OJ题目

1.题目截图&#xff08;把字符串转换成整数----atoi&#xff09; 1.1题目解析&#xff08;在代码里&#xff09; class Solution { public:int myAtoi(string str) {// 100% 97.45% int len str.size();if(len 0)return 0;int i 0, flag 1, isSignal 0, res 0;while(…

小红书孕妇宝妈暴力拉新玩法,每日两小时,单日收益500+

哎呀&#xff0c;你好呀&#xff0c;亲爱的小伙伴们&#xff01;我今天心血来潮&#xff0c;想和你们分享一个超级棒的方法&#xff0c;这个方法我亲自试过&#xff0c;超级有效&#xff01;就是在小红书上针对孕妇和宝妈们进行引流的方法。听起来是不是很有趣呀&#xff1f;&a…

PyCharm运行程序遇到‘[WinError 1455] 页面文件太小’的问题

最近在云环境的PyCharm运行程序&#xff0c;第一次遇到了WinError 1455的问题&#xff0c;感谢大神们给出的解决方法&#xff0c;特此记录一下。 错误提示是‘页面文件小’导致的问题&#xff0c;那么将页面调大即可。 电脑默认情况下没给D盘分配虚拟内存, 如果Python装在D盘…

【工具】macOS、window11访问limux共享目录/共享磁盘,samba服务安装使用

一、samba服务安装 Samba是一个免费的开源软件实现&#xff0c;使得非Windows操作系统能够与Windows系统进行文件和打印服务共享。它实现了SMB/CIFS协议&#xff0c;并且能够在Linux、Unix、BSD等多种系统上运行。 安装 samba&#xff1a; sudo yum install samba配置 samba…

裁员大盘点:2023年50家知名企业到底“减少”了多少员工?

面对裁员传闻&#xff0c;各家都有各家的说法。 什么“人员盘点”、“广进计划、”“优化”、“毕业”、“正常人员调整”、“瘦身”、“寒冬”…… 那么&#xff0c;国内知名企业在过去一年到底增加or减少了多少人&#xff1f; 博主翻查了一些知名上市企业2023年的财报&#…

【SRC实战】findsomething未授权修改密码

挖个洞先 https://mp.weixin.qq.com/s/i6R7OZ-5h9V5o3Kfho7QWA “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合 ” 01 — 漏洞证明 1、网站只有账号密码登录功能&#xff0c;没有注册&#xff0c;忘记密码 2、利用findsomething发现修改密码接口 find…

2024 年第四届长三角高校数学建模竞赛赛题B题超详细解题思路+问题一二代码分享

2024年第四届长三角数学建模竞赛B题详细解题思路 赛道B&#xff1a;人工智能范式的物理化学家 长三角分享资料&#xff08;问题一代码论文思路&#xff09;链接&#xff08;18点更新&#xff09;&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1lteKvIWNZ4v-Gd7oOcg…

visual studio 2017重命名解决方案或项目名称

1.解决方案->右键->重命名->新的名字 2.项目->右键->重命名->新的名字 3.修改程序集和命名空间名称 项目->右键->属性->修改程序集名称和命名空间名称 4.搜索换名 Ctrl-F->输入旧名称->搜索->将所有旧名称改为新名称&#xff08;注意是整…