11.泛型

文章目录

  • 1 泛型概念
  • 2. 自定义泛型结构
  • 3 泛型方法
  • 4 泛型在继承上的体现
  • 5 通配符的使用

1 泛型概念

所谓泛型就是用标识符标识不确定的类型,详细说就是:定义类或接口时用标识符表示类中某个属性的类型或者是某个方法的返回值及参数类型。泛型将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。

泛型的优势:

  1. 类型安全性: 泛型允许你在编译时检查类型的一致性。通过指定类型参数,你可以确保代码在运行时不会发生类型转换错误。 (没有泛型的时候用Object,类型太多,有了泛型就能在简化代码的同时规定类型)
  2. 代码重用: 泛型使得你可以编写通用的代码,可以用于多种不同类型的对象,而无需重复编写相似的代码。这样可以减少代码的冗余,提高代码的可维护性和可读性。
  3. 性能优化: 泛型在编译时执行类型检查,而不是在运行时进行。这意味着在运行时不需要额外的类型检查和转换操作,可以提高程序的性能。

2. 自定义泛型结构

  1. 泛型的声明 interface List<T>class GenTest<K,V>

    其中,T,K,V不代表值,而是表示类型。这里使用任意字母都可以。常用T表示,是Type的缩写。

  2. 泛型的实例化:

    当泛型定义的接口或者类实例化时指定泛型具体类型的过程就是泛型的实例化

    List<String> strList = new ArrayList<String>();

    Iterator<Customer> iterator = customers.iterator();

泛型使用细节:

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>

  2. 泛型类的构造器定义方式:public GenericClass(){}。而非:public GenericClass<E>(){};

  3. 泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。经验:泛型要使用一路都用。要不用,一路都不要用。

    class GenericTest {
    	public static void main(String[] args) {
        // 1、使用时:类似于Object,不等同于Object
        ArrayList list = new ArrayList();
        // list.add(new Date());//有风险
        list.add("hello");
        test(list);// 泛型擦除,编译不会类型检查
            
        // ArrayList<Object> list2 = new ArrayList<Object>();
        // test(list2);//一旦指定Object,编译会类型检查,必须按照Object处理,此处报错 
        //java: 不兼容的类型: java.util.ArrayList<java.lang.Object>无法转换为java.util.ArrayList<java.lang.String>
        }
        
        public static void test(ArrayList<String> list) {
            String str = "";
            for (String s : list) {
            	str += s + ",";
            }
            System.out.println("元素:" + str);
        }
    }
    
  4. 泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>()类型推断

  5. 泛型的指定中不能使用基本数据类型,可以使用包装类替换

  6. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型,但允许使用和类无关的泛型也就是泛型方法。(因为静态方法早于类实例的创建,并且允许未实例化的类直接调用静态方法,此时泛型未被实例化

  7. 异常类不能是泛型的

  8. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity];参考:ArrayList源码中声明:Object[] elementData,而非泛型参数类型数组。

  9. 父类有泛型,子类可以保留父类泛型、泛型实例化、或者增加泛型等等

    子类不保留父类的泛型:按需实现

    • 没有类型 擦除
    • 具体指定泛型类型

    子类保留父类的泛型:泛型子类

    • 全部保留
    • 部分保留

结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型

class Father<T1, T2> {}

// 子类不保留父类的泛型
// 1)没有类型 擦除
class Son1 extends Father {}// 等价于class Son extends Father<Object,Object>{

// 2)具体指定泛型类型
class Son2 extends Father<Integer, String> {}

// 子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2> extends Father<T1, T2> {}
// 2)部分保留
class Son4<T2> extends Father<Integer, T2> {}
// 3)甚至可以增加泛型
class Son5<T2,T3> extends Father<Integer, T2> {}

3 泛型方法

方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的 类型。

泛型方法的格式:(访问权限后面定义泛型)

[访问权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) 抛出的异常

例子一:

public static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
    for (T o : a) {
    	c.add(o);
    }
}

