简单了解泛型

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

在Java中, 基本数据类型不是继承自Object, 为了在泛型代码中可以支持基本类型, Java给每个基本类型都对应了一个包装类型.

简单来说就是让基本数据类型也能面向对象.基本数据类型可以使用很多方法, 这就必须让它变成类.

基本数据类型对定的包装类

基本数据类型       包装类

byte                      Byte

short                    Short

int                        Integer

long                     Long

float                     Float

double                 Double

char                    Character

boolean              Boolean

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

装包(箱)和拆包(箱)

把基本类型变为包装类型, 叫做装箱

把包装类型变为基本类型, 叫做拆箱

    public static void main(String[] args) {//自动装包, 内部其实是调用了 valueOf 方法来实现的Integer a = 10;int i = 99;Integer b = i;//基本类型 转变为 包装类型, 都是可以直接打印的System.out.println(a);System.out.println(b);//显示装箱Integer aa = Integer.valueOf(10);}
    public static void main(String[] args) {Integer a = 10;//自动拆箱, 内部调用了 intValue() 方法;int i = a;//拆包int aa = a.intValue();double b = a.doubleValue();}

Java 包装类提供了很多方法, 可以自动调用很方便

    public static void main(String[] args) {Integer a = 100;Integer b = 100;System.out.println(a == b);Integer a1 = 200;Integer b1 = 200;System.out.println(a1 == b1);}//代码上述的输出结果为: true   和    false

为什么呢?

如果出现这个错误第一时间想到了什么呢? 我想可以看一下 Integer 出现了什么错误, 然后呢? 在赋值的过程中出现了自动装箱, 自动装箱的函数是 valueOf , 所以可以在valueOf中寻找出错的点在哪里, 现在找到 valueOf 的源码, 看装包的过程哪一点出错了

    public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

这个源码, 如果 i 在范围内就返回一个数组里面的值, 如果不在范围就返回 new Integer(i)

我们在源码中可以得到 low的大小为 -128, high 的大小为 127;

也就是 i 的范围在 -128 到 127 之间的话返回这个数组的某一个值

这个数组大小是多少呢? 范围是 [-128, 127], 共 256 个数字, 可以得出 下图 这个数组的样子

当 i 的范围在其之间可以返回相同的值, 如果超过了就返回一个 new 的值. 由此可出上述结果为什么是这样.

泛型

是Java中一种很难的语法

举个例子, 写一个类, 类包含一个数组成员, 让数组中可以存放任意类型的数据, 也能根据成员方法返回数组某个下标的值.

class MyArray {Object[] array = new Object[10];void setValue(int i, Object val) {array[i] = val;}Object getValue(int i) {return array[i];}
}
public class Main {public static void main(String[] args) {MyArray myArray = new MyArray();myArray.setValue(0, 1);myArray.setValue(1, "hello");//下面这一行代码报错, 因为返回值是 Object 类型,//需要强转为 String 类型才可以//String str = myArray.getValue(0);  <---报错String str = (String)myArray.getVlaue(0);}
}

这我们就想了, 不能让什么数据类型都能放到这个数组中, 我们可以指定一个数据, 这样我们在接受数据的时候也不用看每一个接收的数据是什么类型了. 我们就引入了泛型.

泛型的语法

1>

class 泛型类名称 <类型形参列表> {

    //可以使用类型参数

}

示例:

class ClassName<T1, T2, .... Tn>{

}

2>

class 泛型类名称<类型形参列表> extends 继承类 {

         //可以使用类型参数

}

示例:

class ClassName<T1, T2, .... Tn> extends ParentClass<T1> {

        //可以使用类型参数

}

类型形参列表可以用 T , E , K , V 等字母表示 其中<T, E, K, V...> 表示什么呢?

表示当前类 是一个泛型类 它只是一个占位符.

下面将上述代码改一下:

class MyArray <T>{Object[] array = new Object[10];void setValue(int i, T val) {array[i] = val;}T getValue(int i) {return (T)array[i]; // 把返回的类型,强转为指定类型}
}
public class Main {public static void main(String[] args) {//这行代码强制了数据类型为Integer, <>里面只能放入包装类MyArray<Integer> myArray = new MyArray<>();myArray.setValue(0, 1);//myArray.setValue(1, "hello");  <----当前代码报错了//如果我们想要放入其它类型的数据怎么做呢? 在创建一个新对象就好了MyArray<String> myArray1 = new MyArray<>();int i = myArray.getValue(0);System.out.println(i);}
}

 注意:

1> 因为使用了泛型, 在编译的时候 帮我们进行了类型的检查, 取数据也不需要进行类型转换

2> 在尖括号 <> 里面必须是引用类型.

3> 创建的一个数组的时候 不能写成 T[] array = new T[];

泛型的上界

语法:

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

...

}

示例:

public class MyArray<T extends Number> {

...

}

其中的 T 必须是 Number 或者 Number的子类, 这就叫做泛型的上界

在创建对象时:

MyArray<Integer> a1 = new MyArray<>();   可以

MyArray<Double> a1 = new MyArray<>();   可以

MyArray<String> a1 = new MyArray<>();   不可以

举例: 写一个泛型类, 求一个数组中的最大值

class Alg<T> {public T findMaxValue(T[] array) {T max = array[0];for (int i = 1; i < array.length; i++) {if(max < array[i]) {max = array[i];}}return max;}
}

这段代码的 if 中的判断条件会出现报错, 为什么呢?

因为 T 是引用数据类型, 最终是被擦除为了 Object 类型, Object 没有实现了Comparable 接口, 所以不能直接比较大小, 要想能够比较大小, 就得让 T 实现 Comparable 接口, 实现了 Comparable接口后, 以后创建对象时, 只有实现了 Comparable 接口的才能创建

就比如: 

MyArray<Integer> a1 = new MyArray<>();   可以, 因为Integer 实现 Comparable 接口

class Preson { ... }

MyArray<Person> a1 = new MyArray<>();   不可以 , 因为Person 没有实现 Comparable 接口

所以上述代码应该写成:

class Alg<T extends Comparable> {public T findMaxValue(T[] array) {T max = array[0];for (int i = 1; i < array.length; i++) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}
public class Main {public static void main(String[] args) {Alg<Integer> alg = new Alg<>();Integer[] integers = {1, 2, 3, 4, 5, 6};Integer ret = alg.findMaxValue(integers);System.out.println(ret);}
}

写一个泛型方法:

如下列代码:

在这种情况下会出现 类型推导, 根据实参传值, 来推导出此时的类型.

class Alg2 {public <T extends Comparable>T findMaxValue(T[] array) {T max = array[0];for (int i = 1; i < array.length; i++) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}
public class Main {public static void main(String[] args) {Alg2 alg2 = new Alg2();Integer[] integers = {1, 2, 3, 4, 5, 6};Integer ret2 = alg2.findMaxValue(integers);System.out.println(ret2);}
}

下列代码将泛型方法改为静态的, 可以通过类名直接调用该泛型方法, 不用实例化对象了

class Alg3 {public static <T extends Comparable>T findMaxValue(T[] array) {T max = array[0];for (int i = 1; i < array.length; i++) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}public class Main {public static void main(String[] args) {Integer[] integers = {1, 2, 3, 4, 5, 6};Integer ret3 = Alg3.findMaxValue(integers);System.out.println(ret3);}
}

小结

学会泛型的含义, 泛型的目的, 泛型的语法

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

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

相关文章

HDLC协议

目录 1.概念 2.配置 3.HDLC帧结构 4.HDLC帧类型 1.概念 HDLC(High-level Data Link Control&#xff09;高级数据链路控制位于链路层协议&#xff0c;传输单位是帧&#xff0c;它是一组用于在网络结点间传送数据的协议。其特点是各项数据和控制信息都以比特为单位&#xff…

神经网络极简入门

神经网络是深度学习的基础&#xff0c;正是深度学习的兴起&#xff0c;让停滞不前的人工智能再一次的取得飞速的发展。 其实神经网络的理论由来已久&#xff0c;灵感来自仿生智能计算&#xff0c;只是以前限于硬件的计算能力&#xff0c;没有突出的表现&#xff0c;直至谷歌的A…

bfs之八数码

文章目录 八数码解题思路图解举例算法思路 代码CPP代码Java代码 八数码 在一个 33的网格中&#xff0c;1∼8这 8个数字和一个 x 恰好不重不漏地分布在这 33 的网格中。 例如&#xff1a; 1 2 3 x 4 6 7 5 8在游戏过程中&#xff0c;可以把 x 与其上、下、左、右四个方向之一…

leetcode-字符串的排列-100

题目要求 思路 1.因为只涉及到字符&#xff0c;因此可以进行排序 2.创建临时字符串&#xff0c;当临时字符串temp的长度等于str的长度&#xff0c;作为判出条件。 3.创建一个标记的数组&#xff0c;每次在temp中插入一个字符&#xff0c;便在对应的数组下标设置为1&#xff0c…

初期Linux

一&#xff0c;系统分为 1.1window系统 个人 &#xff1a;win7&#xff0c;win8&#xff0c;Win10&#xff0c;Win11服务器版&#xff1a;window server 2003&#xff0c;window server 2008 1.2Linux系统 centos7redhatubantukali 1.3什么是Linux&#xff1f; Linux是基…

C++变量的作用域与存储类型

一 变量的作用域和存储类型 1 变量的作用域(Scope) 指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(Local Variable)和全局变量(Global Variable) 1&#xff09;局部变量(Local Variable) 在语句块内定义的变量 形参也是局部变量 特点&#xff1a; 生存期是…

YzmCMS 7.0任意函数调用RCE 漏洞研究分析

YzmCMS是一款基于YZMPHP开发的一套轻量级开源内容管理系统,YzmCMS简洁、安全、开源、免费,可运行在Linux、Windows、MacOSX、Solaris等各种平台上,专注为公司企业、个人站长快速建站提供解决方案。 YzmCMS 某些接口调用了 db_pdo类的where方法 导致了远程命令执行漏洞&#xf…

python菜鸟级安装教程 -下篇(安装编辑器)

来来~接着上篇的来~ 安装好python.exe之后&#xff0c;我们可以根据cmd命令窗口&#xff0c;码代码。 这算最简单入门了~ 如果我们在安装个编辑器。是什么效果&#xff0c;一起体验一下吧 第一步&#xff0c;下载编辑器&#xff0c;选择官网&#xff0c;下载免费版本入门足…

图解HTTP(2、简单的 HTTP 协议)

HTTP 协议用于客户端和服务器端之间的通信 请求访问文本或图像等资源的一端称为客户端&#xff0c;而提供资源响应的一端称为服务器端。 通过请求和响应的交换达成通信 请求必定由客户端发出&#xff0c;而服务器端回复响应报文 请求报文是由请求方法、请求 URI、协议版本、…

【Gaea+UE5】创建基本的大型世界场景

目录 效果 步骤 一、在Gaea中生成地形 二、确定导出的地形规模 三、在UE中创建地形 四、验证UE创建的地形规模是否正确 五、使用M4自动地形材质 效果 步骤 一、在Gaea中生成地形 1. 打开Gaea官网下载软件 2. 打开Gaea软件&#xff0c;我们可以选择一个预设的山体 创…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐PyMuPDF+tqdm)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 文章目录 PyMuPDF 使用体验与评估1 安装指南2 测试代码3 测试结果3.1 转 HTML …

docker资源限额

多数的应⽤场景要对Docker容器的运⾏内存进⾏限制&#xff0c;防⽌其使⽤过多的内存。 格式&#xff1a;-m或--memory 正常的内存大小 [rootadmin ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS …