Java认识泛型类

一、包装类

认识泛型类之前先来认识一下包装类

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

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

514bc8b4f8ac42f7a529af966a662c3b.png

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

        2、 装箱和拆箱

装箱:把基本类型变成引用类型

 public static void main(String[] args) {//包装类int a = 10;Integer ii2=Integer.valueOf(a);//显示装箱Integer ii=a;//自动装箱,底层调用也是valueOf}

拆箱:把引用类型变成基本类型

 public static void main(String[] args) {Integer ii=10;//装箱int a = ii;//自动拆箱int aa = ii.intValue();//手动拆箱double d=ii.doubleValue();}

问题:看下列代码输出结果是什么

 public static void main(String[] args) {Integer a = 127;Integer b = 127;System.out.println(a == b);Integer c = 128;Integer d = 128;System.out.println(c == d);}

运行结果 

3102f98b79d74d98828db3e772812285.png

我们发现都是比较Integer类型的数据,那么为什么会出现结果不同的情况呢?

首先因为上面都是装箱操作,底层调用valueOf方法,所以来看看这个方法是怎么实现的

22373c5e49a3492ab5b78ab729781f99.png

71a771333bcf4935aef02fe1ab1db7b4.pnglow是-128

ab51b18b22dd479f9a480c2589d6e8fd.pnga32b2cd50b3841d6bf3d6aefe75e8bd0.pnghigh是127

总共256个数字,因此数组大小是256

 if语句判断是如果i是在某一个范围内就数组取值,相反如果不在范围内就实例化一个新的对象

a和b都是127,在数组范围内,可以直接去取对应数组值,c和d虽然都是128,但是不在数组范围内,因此都会实例化一个新对象,所以结果不同

二、泛型

        1、什么是泛型

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

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

总的来说泛型主要做的是把类型参数化,意味着可以传指定的类型参数

        2、如何实现

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

首先我们想到的是Object类,可以接受任何数据类型

class MyArray{public Object[] array=new Object[10];public void setValue(int pos,Object x) {array[pos] = x;}public Object getVal(int pos){return (T)array[pos];}}
 public static void main(String[] args) {MyArray myArray = new MyArray();myArray.setArray(0,1);myArray.setArray(1,"hello");myArray.setArray(2,2.3);String s = (String)myArray.getVal(1);//需要强转System.out.println(s);}

虽然任何类型数据都可以存放,但1号下标本身就是字符串,编译出现报错。必须进行强制类型转换,并且数据多了的话就不知道某个位置的数据是什么类型,不知道强转为什么。

所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象,让编译器去做检查。此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。

//<T>代表当前类是泛型类
//E表示Element
//K表示key
//V表示value
//N表示Number
//T表示Typeclass MyArray<T>{public Object[] array=new Object[10];//以后这么写// public T[] array = (T[]) new Object[10];勉强可以,但是也会存在问题//public T[] ts = new T[5];不对的public void setArray(int pos,T x) {//放T类型的xarray[pos] = x;}public T getVal(int pos){return (T)array[pos];//强转成T类型}
}

使用方法:类名后面写<>,里面写要传给这个类的类型

 public static void main(String[] args) {MyArray<Integer> myArray= new MyArray<>();//当编译器可以根据上下文推导出类型实参时,可以省略类型实参的填写myArray.setArray(0,2);Integer x = myArray.getVal(0);//尖括号里只能放类类型,不能放基本类型,例如int,char,boolean等MyArray<String> myArray1 = new MyArray<>();myArray1.setArray(1,"hello");System.out.println(myArray1.getVal(1));}

用泛型方法优点:

1、编译的时候:每次存储数据的时会自动检查你存入的数据是不是和你指定的数据类型一样。

2、接收得到的值时,不需要我们进行强转。

注意:

1、运行的时候没有泛型这样的概念,代码在JVM中运行,也就是说在JVM中没有泛型的概念。

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

        3、泛型如何编译

擦除机制:在编译的过程当中,将所有的T替换为Object这种机制。

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

问题:为什么T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = newObject[5]吗?

答:编译的时候不知到T是什么类型的数组,只有擦完之后才知道,所以new数组是要写具体的数组类型,并且java规定new数组要写具体类型。

另一种存在问题的创建数组写法:实例化泛型类型的数组

Object类是所有类的父类,但是Object[]不是所有数组的父类,Object[]不是Stri(ng的父类,但Object是String的父类,因此下面代码中的getArray()只能通过Object[]接收。

class MyArray<T>{//实例化泛型类型的数组public T[] array = (T[]) new Object[10];//勉强通过但是也有问题,就是下面所写的问题public void setValue(int pos,T x) {array[pos] = x;}public T getVal(int pos){return (T)array[pos];//强转成T类型}public T[] getArray(){return (T[])array;}
}    public static void main3(String[] args) {MyArray<String> myArray = new MyArray<>();String[] strings = (String[]) myArray.getArray();//错误//Object类是所有类的父类,但是Object[]不是所有数组的父类,Object[]不是String的父类,但Object是String的父类//只能通过Object[]接受Object[] strings1 = myArray.getArray();//只能使用Object[]接收}

三、泛型的上界

        1、定义泛型类

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

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

 只接受 Number 的子类型作为 E 的类型实参或者是Number自己

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

 例:定义一个泛型类,找到数组中的最大值

class Alg<T extends Comparable<T>>{//T实现了Comparable接口,就可以使用compareTo和T类型的max比较public T findMax(T[] array){T max = array[0];for (int i = 0; i < array.length; i++) {if(array[i].compareTo(max)>0){//引用类型不能直接比较,需要用Comparable<>max = array[i];}}return max;}
}  public static void main4(String[] args) {//泛型的上界//定义一个泛型类,找到数组中的最大值Alg<Integer> alg = new Alg<>();//Integer实现了Comparable接口Integer[] array = {1,2,3,4};//装箱Integer x = alg.findMax(array);System.out.println(x);}

        2、泛型方法 

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

class Alg2{public <T extends Comparable<T>>T findMax(T[] array){T max = array[0];for (int i = 0; i < array.length; i++) {if(array[i].compareTo(max)>0){//引用类型不能直接比较,需要用Comparable<>max = array[i];}}return max;}//泛型方法,也可以是静态的就不需要实例化对象了
}
public class test {public static void main(String[] args) {Alg2 alg2 = new Alg2();Integer[] array = {1,2,3,4,5};Integer x = alg2.findMax(array);Integer x2 = alg2.<Integer>findMax(array);//<Integer>可以省略System.out.println(x);}

 四、裸类型

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

MyArray list = new MyArray();

我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制下面的类型擦除部分。

 

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

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

相关文章

学点Java_Day12_JDBC

1 JDBC 面向接口编程 在JDBC里面Java这个公司只是提供了一套接口Connection、Statement、ResultSet&#xff0c;每个数据库厂商实现了这套接口&#xff0c;例如MySql公司实现了&#xff1a;MySql驱动程序里面实现了这套接口&#xff0c;Java程序员只要调用实现了这些方法就可以…

自动化测试 —— Pytest fixture及conftest详解

前言 fixture是在测试函数运行前后&#xff0c;由pytest执行的外壳函数。fixture中的代码可以定制&#xff0c;满足多变的测试需求&#xff0c;包括定义传入测试中的数据集、配置测试前系统的初始状态、为批量测试提供数据源等等。fixture是pytest的精髓所在&#xff0c;类似u…

智能设备控制概念及方式详解

设备控制 随着物联网设备的普及&#xff0c;如何让用户或者企业安全、灵活地控制和管理设备变得更加重要。因此&#xff0c;便有了设备控制、群组管理、智能场景、多控关联、定时任务等概念。本文主要讲解移动端应用涉及的物联网设备控制相关概念及方式方法。 在以往简单的应…

快速上手Spring Cloud 十五:与人工智能的智慧交融

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

专题:一个自制代码生成器(嵌入式脚本语言)之应用实例

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 专题&#xff1a;一个自制代码…

HTTP

HTTP 概念&#xff1a;HyperTextTransferProtocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则 HTTP协议特点&#xff1a; 1.基于TCP协议&#xff1a;面向连接&#xff0c;安全 2.基于请求-响应模型的&#xff1a;一次请求对应一次响应 …

Redis中的客户端(三)

客户端 身份验证 客户端状态的authenticated属性用于记录客户端是否通过了身份验证: typedef struct redisClient {// ...int authenticated;// ... } redisClient;如果authnticated的值为0&#xff0c;那么表示客户端未通过身份验证&#xff1b;如果authenticated的值为1&a…

目标检测+车道线识别+追踪

一种方法&#xff1a; 车道线检测-canny边缘检测-霍夫变换 一、什么是霍夫变换 霍夫变换&#xff08;Hough Transform&#xff09;是一种在图像处理和计算机视觉中广泛使用的特征检测技术&#xff0c;主要用于识别图像中的几何形状&#xff0c;尤其是直线、圆和椭圆等常见形状…

Ubuntu20.04安装OpenCV并在vsCode中配置

1. 安装OpenCV 1.1 安装准备&#xff1a; 1.1.1 安装cmake sudo apt-get install cmake 1.1.2 依赖环境 sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev sudo apt-get install libgtk2.0-d…

通过WSL在阿里云上部署Vue项目

参考&#xff1a; 阿里云上搭建网站-CSDN博客 云服务器重装 关闭当前运行实例 更换操作系统&#xff0c;还有其他的进入方式。 选择ubuntu系统&#xff08;和WSL使用相同的系统&#xff09;。 设置用户和密码。发送短信验证码。 新系统更新。秒速干净的新系统设置完成。 这…

PS从入门到精通视频各类教程整理全集,包含素材、作业等

PS从入门到精通视频各类教程整理全集&#xff0c;包含素材、作业等 最新PS以及插件合集&#xff0c;可在我以往文章中找到 由于阿里云盘有分享次受限制和文件大小限制&#xff0c;今天先分享到这里&#xff0c;后续持续更新 【Photoshop 教程】史上最容易听懂的PS...在最后四…

Java八股文(JVM)

Java八股文のJVM JVM JVM 什么是Java虚拟机&#xff08;JVM&#xff09;&#xff1f; Java虚拟机是一个运行Java字节码的虚拟机。 它负责将Java程序翻译成机器代码并执行。 JVM的主要组成部分是什么&#xff1f; JVM包括以下组件&#xff1a; ● 类加载器&#xff08;ClassLoa…