public static void main(String[] args) {
    Object[] ao = new Object[100];
    Collection<Object> co = new ArrayList<Object>();
    fromArrayToCollection(ao, co);
    
    String[] sa = new String[20];
    Collection<String> cs = new ArrayList<>();
    fromArrayToCollection(sa, cs);
    
    Collection<Double> cd = new ArrayList<>();
    // 下面代码中T是Double类,但sa是String类型,编译错误。
    // fromArrayToCollection(sa, cd);
    // 下面代码中T是Object类型,sa是String类型,可以赋值成功。
    fromArrayToCollection(sa, co);
}

例子二:

class Creature{}
class Person extends Creature{}
class Man extends Person{}

class PersonTest {
    public static <T extends Person> void test(T t){//要求是Person的子类
        System.out.println(t);
    }
    
    public static void main(String[] args) {
    	test(new Person());
    	test(new Man());
    	//The method test(T) in the type PersonTest is not 
    	//applicable for the arguments (Creature)
    	test(new Creature());//报错!!
    }
}

4 泛型在继承上的体现

如果B是A的一个子类(子类或者子接口),而G是具有泛型声明的类或接口,G<B>并不是G<A>的子类型!若A是B的子类,则A<T>B<T>的子类

比如:StringObject的子类,但是List<String>并不是List<Object>的子类。

public void testGenericAndSubClass() {
    Person[] persons = null;
    Man[] mans = null;
    // 而 Person[] 是 Man[] 的父类.
    persons = mans;
    Person p = mans[0];
    
    // 在泛型的集合上
    List<Person> personList = null;
    List<Man> manList = null;
    // personList = manList;(报错)
}

5 通配符的使用

在Java中,类型通配符(Wildcard)是用来表示未知类型的,通常在泛型中使用。它的语法形式是?,可以用在泛型类、泛型方法、以及泛型接口中。

类型通配符有两种常见的形式:

  1. ? extends T: 表示通配符的类型是T或者T的子类型。这个通配符意味着你可以传递T或者T的任何子类型作为参数,但是不能传递T的超类型。

    List<? extends Number> list = new ArrayList<>();
    

    这里list可以指向任何元素是Number或者Number的子类的列表。

  2. ? super T: 表示通配符的类型是T或者T的父类型。这个通配符意味着你可以传递T或者T的任何父类型作为参数,但是不能传递T的子类型。

    List<? super Integer> list = new ArrayList<>();
    

    这里list可以指向任何元素是Integer或者Integer的父类的列表。

    public static void printCollection3(Collection<? extends Person> coll) {
        //Iterator只能用Iterator<?>或Iterator<? extends Person>.why?
        Iterator<?> iterator = coll.iterator();
        while (iterator.hasNext()) {
      	    System.out.println(iterator.next());
        }
    }
    public static void printCollection4(Collection<? super Person> coll) {
        //Iterator只能用Iterator<?>或Iterator<? super Person>.why?
        Iterator<?> iterator = coll.iterator();
        while (iterator.hasNext()) {
    		System.out.println(iterator.next());
        }
    }
    

使用类型通配符可以增加泛型的灵活性,特别是在处理泛型集合时,因为它允许你编写更通用的代码,而不需要明确知道泛型参数的具体类型。

细节:

  1. 使用类型通配符:?

    比如:List<?> ,Map<?,?>

    List<?>List<String>List<Object>等各种泛型List的父类。

  2. 读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。

  3. 不能向List<?>中添加元素,因为不知道他的数据类型。但null除外,可以向其添加null值。读取元素正常,读取出来的元素都是Object类型

    将任意元素加入到其中不是类型安全的:

    Collection<?> c = new ArrayList<String>();
    c.add(new Object()); // 编译时错误
    

    因为我们不知道c的元素类型,我们不能向其中添加对象。唯一可以添加的数值式null,另一方面,我们可以调用get()方法并使用其返回值,返回值是一个位置的类型,但是我们知道,他总是一个Object

例子:

