DataStructure.包装类简单认识泛型

包装类&简单认识泛型

  • 【本节目标】
  • 1 包装类
    • 1.1 基本数据类型和对应的包装类
    • 1.2 装箱和拆箱
    • 1.3 自动装箱和自动拆箱
  • 2 什么是泛型
  • 3 引出泛型
    • 3.1 语法
  • 4 泛型类的使用
    • 4.1 语法
    • 4.2 示例
    • 4.3 类型推导(Type Inference)
  • 5. 裸类型(Raw Type) (了解)
    • 5.1 说明
  • 6 泛型如何编译的
    • 6.1 擦除机制
    • 6.2 为什么不能实例化泛型类型数组
  • 7 泛型的上界
    • 7.1语法
    • 7.2 示例
    • 7.3 复杂示例
      • Alg 类
      • TestGeneric 类
      • 逻辑关系和总结
  • 8 泛型方法
    • 8.1 定义语法
    • 8.2 示例
    • 8.3 使用示例
      • Alg2 类
      • TestGeneric 类
      • 逻辑关系和总结

【本节目标】

  1. 以能阅读 java 集合源码为目标学习泛型
  2. 了解包装类
  3. 了解泛型

1 包装类

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

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

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

除了 IntegerCharacter, 其余基本类型的包装类都是首字母大写。

1.2 装箱和拆箱

public class Test {public static void main(String[] args) {int i = 10;//装箱操作:新建一个Integer类型对象,将i的值放进对象的某个属性中Integer ii = Integer.valueOf(i);Integer ij = new Integer(i);//拆箱操作:将Integer对象中的值取出,放到一个基本数据类型中int j = ii.intValue();}
}

1.3 自动装箱和自动拆箱

可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。

public class Test {
//可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。public static void main2(String[] args) {int a = 10;Integer b = a; // 自动装箱Integer c = (Integer) a; // 自动装箱int j = b; // 自动拆箱int k = (Integer) b; // 自动拆箱 }
}

在这里插入图片描述
【面试题】

下列代码输出什么,为什么?

public class Test {//下列代码输出是什么,为什么?public static void main(String[] args) {Integer a = 127;Integer b = 127;Integer c = 128;Integer d = 128;System.out.println(a == b);//trueSystem.out.println(c == d);//false}
}

2 什么是泛型

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

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

3 引出泛型

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

思路:

  1. 以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] array = new String[10];
  2. 所有类的父类,默认为Object类,数组是否创建为Object

代码示例:

