泛型总结(擦除机制+泛型上界+通配符的上下界)

文章目录

  • 泛型
    • 一、 什么是泛型
      • 1.能用于多种类型,把类型当做参数
        • 1.1 作用
        • 1.2 语法
    • 二、擦除机制
      • 1. 为什么采用擦除机制实现泛型?
            • 向后兼容性
          • 移植兼容性
      • 2. 为什么不能使用“newT()”?
      • 3. 创建类型T的数组
          • 3.1 不安全的写法
          • 3.2 官方的写法
        • 3. 3 正确的写法
      • 4. 反编译后,对比方法的参数
    • 三、泛型的上界
    • 四、泛型方法
    • 五、通配符
      • 通配符的上界和下界


泛型


一、 什么是泛型

1.能用于多种类型,把类型当做参数

JDK1.5后引入的

1.1 作用

在编译的时候

  • 存储数据的时候,进行自动的类型检查
  • 获取元素的时候,帮助进行类型转换
  • 泛型是编译时期的一种机制,在运行的时候没有泛型的概念

1.2 语法
class MyArray <T>{//当前类是一个泛型类

    //public Object[]  obj = new Object[5];//实现一个类,类中包含一个数组成员,\
    public T[] obj = (T[]) new Object[5];//

    // 使得数组中可以存放任何类型的数据,也可以根据成员方法返回数组中某个
    //下标的值?
    public T getPos(int pos) {
        return this.obj[pos];//回数组中某个
        //下标的值?
    }
    public void setObj(int pos,T val){
        this.obj[pos] = val;
    }
}

public class Test2 {
    public static void main(String[] args) {
        
        MyArray<Integer> myArray = new MyArray<>();//后面的<>可以省略
        //实例化对象的同时,指定当前的泛型类 的 指定参数类型为Integer
        //把类型进行了传递,只能存指定的数据类型
        //MyArray<Integer> myArray = new MyArray<Integer>();
        //指定的参数类型,必须是引用类型
        myArray.setObj(0,3);
        myArray.setObj(1,4);//这时就不能传String类型
        myArray.setObj(2,5);
        Object pos = myArray.getPos(1);
     //  double d = myArray.getPos(2);//不知道是什么类型的,取出的时候很麻烦
        //什么数据都能存储
        //传进去后,都向上转型常量object,获取数据的时候要强转
        //需要指定类型,才能不进行强转
        System.out.println(pos);
        System.out.println("-------------");
        MyArray<String> myArray1 = new MyArray<>();
        myArray1.setObj(1,"hello");
        //获取数据的时候不用强转,里面都是指定的数据类型,直接拿指定的类型接收
        myArray1.setObj(0,"Hello");
        String pos1 = myArray1.getPos(0);
        String pos2 = myArray1.getPos(1);
        //在编译的时候
        //存储数据的时候,进行自动的类型检查
        //获取元素的时候,帮助进行类型转换

    }
}
  • 类名后的 代表占位符,表示当前类是一个泛型类
  • 前面<>指定类型,后面的<>可以省略
  • 把类型进行了传递,只能存指定的数据类型
  • 指定的参数类型,必须是引用类型
  • 不能实例化一个泛型类型的数组
  • 裸类型:不加<>,兼容老版本的机制

E 表示 Element K 表示 Key V 表示 Value N 表示 Number


二、擦除机制

1. 为什么采用擦除机制实现泛型?

为什么Sun公司选择采用擦除机制实现泛型?

向后兼容性
  • 这种设计是为向后兼容性提供源代码和目标代码两方面的支持,希望现有的代码和类文件在新版本的Java中继续使用,而不发生冲突,在不破坏语言的同时,更改语言
移植兼容性
  • 移植兼容性要求API的泛型版本要和老的版本兼容,就是说用户能继续编译(源文件)和运行(编译后的程序)。这种要求在很大程度上限制了Java泛型设计的空间

