目录

​编辑

1.泛型

1.1Object类引出泛型概念

2.泛型语法

2.1泛型编写代码

3.泛型的机制

3.1擦除机制

4.泛型的上界

4.1泛型上界的语法

4.2泛型上界的使用

5.泛型方法

5.1泛型方法语法

5.2泛型方法的使用

1.泛型

一般的类和方法中,只能使用具体的代码来实现同一种类型数据的操作。比如一个数组里面存储的是同一种类型,这种存储方式太过于死板。因此JDK1.5引入了新的语法:泛型,通俗的来讲泛型就是多种数据类型(泛滥),从代码上来说就是实现了不同类型之间的存储,因此当我们想要存储各种各样的数据时,我们会使用到泛型。


1.1Object类引出泛型概念

在泛型之前,我们在Object类中学到了,所有类的父类都是Object类,因此我们能把一个数组设置为Object类型呢,这样就能达到数组里面存放各种各样的元素。所以我们可以这样去写代码:

class MyArray {//Object类型数组Object[] arr = new Object[3];public void show() {//分别初始化三种不同类型的数据arr[0] = 1;arr[1] = 1.2;arr[2] = "abc";//遍历arr数组for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}}
}
public class Test {public static void main(String[] args) {MyArray myArray = new MyArray();myArray.show();}
}

运行后输出:

以上代码是可以很好的运行,因为我们直接初始化了Object类中的元素。当我们使用get、set方法来实现时就会发现不同处。