class MyArray {public Object[] objects = new Object[10];//输入public Object getObjects(int pos) {return objects[pos];}//输出public void setObjects(int pos, Object obj) {this.objects[pos] = obj;}
}public class Test {public static void main(String[] args) {MyArray myArray = new MyArray();myArray.setObjects(0, 100);myArray.setObjects(1, "hello");//字符串也可以存放String ret = (String)myArray.getObjects(1);//String ret = myArray.getObjects(1);//编译报错System.out.println(ret);}
}

问题:以上代码实现后 发现

  1. 任何类型数据都可以存放
  2. 下标1本身是字符串,但是编译报错,必须进行强制类型转换
  • 虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。
  • 所以,泛型的主要目的:就是指定当前的容器,要持有什么样的类型。让编译器去做检验。 此时,就需要把类型,作为参数传递,需要什么的类型,就传入什么类型。

3.1 语法

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

上述代码进行改写如下:

class MyArray1 <T> {public T[] objects = (T[])new Object[10];//1public T getObjects(int pos) {return objects[pos];}public void setObjects(int pos, T obj) {this.objects[pos] = obj;}
}public class Test1 {public static void main(String[] args) {MyArray1<Integer> myArray11 = new MyArray1<>();//2myArray11.setObjects(1, 100);int ret1 = myArray11.getObjects(1);//3System.out.println(ret1);System.out.println(myArray11.getObjects(1));//myArray11.setObjects(2,"bit");//4}
}

代码解释:

  1. 类名后的代表占位符,表示当前类是一个泛型类
    了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:
  • E表示Element
  • K表示Key
  • V表示Value
  • N表示Number
  • T表示Type
  • S, U, V 等等 - 第二、第三、第四个类型
  1. 注释1处,不能new泛型类型的数组
    意味着:
T[] ts = new T[];//error

课件当中的代码:T[] array = (T[])new Object[10];是否就足够好,答案是未必的。这块问题一会儿介绍。

  1. 注释2处,类型后加入<Integer>指定当前类型
  2. 注释3处,不需要进行强制类型转换
  3. 注释4处,代码编译报错,此时因为在注释2处指定类当前的类型,此时在注释4处,编译器会在存放元素的时候帮助我们进行校验检查。

4 泛型类的使用

4.1 语法

泛型类<类型实参> 变量名; //定义一个泛型类
new 泛型类<类型实参>(构造方法实参); //实例一个泛型类对象

4.2 示例

MyArray<Integer> list = new MyArray<Integer>();

注意:泛型只能接受类,所有的基本数据类型必须使用包装类!

4.3 类型推导(Type Inference)

当编译器可以根据上下文导出类型实参时,可以省略类型实参的填写

MyArray<Integer> list = new MyArray<>(); //可以推导出实例化需要的类型实参为 Integer

5. 裸类型(Raw Type) (了解)

5.1 说明

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

MyArray List = new MyArray();

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

下面的类型擦除部分,我们也会讲到编译器是如何使用裸类型的。

小结:

  1. 泛型是将数据类型参数化,进行传递
  2. 使用<T>表示当前类是一个泛型类。
  3. 泛型到目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换

6 泛型如何编译的

6.1 擦除机制

那么,泛型到底是怎么编译的?这个问题,也是曾经的一个面试问题。泛型本质是一个非常难的语法,要理解好他还是需要一定的时间打磨。

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

在这里插入图片描述
在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制

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

提出问题:

1、那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?
2、类型擦除,一定是把T变成Object吗?

6.2 为什么不能实例化泛型类型数组

代码1:

class MyArray2 <T> {public T[] array = (T[]) new Object[10];public T getPos(int pos) {return array[pos];}public void setVal(int pos, T val) {this.array[pos] = val;}public T[] getArray() {return array;}
}public class Test {public static void main(String[] args) {MyArray2<Integer> myArray2 = new MyArray2<>();Integer[] string = myArray2.getArray();}
}/*
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;*/

原因:替换后的方法为:将Object[]分配给Integer[]引用,程序报错.

public Object[] getArray() {return array;
}

通俗讲就是:返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Integer类型的数组,编译器认为是不安全的。

正确的方式:【了解即可】

class MyArray<T> {public T[] array;public MyArray() {}/*** 通过反射创建,指定类型的数组** @param clazz* @param capacity*/public MyArray(Class<T> clazz, int capacity) {array = (T[]) Array.newInstance(clazz, capacity);}public T getPos(int pos) {return this.array[pos];}public void setVal(int pos, T val) {this.array[pos] = val;}public T[] getArray() {return array;}
}public class Test1 {public static void main(String[] args) {MyArray<Integer> myArray1 = new MyArray<>(Integer.class, 10);Integer[] integers = myArray1.getArray();}
}

7 泛型的上界

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

7.1语法

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

7.2 示例

public class MyArray<E extends Number> {...
}

只接受Number的子类型作为E的类型实参

MyArray<Integer> l1; //正常,因为Integer是Number的子类型
MyArray<String> l2; //编译报错,因为String不是Number的子类型

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

7.3 复杂示例

写一个泛型类,当中的方法,可以求数组中的最大值

//写一个泛型类,当中的方法,可以求数组中的最大值
class Alg<E extends Comparable<E>> {public E findMax(E[] array) {E max = array[0];for (int i = 0; i < array.length; i++) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}public class TestGeneric {public static void main(String[] args) {Integer[] array = {1, 2, 3, 4, 5, };Alg<Integer> alg = new Alg<>();Integer ret = alg.findMax(array);System.out.println(ret);}
}

代码包含两个类:AlgTestGeneric。其中,Alg 是一个泛型类,用于找到数组中的最大值,而 TestGeneric 是包含 main 方法的测试类,用于演示如何使用 Alg 类来找到整数数组中的最大值。

Alg 类

  1. 泛型定义Alg 类被定义为一个泛型类 Alg<E extends Comparable<E>>,这意味着它接受一个类型参数 E,这个类型必须实现 Comparable<E> 接口。这样,Alg 类就能对 E 类型的对象进行排序和比较。

  2. findMax 方法

    • 这个方法接受一个 E 类型的数组作为参数。
    • 它首先将数组的第一个元素赋值给变量 max,作为初始的最大值。
    • 然后,它遍历整个数组,使用 compareTo 方法比较当前最大值 max 和数组中的每个元素。
    • 如果当前元素大于 max(即 max.compareTo(array[i]) < 0),则更新 max 为当前元素。
    • 最后,返回找到的最大值。

TestGeneric 类

  1. main 方法
    • 首先,定义了一个 Integer 类型的数组 array,并初始化了一些值。
    • 然后,创建了一个 Alg<Integer> 的实例 alg
    • 调用 algfindMax 方法,将整数数组作为参数传入,并将返回的最大值存储在变量 ret 中。
    • 最后,打印出找到的最大值。

逻辑关系和总结

  • Alg 类利用了 Java 的泛型机制,使其能够处理实现了 Comparable 接口的任何类型的数据。这提供了很大的灵活性,因为你可以用它来找到任何可比较类型数组中的最大值。
  • TestGeneric 类中,通过创建一个 Alg<Integer> 的实例并调用其 findMax 方法,我们演示了如何使用这个泛型类来找到整数数组中的最大值。
  • compareTo 方法用于比较两个对象的大小,这是 Comparable 接口的一部分。在这个例子中,它用于确定数组中的最大值。
  • 最终,程序打印出数组 {1, 2, 3, 4, 5} 中的最大值,即 5

整个程序的逻辑关系是:定义一个能找数组中最大元素的泛型类 -> 实例化这个类并传入特定类型的数组 -> 找出并打印数组中的最大值。

8 泛型方法

8.1 定义语法

方法限定符<类型参数列表> 返回值类型 方法名称(相残列表) {...
}

8.2 示例

public class Util {//静态的泛型方法 需要在static后用<>声明泛型类型参数public static <E> void swap(E[] array, int i, int j) {E t = array[i];array[i] = array[j];array[j] = t;}
}

8.3 使用示例

//写一个泛型类,当中的方法,可以求数组中的最大值
class Alg2 {public <E extends Comparable<E>> E findMax(E[] array) {E max = array[0];for (int i = 0; i < array.length; i++) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}public class TestGeneric {public static void main2(String[] args) {Integer[] array = {1, 2, 3, 4, 5, };Alg2 alg2 = new Alg2();Integer ret = alg2.findMax(array);//Integer ret = alg2.<Integer>findMax(array);System.out.println(ret);}
}

在这段代码中,Alg2 类不再是一个泛型类,而是其中的 findMax 方法是一个泛型方法。这意味着这个方法可以接受任何实现了 Comparable 接口的类型数组,并返回该类型数组中的最大值。

Alg2 类

  • findMax 方法被声明为泛型方法,通过 <E extends Comparable<E>> 来定义类型参数 E,这表明 E 必须实现 Comparable<E> 接口。
  • 方法的实现逻辑与之前相同:初始化 max 为数组的第一个元素,遍历数组,通过 compareTo 方法比较每个元素,并更新 max 如果找到更大的元素,最后返回 max

TestGeneric 类

  • main 方法中,创建了一个 Alg2 的实例 alg2
  • 调用 alg2findMax 方法,并传入一个 Integer 类型的数组 array。由于 Integer 实现了 Comparable<Integer>,因此可以作为 findMax 方法的参数。
  • 将返回的最大值存储在变量 ret 中,并打印出来。

逻辑关系和总结

  1. 泛型方法findMax 是一个泛型方法,它允许在方法调用时确定类型参数,而不是在类实例化时。这提供了灵活性,因为你可以对不同类型的数组调用同一个方法,只要这些类型实现了 Comparable 接口。

  2. 类型推断:在调用 findMax 方法时,Java 编译器能够根据传入的数组类型自动推断出类型参数 E。因此,在调用 alg2.findMax(array) 时,编译器知道 E 应该是 Integer 类型。这就是为什么你可以直接写 Integer ret = alg2.findMax(array); 而不是显式指定类型参数(如 alg2.<Integer>findMax(array))。

  3. 代码复用:通过使用泛型方法,Alg2 类可以很容易地用于找到任何实现了 Comparable 接口的类型数组中的最大值,从而提高了代码的复用性。

  4. 输出:程序将打印出数组 {1, 2, 3, 4, 5} 中的最大值,即 5

总的来说,这段代码展示了如何使用泛型方法来编写灵活且可重用的代码,以便处理不同类型的数组并找到其中的最大值。

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

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

相关文章

tensorflow学习:错误 InternalError: Dst tensor is not initialized

tensorflow学习&#xff1a;错误 InternalError: Dst tensor is not initialized_dst tensor is not initialized.-CSDN博客https://blog.csdn.net/wanglitao588/article/details/77033659

多元化功能空间,打造影像产业生态圈

国际数字影像产业园的多元化功能空间定位涵盖了从产业实训、研发创新、资产交易、集群发展到孵化服务、大数据支持、产学研合作以及人力资源服务等多个方面&#xff0c;旨在为数字影像产业提供全方位的支持和服务&#xff0c;推动产业的升级和发展。 1、产业实训空间&#xff1…

开发一款直播APP完整指南

直播是一种强大的营销工具&#xff0c;可以让企业与观众进行真实的互动。 根据Grand View Research发布的预测&#xff0c;直播行业规模将从 2021 年的 700 亿美元增长到 2028 年的近 2240 亿美元&#xff0c;七年内增长三倍。 区块链技术和人工智能等技术进步将在未来几年提…

网络协议TCP/IP, HTTP/HTTPS介绍

TCP/IP协议 TCP/IP是一种基于连接的通信协议&#xff0c;它是互联网的基础协议。TCP代表传输控制协议&#xff0c;IP代表Internet协议。虽然这两个协议通常一起提及&#xff0c;但它们实际上是分开的&#xff1a;IP负责在网络中从一台计算机向另一台计算机发送数据包&#xff0…

深度学习21-30

1.池化层作用&#xff08;筛选、过滤、压缩&#xff09; h和w变为原来的1/2&#xff0c;64是特征图个数保持不变。 每个位置把最大的数字取出来 用滑动窗口把最大的数值拿出来&#xff0c;把44变成22 2.卷积神经网络 &#xff08;1&#xff09;conv&#xff1a;卷积进行特征…

圈复杂度.

圈复杂度是衡量代码的重要标准 配置&#xff1a; eslint里面&#xff1a;rules&#xff1a;complexity&#xff1a;[error,10]

ChatBI开源实现: 基于SuperSonic的AI+BI的产品设计

产品起源 为什么要做这样的产品&#xff1f;文章《ChatBI开源实现: AIBI的产品设计》中有介绍 为什么要自己做这样的产品&#xff1f;1、低成本试错&#xff1b;2、未来数据生态入口&#xff1b; 为什么要基于Supersonic做&#xff1f; 开源协议友好&#xff1a;可魔改商用 社区…

深入解析MVCC:多版本并发控制的数据库之道

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起进步&am…

C语言王国——深入自定义类型(联合体、枚举)

目录 一、引言 二、联合体 2.1 联合体类型的声明 2.2 联合体大小的计算 2.3 联合体的实践运用 2.4 用联合体测试大小端字节序 三、枚举 3.1 枚举类型的声明 3.2 枚举类型的特点 四、总结 一、引言 我们刚学完了结构体&#xff0c;相信大家对自定义类型也有了些许了解&…

【代码随想录】【算法训练营】【第50天】 [1143]最长公共子序列 [1035]不相交的线 [53]买卖股票的最佳时机III [392]判断子序列

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 50&#xff0c;周三&#xff0c;无法坚持~ 题目详情 [1143] 最长公共子序列 题目描述 1143 最长公共子序列 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语…

07 - matlab m_map地学绘图工具基础函数 - 绘制等高线

07 - matlab m_map地学绘图工具基础函数 - 绘制等高线 0. 引言1. 关于绘制m_contour2. 关于绘制m_contourf3. 关于绘制m_elev4. 结语 0. 引言 本篇介绍下m_map中添加绘制等高线的一系列函数及其用法&#xff0c;主要函数包括m_elev、m_contour、m_contourf还有一些函数也和绘制…

初探海龟绘图

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 海龟绘图是Python内置的模块&#xff0c;在使用前需要导入该模块&#xff0c;可以使用以下几种方法导入&#xff1a; l 直接使用import语句导入海龟…

LeetCode 算法:将有序数组转换为二叉搜索树 c++

原题链接&#x1f517;&#xff1a;将有序数组转换为二叉搜索树 难度&#xff1a;简单⭐️ 题目 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9]…

[面试题]Zookeeper

[面试题]Java【基础】[面试题]Java【虚拟机】[面试题]Java【并发】[面试题]Java【集合】[面试题]MySQL[面试题]Maven[面试题]Spring Boot[面试题]Spring Cloud[面试题]Spring MVC[面试题]Spring[面试题]MyBatis[面试题]Nginx[面试题]缓存[面试题]Redis[面试题]消息队列[面试题]…

【C语言】操作符(上)

目录 1. 操作符的分类 2. 原码、反码、补码 3. 移位操作符 3.1 左移操作符 3.2 右移操作符 4. 位操作符&#xff1a;&、|、^、~ 5. 单目操作符 6. 逗号表达式 最近准备期末考试&#xff0c;好久不见啦&#xff0c;现在回归—— 正文开始—— 1. …

mulesoft --环境安装与搭建

1.mavenjdkpostman 2.anypoint statdio 下载安装 下载 Anypoint Studio & Mule |骡子软件 (mulesoft.com) 填好基本信息后&#xff0c;会发邮件&#xff0c;在邮件中下载&#xff0c;跳到官网下载 3注册账号 Download Anypoint Studio & Mule | MuleSoft 4.Connect…

详解 ClickHouse 的分片集群

一、简介 分片功能依赖于 Distributed 表引擎&#xff0c;Distributed 表引擎本身不存储数据&#xff0c;有点类似于 MyCat 之于 MySql&#xff0c;成为一种中间件&#xff0c;通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据 ClickHouse 进行分片集群的…

C语言基础——函数(2)

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 文章目录 前言 一、return语句 二、数组做函数参数 三、嵌套调用和链式访问 3.1 嵌套调用 3.2 链式访问 四、函数声明和定义 4.1 单个文件 4.2 多个文件 总结 前言 大家好啊&#xff0c;继我们上一…

优化系统小工具

一款利用VB6编写的系统优化小工具&#xff0c;系统优化、桌面优化、清理垃圾、查找文件等功能。 下载:https://download.csdn.net/download/ty5858/89432367

【UE5.3】笔记1

内容浏览器&#xff1a;存放项目中所有的资源&#xff1a;关卡、蓝图类...... 关卡--Map 至少有一个关卡&#xff0c;可以有多个关卡 -漫游 视野漫游&#xff1a;鼠标右键WASD QE 鼠标滑轮控制摄像机速度 运行&#xff0c;ESC退出运行,快捷键F8不停止运行单独弹出功能 -创…