2. 为什么不能使用“newT()”?

是因为,并不是每个类型都有一个空的构造器

  • Java是静态类型语言,不能简单的调用某一类型的空构造器,因为这个类型自身并不静态地知道有这样的构造器存在。由于擦除机制,所以没有办法来生成这种代码。

3. 创建类型T的数组

3.1 不安全的写法
T[] a = (T[]) new Object[N];

不安全,但可以在多数情况下运行,在编译时会警告
因为Object数组不是具体T类型的数组

如果方法返回T[],并且指定的类型是,将返回值存入String[]类型的变量中,在运行时将得到ClssCastException错误。

		 public T[] copyArr(T[] obj){
      		  return obj;
  	 	 }
        
        public static void main(String[] args) {
        Student<String> student = new Student<>();
        student.setObj(0,"小明");
        student.setObj(1,"小王");
        student.setObj(2,"小红");

        String[] copyArr = student.copyArr(student.obj);
        System.out.println(Arrays.toString(copyArr));
    }
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at learn.Test3.main(Test3.java:35)

返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,可能是Integer.运行的时候,直接转给String类型的数组,编译器认为是不安全的。

3.2 官方的写法
public Object[] obj =  new Object[5];//正确写法

  return (E) elementData[index];

在Java源码中,使用的是Object类型的数组,在方法中,返回时进行泛型的转换

3. 3 正确的写法

通过反射创建,实现类型的数组

/**
     * 通过反射创建,实现类型的数组
     * @param clazz
     * @param capacity
     */
    public Student(Class<T>clazz, int capacity) {
        this.obj = (T[])Array.newInstance(clazz,capacity);
    }
    Student<String> student = new Student<>(String.class,10);

4. 反编译后,对比方法的参数

在这里插入图片描述

  • 在运行的时候,没有泛型的概念
  • 泛型只是编译时期的一种机制
  • 编译完成后,会将泛类型擦除成了Object类型,叫做擦除机制
  • Java的泛型机制是在编译级别实现的。
  • 编译器生成的字节码在运行期间并不包含泛型的类型信息。

三、泛型的上界

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

public class MyArray<E extends Number>

E是number的子类 或者 E是Number本身

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

代表将来指定的数据类型,一定实现了这个接口

四、泛型方法

  • 静态的泛型方法,要在static后面声明泛型的参数

  •     public static void main(String[] args) {
            List<Integer>list = new ArrayList<>();
            Integer [] arr = {1,2,3,4,5};
           Test2.<Integer>swap(arr,0,2);
            for (int x:arr) {
                System.out.println(x);
            }
        }
        public static<E> void swap(E[]array, int i, int j){
            E t = array[i];
            array[i] = array[j];
            array[j] = t;
        }
    }
    

五、通配符

  • 通配符: “ ?”
class Message<T> {//泛型类
	private T message ;
	public T getMessage() {
	return message;
	}
	public void setMessage(T message) {
	this.message = message;
	}
}
    public static void main(String[] args) {
        Message<String> message = new Message<>() ;
        message.setMessage("Hello world");
        fun(message);//Hello world

        Message<Integer> message2 = new Message<>() ;
        message2.setMessage(888);
       // fun(message2);//fun方法,只能接受<String>类型的对象
        fun(message2);

    }
/*    public static void fun(Message<String> temp){
        System.out.println(temp.getMessage());
    }*/
    public static void fun(Message<?> temp){
        //用通配符来规范传进的参数
        System.out.println(temp.getMessage());
    }

  • 通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改

通配符的上界和下界

? extends 类:设置通配符上限

  • 实例化的只能是参数类型本身或者它的子类
  • 不能进行写入数据(无法确定是哪个子类),只能进行读取数据(向上转型)

? super 类:设置通配符下限

  • 实例化的只能是参数类型本身、或者它的父类

  • 不能进行读取数据(无法确定是哪个父类),只能写入数据(传进去子类对象)