public static void main(String[] args) {
    List<?> list = null;
    list = new ArrayList<String>();
    list = new ArrayList<Double>();

    // list.add(3);//编译不通过使用通配符不能添加元素
    list.add(null);
    List<String> l1 = new ArrayList<String>();
    List<Integer> l2 = new ArrayList<Integer>();
    l1.add("尚硅谷");
    l2.add(15);
    read(l1);
    read(l2);
}

public static void read(List<?> list) {
    for (Object o : list) {
    System.out.println(o);
}

注意点:

//注意点1:编译错误:不能用在泛型方法声明上,返回值类型前面<>不能使用?
public static <?> void test(ArrayList<?> list){
}
//注意点2:编译错误:不能用在泛型类的声明上
class GenericTypeClass<?>{
}
//注意点3:编译错误:不能用在创建对象上,右边属于创建集合对象
ArrayList<?> list2 = new ArrayList<?>();

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

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

相关文章

《QT实用小工具·三十九》仿 Windows10 画图3D 的颜色选择器, 但更加强大

1、概述 源码放在文章末尾 该项目实现了仿 Windows10 画图3D 的颜色选择器&#xff0c;功能更加丰富更加强大。 项目部分代码如下所示&#xff1a; import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import QtGraphicalEffects 1.15Item {id…

基于OSAL 实现UART、LED、ADC等基础示例 4

1 UART 实验目的 串口在我们开发单片机项目是很重要的&#xff0c;可以观察我们的代码运行情况&#xff0c;本节的目的就 是实现串口双工收发。 虽然说 osal 相关的代码已经跟硬件关系不大了&#xff0c;但是我们还是来贴出相关的硬件原理图贴出来。 1.1 初始化 osal_init_s…

Leetcode743. 网络延迟时间

Every day a Leetcode 题目来源&#xff1a;743. 网络延迟时间 本题需要用到单源最短路径算法 Dijkstra&#xff0c;现在让我们回顾该算法&#xff0c;其主要思想是贪心。 将所有节点分成两类&#xff1a;已确定从起点到当前点的最短路长度的节点&#xff0c;以及未确定从起…

分类分析|KNN分类模型及其Python实现

KNN分类模型及其Python实现 1. KNN算法思想2. KNN算法步骤2.1 KNN主要优点2.2 KNN主要缺点 3. Python实现KNN分类算法3.1 自定义方法实现KNN分类3.2 调用scikit-learn模块实现KNN分类 4. K值的确定 在之前文章 分类分析|贝叶斯分类器及其Python实现中&#xff0c;我们对分类分…

DHCP的原理与配置

一.了解DHCP服务 1. DHCP (Dynamic Host Configuration Protocol)动态主机配置协议 是由Internet工作小组设计开发的&#xff0c;专门用于为TCP/IP网络中的计算机自动分配TCP/IP参数的协议 DHCP协议采用的是UDP作为传输协议&#xff0c;是给网络内的客户机自动分配IP地址&…

Redis入门到通关之Redis实现Session共享

文章目录 ☃️前期概要☃️基于Session实现登录方案☃️现有方案存在的问题☃️Redis代替Session的业务流程❄️❄️设计key的结构❄️❄️设计key的具体细节❄️❄️整体访问流程 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博…

羊大师分析,羊奶和牛奶哪个更适合夏天喝?

羊大师分析&#xff0c;羊奶和牛奶哪个更适合夏天喝&#xff1f; 羊奶和牛奶都是营养丰富的饮品&#xff0c;适合不同人群在不同季节饮用。在夏天&#xff0c;选择羊奶还是牛奶主要取决于个人的体质、口味偏好以及需求。 羊奶的营养价值较高&#xff0c;含有丰富的蛋白质、矿物…

ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)

前言&#xff1a;在开发过程中&#xff0c;几乎踩便了所有大坑小坑总结出的文章&#xff0c;我是把坑踩满了&#xff0c;帮助更过小白快速上手&#xff0c;如有错误之处&#xff0c;还麻烦各位大佬帮忙指正、 目录 一、ESP-01s介绍 1、ESP-01s管脚功能&#xff1a; 模组启动模…

