【数据结构】--初识泛型

2024-09-08 00:52
文章标签 初识 数据结构 泛型

本文主要是介绍【数据结构】--初识泛型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 包装类

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

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

在这里插入图片描述
除了 Integer 和 Character, 其余基本类型的包装类都是首字母大写。

1.2 (自动)装箱和(自动)拆箱

装箱(装包): 把 基本数据类型 变为 包装类类型 的过程 叫做装箱。
在这里插入图片描述

反汇编指令:javap -c Test

也可以转换成不同的类型:
在这里插入图片描述
拆箱(拆包): 把 包装类类型 变为 基本数据类型 的过程 叫做拆箱。
在这里插入图片描述

int i = 10;
Integer ii = i; // 自动装箱
Integer ij = (Integer)i; // 自动装箱
int j = ii; // 自动拆箱
int k = (int)ii; // 自动拆箱

在这里插入图片描述

面试题目:
下列代码输出什么,为什么?

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);
}

解析:在这里插入图片描述
思考问题抓住主要矛盾!!!!!!!!

2. 什么是泛型

一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。----- 来源《Java编程思想》对泛型的介绍。
泛型是在JDK1.5引入的新的语法,通俗讲,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化

3. 引出泛型

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

思路:

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

代码示例:

class MyArray {
public Object[] array = new Object[10];
public Object getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,Object val) {
this.array[pos] = val;
}
}
public class TestDemo {
public static void main(String[] args) {
MyArray myArray = new MyArray();
myArray.setVal(0,10);
myArray.setVal(1,"hello");//字符串也可以存放
String ret = myArray.getPos(1);//编译报错
System.out.println(ret);
}
}

问题:

以上代码实现后 发现

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

3.1 语法

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

在这里插入图片描述
在这里插入图片描述
注意:
在这里插入图片描述

了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型

4. 泛型类的使用

4.1 语法

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

4.2 示例

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

4.3 类型推导(TypeInference)

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

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

5. 裸类型(RawType)(了解)

在这里插入图片描述
注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制
下面的类型擦除部分,我们也会讲到编译器是如何使用裸类型的。
小结:

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

6. 泛型如何编译的

6.1 擦除机制

在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。
Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。

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 的子类型

说明:
在Java中,Number 是一个抽象类,位于 java.lang 包中。它是所有数值类型的超类(父类),这些数值类型包括 Byte、Short、Integer、Long、Float、Double。

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

复杂示例:

class Person implements Comparable<Person>{@Overridepublic int compareTo(Person o) {return 0;}
}//泛型类
class Alg<E extends Comparable<E>> {
//此时继承了Compareble  只有继承了Comparable类才能使用comparaTo方法public E findMax(E[] array) {E max = array[0];for (int i = 1; i < array.length; i++) {//if(max < array[i]) {//报错//我们并不知道E的类型是什么,如果没有规定E的类型,//Java会把E擦除成object,不管怎么样,擦除成object一定是一个引用类型//引用类型不能直接通过大于号,小于号进行大小比较,因为它不是基本数据类型//object中并没有实现任何接口 在这个泛型类继承了Comparable类时,//重写了comparaTo方法,就可以直接使用comparaTo来进行比较if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}//泛型方法
class Alg2 {public<E extends Comparable<E>> E findMax(E[] array) {E max = array[0];for (int i = 1; i < array.length; i++) {//if(max < array[i]) {if(max.compareTo(array[i]) < 0) {max = array[i];}}return max;}
}//静态的泛型方法(static)
class Alg3 {public static <E extends Comparable<E>>  E findMax(E[] array) {E max = array[0];for (int i = 1; i < array.length; i++) {//if(max < array[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,45,5,6,8};int ret = Alg3.findMax(array);//不需要new一个新对象,可以通过类名直接调用findmaxSystem.out.println(ret);}public static void main2(String[] args) {Alg2 alg2 = new Alg2();//alg2是一个方法,不会像泛型类一样在实例化的时候传一个类型(泛型参数)Integer[] array = {1,2,3,4,45,5,6,8};int ret = alg2.findMax(array);//问:在调用findmax时,是怎么知道当前是一个integer类型呢?//答:会根据传入的array的类型,推测出来这个E到底是什么//int ret = alg2.<Integer>findMax(array);System.out.println(ret);}public static void main1(String[] args) {Integer[] array = {1,2,3,4,45,5,6,8};Alg<Integer> alg = new Alg<>();int a = alg.findMax(array);//Integer中本身就已经实现了comparable接口,此时就可以直接用System.out.println(a);Alg<Person> alg23 = new Alg<Person>();}
}

8. 泛型方法

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

8.2 示例

看7.2中的复杂示例,三种方式结合着看,注意理解!!!

这篇关于【数据结构】--初识泛型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1146657

相关文章

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

Linux操作系统 初识

在认识操作系统之前,我们首先来了解一下计算机的发展: 计算机的发展 世界上第一台计算机名叫埃尼阿克,诞生在1945年2月14日,用于军事用途。 后来因为计算机的优势和潜力巨大,计算机开始飞速发展,并产生了一个当时一直有效的定律:摩尔定律--当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍。 那么相应的,计算机就会变得越来越快,越来越小型化。

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre

Python 内置的一些数据结构

文章目录 1. 列表 (List)2. 元组 (Tuple)3. 字典 (Dictionary)4. 集合 (Set)5. 字符串 (String) Python 提供了几种内置的数据结构来存储和操作数据,每种都有其独特的特点和用途。下面是一些常用的数据结构及其简要说明: 1. 列表 (List) 列表是一种可变的有序集合,可以存放任意类型的数据。列表中的元素可以通过索

浙大数据结构:04-树7 二叉搜索树的操作集

这道题答案都在PPT上,所以先学会再写的话并不难。 1、BinTree Insert( BinTree BST, ElementType X ) 递归实现,小就进左子树,大就进右子树。 为空就新建结点插入。 BinTree Insert( BinTree BST, ElementType X ){if(!BST){BST=(BinTree)malloc(sizeof(struct TNo

Java泛型类型解析

解析泛型类型 获取字段泛型类型 **java.lang.reflect.Field#getGenericType**: 作用:返回字段的泛型类型。返回类型:Type。如果字段是一个泛型类型,这个方法将返回一个表示这个泛型类型的 Type 对象,比如 ParameterizedType,TypeVariable 等等。如果字段不是泛型类型,这个方法将返回字段的具体类型,即 Class 对象。示例

【数据结构入门】排序算法之交换排序与归并排序

前言         在前一篇博客,我们学习了排序算法中的插入排序和选择排序,接下来我们将继续探索交换排序与归并排序,这两个排序都是重头戏,让我们接着往下看。  一、交换排序 1.1 冒泡排序 冒泡排序是一种简单的排序算法。 1.1.1 基本思想 它的基本思想是通过相邻元素的比较和交换,让较大的元素逐渐向右移动,从而将最大的元素移动到最右边。 动画演示: 1.1.2 具体步