点击移步博客主页,欢迎光临~

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从0到1:兼职招聘小程序开发笔记(一)

可行性分析 兼职招聘小程序&#xff1a;为雇主和求职者提供便利的平台&#xff0c;旨在帮助雇主招聘兼职员工&#xff0c;并让求职者寻找合适的兼职工作。提供简单、快捷的方式来匹配兼职岗位和候选人&#xff0c;节省了招聘和求职的时间和精力。其主要功能模块包括&#xff1…

Cross Hyperspectral and LiDAR Attention Transformer

TGRS 2024&#xff1a;Cross Hyperspectral and LiDAR Attention Transformer: An Extended Self-Attention for Land Use and Land Cover Classification 题目 Cross Hyperspectral and LiDAR Attention Transformer: An Extended Self-Attention for Land Use and Land Cov…

安装mysql8,启动mysql服务日志 libstdc++.so.6: wrong ELF class: ELFCLASS32

背景&#xff1a;linux centos7.9安装mysql5.7版本&#xff0c;服务启动成功后被告知要求安装mysql8版本&#xff0c;故卸载之后安装mysql8&#xff0c;后启动mysql服务报错提示&#xff1a;libstdc.so.6: wrong ELF class: ELFCLASS32 解决办法&#xff1a; 1、下载安装包li…

LeetCode Python - 81. 搜索旋转排序数组 II

目录 题目描述解法运行结果 题目描述 已知存在一个按非降序排列的整数数组 nums &#xff0c;数组中的值不必互不相同。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转 &#xff0c;使数组变为 […

屌爆了,我不懂音乐,但AI让我一天完成原创专辑制作

前言 作为一个完全不懂音乐的程序员&#xff0c;我从未想象过自己能够踏入音乐创作的领域。然而&#xff0c;借助AI的力量&#xff0c;我竟然实现了制作一张完整专辑的梦想&#xff0c;而整个过程不过一天时间。从写词到生成音频&#xff0c;再到制作MV&#xff0c;每首歌曲仅需…

PHP在线客服系统源码修复版

源码简介 在线客服系统网站源码https://www.888host.cn/330.html 新增消息预知&#xff0c;消息撤回&#xff0c;消息已读未读&#xff0c; 修复需要刷新才能收到消息 修复客户来源地址 修复消息提示音 修复桌面推送提醒 搭建环境 宝塔面板 &#xff0c;Nginx1.16-1.18 …

什么是检索增强生成(Retrieval-Augmented Generation,RAG)

什么是RAG&#xff1f; 检索增强生成&#xff08;Retrieval-Augmented Generation&#xff0c;RAG&#xff09;&#xff0c;是指为大模型提供外部知识源的概念。能够让大模型生成准确且符合上下文的答案&#xff0c;同时能够减少模型幻觉。 用最通俗的语言描述&#xff1a;在已…

第十四届蓝桥杯软件赛省赛C/C++ C组 思路讲解与参考代码

A. 求和&#xff1a; 问题描述 求 11 &#xff08;含&#xff09;至 2023040820230408 &#xff08;含&#xff09;中每个数的和。 思路&#xff1a;等差数列&#xff0c;d位1&#xff0c;Sn &#xff08;a1an&#xff09;*n/2; 参考代码&#xff1a; #include <iost…

动态规划-----背包类问题(0-1背包与完全背包)详解

目录 什么是背包问题&#xff1f; 动态规划问题的一般解决办法&#xff1a; 0-1背包问题&#xff1a; 0 - 1背包类问题 分割等和子集&#xff1a; 完全背包问题&#xff1a; 完全背包类问题 零钱兑换II: 什么是背包问题&#xff1f; 背包问题(Knapsack problem)是一种…

obspy安装

最近在安装obspy时经常&#xff0c;试了各种方法 conda install obspy pip install obspy 发现都没有办法&#xff0c;包括选择了很多镜像源。 C: \Users admin>conda config -add channels https://mirrors. sustech. edu. cn/anaconda/cloud/biocondal (base)C:\Users…

