一文带领大家了解什么是泛型

2023-11-10 09:59

本文主要是介绍一文带领大家了解什么是泛型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

对于泛型!其实大家了解不是很多,在各大高校的学习中,如果你不去深入的了解泛型,老师只是会一水儿过,并不会单独去带领大家了解!!那么,笔者结合自身的学习泛型的想法,结合了一些课件,索性写出了一篇关于泛型的简单博客,来带领大家了解泛型!!

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

                                                                            ----- 来源《Java编程思想》对泛型的介绍。

简而言之,泛型:就是适用于许多许多类型,从代码上讲,就是对类型实现参数化!

在Java语法中,泛型是一个较难的语法,但是,在目前这个博客中,笔者仅仅讲解一部分,目前所接触的只是一丢丢!!后续在数据结构进阶阶段将会深入了解泛型!!

引出泛型??

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

解题思路:

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

 下面请看笔者根据上面两个思路所进行书写的代码:

 


class MyArray {public Object[] obj = new Object[3];public Object getPos(int pos) {return obj[pos];}//返回所对应的pos下标的值public void setObj(int pos , Object val) {obj[pos] = val;}//将数组下标为pos的元素赋值为val
}public class Test {public static void main(String[] args) {MyArray myArray = new MyArray();myArray.setObj(0,10);//存放整型myArray.setObj(1,"hello"); //存放字符串myArray.setObj(2,10.56); //存放double类型 //实现了存储任意类型的数据!}
}

对于上述代码,实现了一个数组,并且该数组内部可以存放任何数据,但是,当我们想要打印该数组中的某下标的值时,列如: double d = myArray.getPos(2); 这样写会进行报错!!

d1e920842cc54a0f870f9e5af585e677.png

当我们进行强制类型转化的时候,double d = (double) myArray.getPos(2); 不会进行报错了!!

b3c9e4570c3c4915ad55f620784c08a5.png

那么疑问又来了,笔者现在定义的数组很小,我们可以看到数组里面存储的数据类型,但是,当我们定义一个很大很大的数组时,当输出某一元素的时候,又怎能知道该下标所对应的元素类型呢??

上述代码实现后,我们可以发现:

  1. 任何类型的数据都可以存放
  2. 获取数据的时候(double d = myArray.getPos(2) ),编译报错,必须进行强制类型转化

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

下面请看笔者的简单的代码:


class MyArray<T> {//public Object[] obj = new Object[3];public T[] obj = (T[])new Object[3];//先这样理解,会有警告//在Java官方不会这样去写public T getPos(int pos) {return obj[pos];}//返回所对应的pos下标的值public void setObj(int pos , T val) {obj[pos] = val;}//将数组下标为pos的元素赋值为val
}public class Test {public static void main(String[] args) {MyArray<Integer> myArray = new MyArray<Integer>();//实列化对象的同时,指定当前泛型类的指定参数类型是Integer//然后就可以进行存储指定的数据类型myArray.setObj(0,10);myArray.setObj(1,78);myArray.setObj(2,99);//myArray.setObj(0,"sjd");//传入不是整型的数据,会进行报错Integer d = myArray.getPos(2);  //不需要强制类型转化}
}

对于上述代码,便是泛型的简单应用,如果您能看懂上述的代码,那么,恭喜你,对于泛型的简单应用,你已经学会了!!

对于泛型,有着下面几个简单的意义:

  1. 存储数据的时候,可以帮助我们进行自动的类型检查
  2. 获取元素的时候,可以帮助我们进行类型转化

上述的两点意义,是在编译的时候,就进行的,因此,泛型是编译时期的一种机制,在运行的时候,没有泛型的概念!!

下面来带领大家走进泛型的语法!!

语法1:

语法1:

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

// 这里可以使用类型参数

}

语法1 的使用情况为

class ClassName<T1,T2,T3…………Tn> {

…………

}

语法2:

语法2:

class 泛型类名称 <类型形参列表> extends 继承类/* 这里可以使用类型参数 */

{

// 这里可以使用类型参数

}

 

class ClassName<T1,T2,T3…………Tn> extends ParentClass<T1> {

// 可以只使用部分类型参数

}

 

对于上述的类名后的<T> 代表占位符,表示当前类是一个泛型类!!

了解一下: ;类型形参一般使用一个大写字母表示,常用的占位符有:

  1. E   表示:Element
  2. K   表示:Key
  3. V   表示:Value
  4. N   表示:Number
  5. T   表示:Type
  6. S,U,V等等,第二,第三,第四个类型

在上述占位符中,E , K , V , T 所应用的比较多!!谨记,其实对于上述的用法,笔者也……尴尬了!

值得注意的是:不可以new 一个泛型类型的数组(语法规定)比如:public T[] obj = new T[3]; 这个就是一个错误的做法!因此,泛型当中,不能实列化一个泛型类型的数组!!!

小结一下,瞬间开心:

  1. 泛型是将数据类型参数化进行传递
    MyArray<Integer> myArray = new MyArray<Integer>();
    
  2. 使用<T>,表示当前类是一个泛型类
  3. 泛型目前为止的优点:数据类型参数化,编译时自动进行检查和转化
  4. 运行的时候,没有泛型的概念,编译完成之后,泛型被擦除为Object(擦除机制仅作了解即可)

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

下面笔者就Java当中,泛型的正确写法,来简单书写一下:(以后将会经常使用)Java官方的写法!

    public Object[] obj = new Object[3];public E getPos(int pos) {return (E)obj[pos];}

 对于上述代码的简单解析:

c8d316104e2e4e9eaaaa747e7515c6bc.png

 上面笔者简单的介绍了一下泛型,那么,就用泛型来实现一个小小的练习题吧!!

实现一个泛型,泛型类里面写一个方法,来求得数组的最大值??

 对于这个方法,我们可以根据最原始的:求数组的最大值的代码,来进行简单改写,然后改编成为我们想要的代码!

抛开泛型,我们在以前在数组中寻找最大值的代码为:

//抛开泛型,我们在以前在数组中寻找最大值的代码为:
class Alg{public int findMax(int[] array) {int max = array[0];for (int i = 1; i < array.length; i++) {if (max < array[i]) {max = array[i];}}return max;}
}

对于上述代码,想必,到目前为止,大家已经了然于胸了吧!!不用在进行讲解了!!

那么,笔者就根据上述的代码进行简单改写一下,然后就出现我们想要的泛型写法了!!请大家仔细对比一下哟!

class Alg<E extends Comparable<E>>{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 Test2 {public static void main(String[] args) {Alg<Integer> alg = new Alg<>();Integer[] array = {1,4,7,29,20,48,21,23};Integer val =alg.findMax(array);System.out.println(val);}
}

上述代码,便是用泛型来实现要求!!代码的运行结果为:

115311330f1b430aa92c7b6f75ead7f7.png

简单解析一下吧!:

ed08147d7b27431893c70ef137f3594c.png

上述代码是一个泛型类,那么有没有泛型方法呢??那么,请看笔者下面的代码吧!来带领大家用泛型方法来实现一下题目需求!!

//泛型方法
class Alg{public <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 Test2 {public static void main(String[] args) {Alg alg = new Alg();Integer[] array = {1,4,7,29,20,48,21,23};Integer val =alg.findMax(array);System.out.println(val);}
}

上述的代码,就是用泛型方法来实现,求得数组中的最大值

代码的运行结果也是正确的!!

99940a4b327f45cdbc9d6598bbd22828.png

 对于这个方法,必须通过对象的引用才能调用!!

思考一下,如果我们不想通过对象的引用,那么我们应该怎么办??

很简单,将其改为静态(static)修饰的的不就行了吗??

请看笔者代码:

//泛型的静态方法
class Alg{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 Test2 {public static void main(String[] args) {Integer[] array = {1,4,7,29,20,48,21,23};Integer val =Alg.findMax(array);System.out.println(val);}
}

上述代码,就是用静态(static)来修饰的!!

静态方法不依赖于对象,可以通过类名进行访问!!

对于此篇博客,有不懂的各位老铁,欢迎来咨询

 

 

这篇关于一文带领大家了解什么是泛型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例

电脑密码怎么设置? 一文读懂电脑密码的详细指南

《电脑密码怎么设置?一文读懂电脑密码的详细指南》为了保护个人隐私和数据安全,设置电脑密码显得尤为重要,那么,如何在电脑上设置密码呢?详细请看下文介绍... 设置电脑密码是保护个人隐私、数据安全以及系统安全的重要措施,下面以Windows 11系统为例,跟大家分享一下设置电脑密码的具体办php法。Windo

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.

一文带你搞懂Nginx中的配置文件

《一文带你搞懂Nginx中的配置文件》Nginx(发音为“engine-x”)是一款高性能的Web服务器、反向代理服务器和负载均衡器,广泛应用于全球各类网站和应用中,下面就跟随小编一起来了解下如何... 目录摘要一、Nginx 配置文件结构概述二、全局配置(Global Configuration)1. w

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

速了解MySQL 数据库不同存储引擎

快速了解MySQL 数据库不同存储引擎 MySQL 提供了多种存储引擎,每种存储引擎都有其特定的特性和适用场景。了解这些存储引擎的特性,有助于在设计数据库时做出合理的选择。以下是 MySQL 中几种常用存储引擎的详细介绍。 1. InnoDB 特点: 事务支持:InnoDB 是一个支持 ACID(原子性、一致性、隔离性、持久性)事务的存储引擎。行级锁:使用行级锁来提高并发性,减少锁竞争

PHP: 深入了解一致性哈希

前言 随着memcache、redis以及其它一些内存K/V数据库的流行,一致性哈希也越来越被开发者所了解。因为这些内存K/V数据库大多不提供分布式支持(本文以redis为例),所以如果要提供多台redis server来提供服务的话,就需要解决如何将数据分散到redis server,并且在增减redis server时如何最大化的不令数据重新分布,这将是本文讨论的范畴。 取模算法 取模运