元数据管理和数据目录对于现代数据平台的重要性——Lakehouse架构(四)

文章目录 前言解读元数据技术元数据业务元数据 元存储和数据目录如何协同工作&#xff1f;数据目录的特点查询、检索和发现数据数据分类数据治理数据血缘 前言 Lakehouse 架构中的存储层负责存储整个平台的数据&#xff0c;要查询存储的这些数据&#xff0c;我们需要一个数据目…

xgp怎么取消续费 微软商店xgp会员取消自动续费详细教程

xgp怎么取消续费 微软商店xgp会员取消自动续费详细教程 XGP这个游戏平台小伙伴们并不陌生吧&#xff0c;它是微软Xbox游戏部门推出的游戏租赁制会员服务&#xff0c;主要用于主机和PC两个平台。这个平台的会员就可以免费享受多款大制作游戏&#xff0c;而且每个月还会自动更新…

ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

JAVA毕业设计137—基于Java+Springboot+Vue的物流快递仓库管理系统(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的物流快递仓库管理系统(源代码数据库)137 一、系统介绍 本项目前后端分离&#xff0c;分为员工、销售员、仓库员、商品管理员、超级管理员五种角色 1、员工…

Linux 的情况下实现贪吃蛇 -- 第二十八天

1. 打印地图 keypad(stdsrc,1) 参数表示是否接收&#xff0c;1表示接收指令 2.思路&#xff1a;初始化initNcurses()&#xff0c; 封装地图函数实现地图gamePic&#xff08;&#xff09; 分三部分实现&#xff1a;2.1: 在第0行&#xff1a;打印 "--",&quo…

矩阵连乘算法

矩阵连乘&#xff1a; #include<iostream> #define inf 0x7fffffff using namespace std; int a[256] { 0 };//存储矩阵的行和列 int m[256][256] { 0 };//存储i到j的最少计算次数 int s[256][256] { 0 };//存储i到j的中转站k void m_print(int i, int j) {if (i …

javaWeb项目-房屋房租租赁系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JSP技术 JSP(Jav…

数据结构-二叉树-链式

一、链式二叉树的结构 typedef int BTNodeDataType; typedef struct BTNode {BTNodeDataType data;struct BTNode* left;struct BTNode* right; }BTNode; 二叉树的前中后序遍历 前序&#xff1a;根左右 中序&#xff1a;左根右 后序&#xff1a;左右根 void PreOrder(BTNo…

栈 、队列

1.stack的介绍和使用 1.1stack的介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 1.2 stack的使用 函数说明 接口说明 stack() 构造空的栈 empty() 检测stack是否为空 size…

Opencv | 边缘检测 轮廓信息

目录 一. 边缘检测1. 边缘的定义2. Sobel算子 边缘提取3. Scharr算子 边缘提取4. Laplacian算子 边缘提取5. Canny 边缘检测算法5.1 计算梯度的强度及方向5.2 非极大值抑制5.3 双阈值检测5.4 抑制孤立弱边缘 二. 轮廓信息1. 获取轮廓信息2. 画轮廓 一. 边缘检测 1. 边缘的定义…

【QT】Ubuntu22.04 配置 QT6.5 LTS

【QT】Ubuntu22.04 配置 QT6.5 LTS 文章目录 【QT】Ubuntu22.04 配置 QT6.5 LTS1.注册QT Group的账号2.安装QT Creator3.启动QT Creator报错from 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.4.运行QT的demoReference 1.注册QT Group的…

mysql buffer pool详解

介绍 缓冲池是InnoDB在访问表和索引数据时缓存的主内存区域。缓冲池允许直接从内存访问频繁使用的数据&#xff0c;这加快了处理速度。在专用服务器上&#xff0c;通常会将多达80%的物理内存分配给缓冲池。 为了提高大容量读操作的效率&#xff0c;缓冲池被划分为可能包含多行…