qtcreator的信号槽链接

在ui文件中简单创建一个信号槽连接并保存可以在ui_mainwindow.h下 class Ui_MainWindow 类 void setupUi(QMainWindow *MainWindow)函数 找到对应代码 QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(close())); 下拉&#xff0c;由于 class MainWind…

书生·浦语大模型实战营之全链路开源体系

书生浦语大模型实战营之全链路开源体系 为了推动大模型在更多行业落地开花&#xff0c;让开发者们更高效的学习大模型的开发与应用&#xff0c;上海人工智能实验室重磅推出书生浦语大模型实战营&#xff0c;为广大开发者搭建大模型学习和实践开发的平台&#xff0c;两周时间带…

按大小顺序输出任一三个数据(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//实现比较函数&#xff1b; int Compare(int a, int b, int c) {//比较a,c的大小&#xff1b;if (a < c){//输出结果&#xff1b;printf("%d > %d &…

如何关闭win10防火墙,怎么关闭win10防火墙通知

Windows10系统自带了防火墙功能,可以有效阻止病毒软件入侵,一般情况下是默认开启的。但是有时候我们下载一些软件,或使用某些功能时,就需要提前将它关闭,以免防火墙阻止正常运作。那么如何关闭win10防火墙呢?网上介绍关于win10系统关闭防火墙的处理方法比较零散,这里小编…

共享办公室行业面临的最大挑战是什么,未来有哪些可能的发展方向

共享办公室行业虽然发展迅速&#xff0c;但也面临着一些挑战和需要解决的问题。咱们来聊聊这行业的最大挑战和未来可能的发展方向。 面临的最大挑战&#xff1a; 市场竞争加剧&#xff1a;随着共享办公室的火热&#xff0c;越来越多的玩家进入市场&#xff0c;竞争变得异常激烈…

安装部署MariaDB数据库管理系统

目录 一、初始化MariaDB服务 1、安装、启动数据库服务程序、将服务加入开机启动项中。 2、为保证数据库安全性和正常运转&#xff0c;需要对数据库程序进行初始化操作。 3、配置防火墙&#xff0c;放行对数据库服务程序的访问请求&#xff0c;允许管理员root能远程访问数据…

应用层协议之DNS协议

一.应用层协议的相关数据传输格式 1.文本字符串格式 应用层主要是自定义协议&#xff0c;以点外卖为例&#xff1a; 客户点开软件&#xff0c;就是应用程序和服务器之间进行网络通信交互。请求和响应可以如下设置 请求&#xff1a;用户信息&#xff0c;位置信息&#xff0c…

比KMP简单的Manacher

P3805 【模板】manacher - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) “没时间悼念KMP了&#xff0c;接下来上场的是Manacher&#xff01;” 什么是Manacher? 历史背景&#xff1a; 1975 年&#xff0c;一个叫 Manacher 的人发明了这个算法&#xff0c;所以叫Manacher 算…

【JavaWeb】Day28.SpringBootWeb请求响应——请求(一)

前言&#xff1a; 我们在开发web程序时呢&#xff0c;定义了一个控制器类Controller&#xff0c;请求会被部署在Tomcat中的Controller接收&#xff0c;然后Controller再给浏览器一个响应。 而在请求响应的过程中是遵循HTTP协议的。 但是&#xff0c;在Tomcat这类Web服务器中&a…

vivado JTAG 回退支持

JTAG 回退支持 基于 XVC 的调试解决方案可配合 AXI 主接口 &#xff08; 如 PCIe XDMA IP &#xff09; 一起使用。如果 AXI 主接口被挂起 &#xff0c; 或者无法正常 运作&#xff0c; 则无法在此类情况下进行调试。为了提供基于 JTAG 的回退调试途径 &#xff08; 与 X…