Java之初始泛型

2024-08-31 19:44
文章标签 java 初始 泛型

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

1 包装类

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

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

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

1.2 装箱和拆箱

public static void main(String[] args) {int i1=10;Integer i2=i1;//自动装箱Integer i3 = Integer.valueOf(i1);//主动装箱Integer j1=10;int j2=j1;//自动拆箱int j3=j1.intValue();//主动拆箱}

可以看到在使用过程中,装箱和拆箱带来不少的代码量,所以为了减少开发者的负担,java 提供了自动机制。
我们通过反汇编来了解一下自动装箱和自动拆箱
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
了解了装箱和拆箱,我们来通过一段代码来深度了解一下:

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

在这里插入图片描述
为了解决这个问题,我们从Integer的底层代码来思考
在这里插入图片描述
得出结论:
在区间[-128,127)内直接比较两数大小,
在区间外产生了新的对象,比较的产生新对象的地址。

2 什么是泛型

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

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

3 引出泛型

实现一个类,类中包含一个数组成员,使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个下标的值?
我们以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] strs = new String[10];
所有类的父类,默认为Object类。数组是否可以创建为Object?

class MyArray {public Object[] objects=new Object[10];public void setObjects(int pos,Object val){this.objects[pos]=val;}public Object getPosval(int pos){return this.objects[pos];}
}
public class TestGenerics {public static void main(String[] args) {MyArray myArray=new MyArray();myArray.setObjects(0,1);myArray.setObjects(1,3.14);myArray.setObjects(2,"xiaoming");myArray.setObjects(3,"true");System.out.println(myArray.getPosval(0));System.out.println(myArray.getPosval(1));String s=(String) myArray.getPosval(2);System.out.println(s);  //虽然可以存放任何类型数据 ,但是在取出时必须强制转换,非常的麻烦}
}

在这里插入图片描述

我们发现使用Object修饰的数组确实可以存放不同类型的数据,但是引发了一个新的问题
虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,
我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。

3.1 语法

class 泛型类名称<类型形参列表> {// 这里可以使用类型参数
}class ClassName<T1, T2, ..., Tn> {  
}

对上述代码进行改写如下:

class MyArray<T>{类名后的<T>代表占位符,表示当前类是一个泛型类public Object[] objects=new Object[10];public void setVal(int pos,T val){this.objects[pos]=val;}public T getPosval(int pos){return (T)this.objects[pos];}
}
public class TestGenerics {public static void main(String[] args) {MyArray<Integer> myArray1=new MyArray();myArray1.setVal(0,1);myArray1.setVal(1,2);MyArray<Double> myArray2=new MyArray<>();myArray2.setVal(0,3.14);MyArray<String> myArray3=new MyArray<>();myArray3.setVal(0,"xiaoming");System.out.println(myArray1.getPosval(0));System.out.println(myArray1.getPosval(1));System.out.println(myArray2.getPosval(0));System.out.println(myArray3.getPosval(0));}}

在这里插入图片描述

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 保留的机制
下面的类型擦除部分,我们也会讲到编译器是如何使用裸类型的。

6 泛型如何编译的

6.1 擦除机制

那么,泛型到底是怎么编译的?这个问题,也是曾经的一个面试问题。泛型本质是一个非常难的语法,要理解好他还是需要一定的时间打磨。
在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。
Java的泛型机制是在编译级别实现的。编译器生成的字节码在运行期间并不包含泛型的类型信息。

7 泛型的上界

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

7.1 语法

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

7.2 示例

class Alg<T extends Comparable<T> >{}

例如:找到数组中的最大值的代码如下

class Alg1<T extends Comparable<T> >{public T finMax(T[] array){T max = array[0];for (int i = 0; i <array.length ; i++) {//if(max<array[i]){//泛型类不能直接通过> < ==来比较if(max.compareTo(array[i])<0) {max=array[i];}}return max;}
}public class TestGenerics {public static void main(String[] args) {Alg1 alg=new Alg1();Integer[] array = {1,2,3,14,5};System.out.println(alg.finMax(array));}
}

8 泛型方法

8.1 定义语法

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

8.2 示例

//泛型方法
class Alg2{public<T extends Comparable> T finMax(T[] array){T max = array[0];for (int i = 0; i <array.length ; i++) {//if(max<array[i]){if(max.compareTo(array[i])<0) {max=array[i];}}return max;}
}
//泛型方法
// //静态的泛型方法 需要在static后用<>声明泛型类型参数
class Alg3{public static <T extends Comparable> T finMax(T[] array){T max = array[0];for (int i = 0; i <array.length ; i++) {//if(max<array[i]){if(max.compareTo(array[i])<0) {max=array[i];}}return max;}
}

这篇关于Java之初始泛型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Java多线程父线程向子线程传值问题及解决

《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

java父子线程之间实现共享传递数据

《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J