class MyArray {//Object类型数组public Object[] arr = new Object[3];//提供get方法public Object getPos(int pos) {return this.arr[pos];}//提供set方法public void setArr(int pos,Object value) {this.arr[pos] = value;}
}public class Test {public static void main(String[] args) {MyArray myArray = new MyArray();//分别设置了三种不同类型的元素myArray.setArr(0,1);myArray.setArr(1,1.2);myArray.setArr(2,"abc");//分别输出了三种不同类型的元素System.out.println(myArray.getPos(0));System.out.println(myArray.getPos(1));//输出字符类型时,报错System.out.println(myArray.getPos(3));}
}

运行后输出:

我们发现,当我往数组中添加了一个字符串时就会出现异常。所以,Object在存储不同类型的时候

还是会出现错误。因此,我们可以想到既然不让我存不同类型的数据,那么我就存同一种类型的数据就好了,这时我们就可以用到泛型。它可以将不同类型数据存储在不同的对象中,但在不同的对象中每一个元素的类型是相同的。


2.泛型语法

(1)语法1

//泛型类语法格式
class 泛型类名称<类型形参列表> {//内容
}
//泛型类中形参可为多个
class ClassName<T,S,B,U> {//内容
}

上述代码中,我们可以看到泛型类与普通类多了一个<>其余并无太大差异,注意<>内可写多个参数。 

(2)语法2 

//泛型类继承类或泛型类
class 泛型类名称<类型形参列表> extends 类名 {}
//泛型类继承泛型类
class ClassName1<T,S,B,U> extends ClassName2<T> {}

上述代码,表示了泛型类可以继承一个普通类,也可以继承一个泛型类


2.1泛型编写代码

因此,我们可以这样去编写一段泛型代码:

class MyArray<T> {//创建一个泛型数组T[] arr= (T[])new Object[3];//get方法public T getPos (int pos) {return this.arr[pos];}//set方法public void setArr (int pos,T value) {this.arr[pos] = value;}
}
public class Test {public static void main(String[] args) {//myArray1对象设置int类型数据MyArray<Integer> myArray1 = new MyArray<>();myArray1.setArr(0,1);myArray1.setArr(1,2);myArray1.setArr(2,3);//myArray2对象设置String类型数据MyArray<String> myArray2 = new MyArray<>();myArray2.setArr(0,"a");myArray2.setArr(1,"b");myArray2.setArr(2,"c");//通过get方法输出各个下标元素System.out.print(myArray1.getPos(0)+" ");System.out.print(myArray1.getPos(1)+" ");System.out.print(myArray1.getPos(2)+" ");System.out.print(myArray2.getPos(0)+" ");System.out.print(myArray2.getPos(1)+" ");System.out.print(myArray2.getPos(2));}
}

运行后输出:

以上代码,就是泛型的一个体现,我们要想设置什么类型的数据就在<>里面设置什么类型的包装类即可。上述代码中相信get和set方法对于大家来说不是很难理解,但很多小伙伴第一件见这种代码,可能有些问题不太清楚,因此我来做出解释:

  1. 类名后面的<T>代表着占位符,表示着当前类为一个泛型类。<>里面的内容可以任意填写,你可以输入E、K、N等等。注意应当填写见名思意内容如T代表着type,N代表着number。
  2. T[] arr = new T[3];是不可行的,因为泛型不能直接new一个数组,但是我们可以强制类型转换如T[] arr = (T[]) new Object[];。
  3. 实例化泛型类时应当在<>只能是引用类型不得是基本类型因此通常我们填写包装类,并且该对象中值的类型要一致。
  4. 实例化泛型类对象时,前面<>内内容不得省略,后面<>内容可以省略。如:Array<String> array = new Array<> ();。

3.泛型的机制

泛型是一种运行时的机制,它会在编译时给我们指出一些错误,也会在获取元素时帮助我们进行强制类型转换。

(1)编译时指出错误

    public static void main(String[] args) {MyArray<int> myArray = new MyArray<>();}

报错:

上述报错,代表着泛型类中<>内容类型不能被定义为int。在上文中我们知道了,泛型类<>里面得是一个引用类型,因此int不能作为<>内参数。再比如以下代码:

    public static void main(String[] args) {MyArray<Integer> myArray = new MyArray<>();myArray.setArr(0,"abc");}

报错:

上述代码,我们在给set方法传参的时候传了一个String类型的数据,并不符合myArray这个对象的属性。因此造成报错现象。


(2)帮助进行强制类型转换

class MyArray<T> {//创建一个泛型数组public Object[] arr = new Object[3];//get方法public T getPos (int pos) {return (T)arr[pos];}//set方法public void setArr (int pos,T value) {arr[pos] = value;}
}
public class Test {public static void main(String[] args) {//Integer泛型类MyArray<Integer> myArray = new MyArray<>();//自动帮我们进行类型转换了myArray.setArr(0,23);//String泛型类MyArray<String> myArray1 = new MyArray<>();//自动帮我们进行类型转换了myArray1.setArr(0,"abc");}
}

以上代码中,set方法形参列表第二个参数value为泛型T类型,但是在main方法中。我在给setArr方法传参的时候,直接传了一个整型和一个字符串。编译器并没有报错,那是因为泛型自动帮助我们进行了强制类型转换,也就是把T类型分别转成了整型和字符串型。


3.1擦除机制

通过上述讲解我们知道了,泛型会在我们编译时显示错误会帮助我们强制类型转换。表明了泛型是一种编译时的机制。那我们的泛型在运行后会是什么样呢?其实我们的泛型在编译后会被擦除为Object类型。

class MyArray<T> {//创建一个泛型数组T[] arr= (T[])new Object[3];//get方法public T getPos (int pos) {return this.arr[pos];}//set方法public void setArr (int pos,T value) {this.arr[pos] = value;}
}
public class Test {public static void main(String[] args) {//实例一个泛型为Integer类的对象MyArray<Integer> myArray = new MyArray<>();myArray.setArr(0,1);myArray.setArr(1,2);//实例一个泛型为String类的对象MyArray<String> myArray1 = new MyArray<>();myArray1.setArr(0,"abc");myArray1.setArr(1,"def");}
}

调试后: 

我们可以发现明明我们在创建数组的时候是这样的 T[] arr= (T[])new Object[3];,但编译器后台自动给我们编程了Object类型。因此,我们可以知道运行后编译器会擦除泛型类型给我们转换为Object类型。

所以,我们可以这样创建一个泛型数组:

class MyArray<T> {//创建一个泛型数组public Object[] arr = new Object[3];//get方法public T getPos (int pos) {return (T)arr[pos];}//set方法public void setArr (int pos,T value) {arr[pos] = value;}
}

上述代码对数组进行一个初始化才是地道的初始化,而原来的T[] arr = (T[]) new T[3];并不是很地道,但也能达到效果。


4.泛型的上界

有一程序要求通过泛型找出一个数组的最大值,因此有以下代码:

class MaxArray<T> {public void findMax(T[] arr) {T max = arr[0];for (int i = 0; i < arr.length; i++) {if (max > arr[i]) {max = arr[i];}}System.out.println(max);}
}
public class Test {public static void main(String[] args) {MaxArray<Integer> maxArray =new MaxArray<>();Integer[] integers = {1,3,4,5,10,8,9,5,20};maxArray.findMax(integers);}
}

运行后报错:

上述代码报错原因是if里面的判断,当基本类型之间进行判断时可以使用算术符,当基本类型与引用类型之间进行判断时我们就得使用Comparable方法来判断。但是我们发现上述泛型并没有使用Comparable接口,因此我们可以使泛型继承这个接口就可以实现该操作,那么这样一个操作就代表着泛型上界这样一个概念。


4.1泛型上界的语法

class 泛型类<参数列表 extems 类型边界> {//内容}

以上代码就是泛型类中参数类型继承一个类型边界的创建,实例:

class Array<T extends Number> {//内容
}

只接受 Number 的子类型作为 T 的类型实参,因此只有关于Number的子类型我们能使用 ,比如Integer。String类型就不能。如:

class Num<T extends Number> {//以下三个都行Num<Integer> num1 = new Num<>();Num<Byte> num2 = new Num<>();Num<Double> num3 = new Num<>();//会报错Num<String> num4 = new Num<>();
}

报错:

jdk-8帮助手册中描述了以下类为Number子类。


4.2泛型上界的使用

还是4.1中那段代码,我们既然不能使用<来比较一个基本类型和一个引用类型,那我们就使T类型继承Comparable接口。

class MaxArray<T extends Comparable<T>> {public void findMax(T[] arr) {T max = arr[0];for (int i = 0; i < arr.length; i++) {//使用了Comparable接口中的compareTo方法if (max.compareTo(arr[i]) < 0) {max = arr[i];}}System.out.println(max);}
}
public class Test {public static void main(String[] args) {MaxArray<Integer> maxArray =new MaxArray<>();Integer[] integers = {1,3,4,5,10,8,9,5,20};maxArray.findMax(integers);}
}

运行后输出:

以上代码中泛型类中T类型继承了Comparable接口,因此if判断里面可以使用Comparable接口中的compareTo方法。此方法返回的值小于0代表前者比后者小,返回值等于0代表前者与后者相等,返回值大于0代表前者比后者大。


5.泛型方法

在上面我们学习到了泛型类的使用,那么泛型也是有方法的。我们可以把一个普通方法变成泛型方法去使用,那么泛型方法具体有什么用呢?下面我就来讲解:


5.1泛型方法语法

泛型方法的语法格式为:方法限定修饰符<类型形参列表> 返回值类型 方法名称(参数列表){ //内容 }。

实例:

public <T> T maxNumber(T[] arr) {//内容}

5.2泛型方法的使用

求数组中的最大数:

class Array {public <T extends Comparable<T>> T maxNum(T[] num){T max = num[0];for (int i = 0; i < num.length; i++) {if (max.compareTo(num[i]) < 0) {max = num[i];}}return max;}
}
public class Test {public static void main(String[] args) {Array array = new Array();Integer[] arr = {1,23,4,5,6,7};Integer max=array.<Integer>maxNum(arr);System.out.println(max);}
}

运行后输出:

以上代码展示了泛型方法的使用,我们可以看到泛型方法的语法比较抽象,这就是泛型方法的难点之处。


本期博客到这里就结束了,感谢各位的阅读。

下期预告:ArrayList与顺序表

数据结构 | 泛型 | 擦除机制| 泛型的上界相关推荐

  1. 泛型擦除机制、自定义注解、代理、反射

    一.泛型擦除机制 1.泛型只在编译阶段限制,之后会擦除.    二.注解 1.注解介绍   2.JDK自带注解   3.元注解  @Target     @Retention 转载于:https:// ...

  2. 深入理解 Java 泛型擦除机制

    我们都知道 Java 中的泛型可以在编译期对类型检查,避免类型强制转化带来的问题,保证代码的健壮性.不同语言对泛型的支持也不一样,Java 中的泛型类型在编译期会擦除,下面一个例子可以证明这一点: p ...

  3. 什么是泛型,为什么要使用泛型? 泛型类和泛型方法的实现以及限定通配符的使用。什么是泛型擦除,为什么有泛型擦除,泛型擦除到底是怎么实现的

    1. 泛型的定义和意义 1.1 什么叫泛型? 泛型,顾名思义就是广泛的类型,专业术语为"参数化类型":当我们创建对象时没指定类型,任何引用类型都可以使用,兼容多种数据类型.如果是基 ...

  4. java 泛型 擦除_Java泛型和类型擦除

    一 前言:初识泛型 废话不说,先来看一段代码: public class Holder { private Object data; public Holder(Object data ){ this ...

  5. 【Java 泛型】使用上下边界通配符解决泛型擦除问题

    文章目录 前言 一.使用上边界通配符示例 二.分析字节码的附加信息 前言 上一篇博客 [Java 泛型]泛型用法 ( 泛型编译期擦除 | 上界通配符 <? extends T> | 下界通 ...

  6. java 获取泛型_聊聊Java泛型擦除那些事

    >版权申明]非商业目的注明出处可自由转载 博文地址:https://blog.csdn.net/ShuSheng0007/article/details/89789849 出自:shushen ...

  7. 十分钟理解Java泛型擦除

    泛型信息只存在于代码编译阶段,但是在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉,专业术语叫做类型擦除. 今天我们来讲解泛型中另一个重要知识点--泛型擦除! 泛型擦除概念 泛型信 ...

  8. 泛型:了解泛型与通配符

    一.引出泛型 1.什么是泛型: 2.代码测试 二.泛型类的使用 1.语法 2.改写上述代码 三. 泛型如何编译的) 3.1.擦除机制 3.2.为什么不能实例化泛型类型数组 四.泛型的上界 1.Numb ...

  9. 3.1_19 JavaSE入门 P18 【泛型】各类泛型对象、通配符、类型擦除

    相关链接 Excel目录 目录 P18 [泛型]各类泛型对象.通配符.类型擦除 1 什么是泛型 2 泛型类.接口库 2.1 泛型类定义语法 2.2 常用泛型标识 2.3 使用语法 2.4 泛型类注意事 ...

最新文章

  1. 程序员,应该掌握的英语词汇
  2. python快速编程入门课后简答题答案-Python编程:从入门到实践(课后习题8)
  3. k8s部署dashboard
  4. python antlr_使用ANTLR在5分钟内用Java解析任何语言:例如Python
  5. 机器学习导论 与数学分析
  6. ElasticSearch bool过滤查询
  7. 面试官系统精讲Java源码及大厂真题 - 44 场景实战:ThreadLocal 在上下文传值场景下的实践
  8. xcode 工程没有模拟器_Xcode只允许我运行iOS设备(没有模拟器)
  9. base——JRE和JDK的区别【转】
  10. 疫情下技术人的宅家指南
  11. 学到了林海峰,武沛齐讲的Day17完-6 文件操作
  12. VSS无法访问 (0x80072EFD) 转载
  13. 巨头发力,社区电子商务发展加速
  14. shape的基本用法
  15. php 405错误怎样重现,phpmyadmin出现405错误怎么办?
  16. 【英语语法入门】 第29讲 情态动词的否定和疑问
  17. 构造方法--带参构造方法
  18. cmwap和cmnet的区别
  19. 程序员自我修炼:《匠艺整洁之道》读书总结
  20. 揭秘2023年高新软件技术

热门文章

  1. Mand Mobile 快速上手
  2. tar,gunzip,gzip,unzip和zgrep 命令的用法和区别
  3. 7-2 国际贸易统计
  4. C++仿马里奥小游戏(Easy库)
  5. thinkphp lang命令执行(QVD-2022-46174)漏洞复现
  6. 中国社会科学院与美国杜兰大学金融管理硕士——所有期待的未来正在路上
  7. 解决快播5.1提示“根据相关法律法规,该网站不可点播”的方法(无需卸载掉5.1版本)。 [复制链接]
  8. 推荐几本数据分析和数据挖掘类的好书
  9. matlab 判断语句是否为真,matlab 条件判断语句不生效
  10. 开篇:为什么学习 Go 语言