JAVA泛型、泛型通配符、综合练习


作用:

是 jdk5 中引入的特性,可以在编译阶段 约束 操作的数据类型,并进行检查。

格式:

<数据类型>
注意泛型只能支持引用数据类型,基本数据类型可转成对应的包装类。


问题:

在没有泛型的时候,集合如何存储数据?
结论:如果我们没有给集合类型,默认数据为 Object 类型。
即可以添加任意类型的数据
如图:
image.png
image.png
等等;


弊端 1:

我们在获取集合内的数据时,无法使用它里面的特有方法。
如,以下情况:
其实这是构成了一种多态结构,而在讲解多态调用成员的特点中说过
调用成员方法,编译看左边,运行看右边
image.png
需要将 Object 强转成 String 才可以调用。
image.png


此时推出了泛型,
可以再添加数据时把类型进行统一。
而且我们在获取数据的时候,也省的强转了,非常方便。
如图:
image.png
好处
总的来说泛型的好处:

  • 统一数据类型。
  • 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来
  • 扩展:
    • 泛型擦除(Type Erasure)是Java中实现泛型的一种方式,泛型类型信息在编译时会被擦除,使得在运行时无法获取泛型的具体类型信息。这可能会导致一些限制和需要额外注意的地方,比如无法直接创建泛型类型的实例。
      • 例如:image.png

泛型细节:

  • 泛型中不能写基本数据类型
  • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
  • 如果不写泛型,类型默认是Object

泛型的应用:

泛型类:在类名后用

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

格式:
image.png
这里的 E 是用来记录数据类型的,可以写成:T、E、K、V 等等
为了方便理解,在编写泛型类时,可以把自己想想成一个大佬,你需要考虑到使用这个类的人 是如何 使用这个类的。
image.png

现在我们就来实际体会下:

/*
泛型类*/
public class MYArrayList <E> {//ArrayList底层是一个Object数组Object[]obj=new Object[10];//集合长度int size;//add方法,其中E表示不确定的类型,e变量名public boolean add(E e){obj[size]=e;//size既表示长度,又表示下一元素存入位置size++;//添加后长度++return true;}//在底层是Object类型,在获取时强转为测试类中泛型指定的类型public E get(int index){return  (E) obj[index];}@Overridepublic String toString(){return Arrays.toString(obj);}
}

测试类

public static void main(String[] args) {//创建对象,指定类型StringMYArrayList<String> list = new MYArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");System.out.println(list.get(0));System.out.println(list);//-----------------------,//创建对象,指定类型IntegerMYArrayList<Integer> list1 = new MYArrayList<>();list1.add(123);list1.add(123);list1.add(123);System.out.println(list1.get(0));System.out.println(list1);}

控制台:
aaa
[aaa, bbb, ccc, null, null, null, null, null, null, null]
123
[123, 123, 123, null, null, null, null, null, null, null]


泛型方法:修饰符后声明泛型

应用场景:方法形参类型不确定时,有两种情况

  1. 使用类名候命定义的泛型----所有方法都能用
  2. 在方法的修饰符后声明自己的泛型------只有本方法能用

格式:public static
image.png

用一个例子来理解:
//在工具类 ListUtil 类中定义一个静态方法addAll,用来添加多个集合元素。

//工具类
public class ListUtil {//私有化构造方法,不让外界创造对象private ListUtil() {}//类中定义一个静态方法add A11,用来添加多个集合的元素。
//    参数一:集合
//    参数二:要添加的元素public static <E>void addAll1(ArrayList<E> list,E e1,E e2,E e3){list.add(e1);list.add(e2);list.add(e3);}/* public static <E>void addAll2(ArrayList<E> list,E...e){for (E element:e){list.add(element);
}   */}

注释部分: E…e 表示可变参数,用 E[] 来存储,只能通过遍历来获取元素,后面再说

测试类:

//创建集合对象,规定泛型为String
ArrayList<String>list1=new ArrayList<>();ListUtil.addAll1(list1,"a","b","c");
System.out.println(list1);//创建集合对象,规定泛型String
ArrayList<Integer>list2=new ArrayList<>();ListUtil.addAll1(list2,1,2,3);
System.out.println(list2);

若没限定,默认 Object 型

泛型接口:在接口名后用

格式:
image.png

重点:如何使用来个带泛型的接口?

  1. 在实现接口的类中给出具体类型

  2. 在实现类中延续泛型,创建实现类的对象时再确定类型

  3. 在实现接口的类中给出具体类型:

这是一个泛型接口
image.png
现在我们创建一个类来实现接口,并直接给出具体类型
image.png
此时实现类中的 add 方法形参直接确定类型为 String
image.png
所以在测试类中创建实现类的对象后 只能添加 String类型
image.png


  1. 在实现类中延续泛型,创建实现类的对象时再确定类型

现在我们创建一个类来实现 List 接口,但延续泛型
image.png
此时实现类中的 add 方法形参仍是泛型
image.png
创建实现类的对象并确定类型
image.png


泛型的通配符:

严格的泛型类型系统使用起来并不那么令人愉快,
“解决方案”:通配符类型。

  • <?>表示 和 一样也表示不确定的类型,但是?不需要提前定义,而 E 需要提前定义

image.png
image.png
image.png

  • ?extends E:表示可以传递E或者E所有的子类类型
  • ?super E:表示可以传递E或者E所有的父类类型

如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符,关键点:可以限定类型的范围。

泛型的继承问题

  • 泛型不具备继承性,但是数据具备继承性

1. 如:
方法 KeepPet3, 形参为 Animal 的集合:image.png
传递一个同是 Animal 类型的集合,传递没问题,
image.png
image.png
这时若换成传递子类 Cat 的集合,会报错
image.png
image.png
所以说泛型不具备继承性

2.但是数据具备继承性image.png

综合练习:

Snipaste_2024-01-25_15-27-20.png

Animal:

public abstract class Animal {private String name;private int age;//构造方法+set+get//定义一个抽象方法public abstract void eat();

Cat:

public abstract  class Cat extends Animal{//    调用构造方法public Cat(){};public  Cat (String name,int age){super(name,age);}
}

Dog:

public abstract class Dog extends Animal{//调用构造方法public  Dog(){}public Dog(String name, int age){super (name ,age);}}

哈士奇:

public class Huskies extends Dog {//调用构造public Huskies(){};public Huskies(String name,int age){super(name,age);}@Overridepublic void eat() {System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的哈士奇,正在吃骨头,边吃边拆家");}
}

泰迪:

public class Teddy extends Dog{//调用构造方法public  Teddy(){}public Teddy(String name, int age){super (name ,age);}@Overridepublic void eat() {System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的泰迪,正在吃骨头,边吃边蹭");}
}

波斯猫:

public class PersianCat  extends Cat{调用构造方法
public PersianCat(){};
public PersianCat(String name,int age){
super(name,age);
}@Overridepublic void eat() {System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的波斯猫,正在吃小饼干");}}

狸花猫:

public class TanukiCat extends Cat{//调用构造public TanukiCat(){};public TanukiCat(String name,int age){super(name,age);}@Overridepublic void eat() {System.out.println("一只叫做"+getName()+"的,"+getAge()+"岁的狸花猫,正在吃鱼");}
}

Test:

public class Test {public static void main(String[] args) {//动物ArrayList<Animal> list1 = new ArrayList<>();//猫ArrayList<Cat> list2 = new ArrayList<>();list2.add(new PersianCat("小花", 3));list2.add(new TanukiCat("小喵", 2));//狗ArrayList<Dog> list3 = new ArrayList<>();list3.add(new Teddy("小黑", 2));list3.add(new Huskies("小汪", 3));KeepPet1(list2);//猫KeepPet2(list3);//狗KeepPet3(list1);//动物}//要求1该方法能养所有品种的猫,但是不能养狗public static void KeepPet1(ArrayList<? extends Cat> list) {list.forEach(cat -> cat.eat());}//要求2:该方法能养所有品种的狗,但是不能养猫public static void KeepPet2(ArrayList<? extends Dog> list) {Iterator it=list.listIterator();while(it.hasNext()){Dog dog=(Dog)it.next();dog.eat();}}//要求3:该方法能养所有的动物,但是不能传递其他类型public static void KeepPet3(ArrayList<Animal> list) {for (Animal a : list) {a.eat();}}
}

控制台:
一只叫做小花的,3岁的波斯猫,正在吃小饼干
一只叫做小喵的,2岁的狸花猫,正在吃鱼
一只叫做小黑的,2岁的泰迪,正在吃骨头,边吃边蹭
一只叫做小汪的,3岁的哈士奇,正在吃骨头,边吃边拆家

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

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

相关文章

UE使用C++添加FGameplayTag(游戏标签)

首先Ue会有一个UGameplayTagsManager类型的对象 游戏标签管理器(全局中就有一个) 我们直接通过 UGameplayTagsManager::Get()静态函数拿到 全局唯一的游戏标签管理器的实例 返回的是个左值引用 之后通过调用 AddNativeGameplayTag()函数就可添加游戏标签了 就这么简单 第…

按条件自动搜索文件

在计算机的某个文件夹中&#xff0c;假如有一大堆不同格式的文件&#xff0c;如下图&#xff1a; 我们的目的&#xff1a;快速查找出文件名中包含某文字内容的指定格式的文件&#xff0c;看看它们都放在哪里&#xff1f;通过分析&#xff0c;可能在当前文件夹中也可能在某个子…

核心类库ArrayList、hashMap等

八. 核心类库 1. ArrayList 数组缺点 ArrayList&#xff0c;它常常被用来替代数组 数组的缺点&#xff1a;不能自动扩容&#xff0c;比如已经创建了大小为 5 的数组&#xff0c;再想放入一个元素&#xff0c;就放不下了&#xff0c;需要创建更大的数组&#xff0c;还得把旧…

防御保护---防火墙(安全策略、NAT策略实验)

防御保护---防火墙&#xff08;安全策略、NAT策略实验&#xff09; 1.实验需求2.实验说明及思路3.实验配置3.1 配置IP地址以及VLAN3.2 配置防火墙IP地址及划分区域3.3 配置防火墙安全策略3.4 配置防火墙NAT策略 1.实验需求 1.生产区在工作时间内可以访问服务器区&#xff0c;仅…

【iOS ARKit】人脸追踪之挂载虚拟元素

人脸跟踪&#xff08;Face Tracking&#xff09;是指将人脸检测扩展到视频序列&#xff0c;跟踪同一张人脸在视频序列中的位置。是论上讲&#xff0c;任何出现在视频中的人险都可以被跟踪&#xff0c;也即是说&#xff0c;在连续视频帧中检测到的人脸可以被识别为同一个人。人脸…

ActiveMQ|01-ClassicArtemis功能介绍

接上篇-MQ消息队列主流消息服务规范及代表产品&#xff0c;ActiveMQ就是基于JMS消息服务规范的消息中间件组件&#xff0c;主要应用在分布式系统架构中&#xff0c;帮助构建高可用、 高性能、可伸缩的企业级面向消息服务的系统 本文速览&#xff1a; JMS对象模型ActiveMQ的功…

import tensorflow.contrib.slim as slim中contrib报红,显示没有导入contrib

本人环境&#xff1a; python 3.6 tensorflow 1.13 问题如下图&#xff1a; 解决方法&#xff1a; 找到包的位置&#xff0c;查看tensorflow中是否下载了contrib包&#xff0c;如果有的话&#xff0c;建议重新装一次TensorFlow 如果没有找找&#xff0c;可以在搜索栏搜一下…

【Web前端实操15】利用Grid布局完成九宫格

相关知识点&#xff1a; 创建多列 column-count 属性指定了需要分割的列数 列与列之间的间隙 column-gap 属性指定了列与列间的间隙 列边框 column-rule-style 属性指定了列与列间的边框样式 column-rule-width 属性指定了两列的边框厚度 column-rule-color 属性指定了…

【GitHub项目推荐--不错的Flutter项目】【转载】

01 可定制的图表库 FL Chart是一个高度可定制的 Flutter 图表库&#xff0c;支持折线图、条形图、饼图、散点图和雷达图 。 项目地址&#xff1a;https://github.com/imaNNeoFighT/fl_chart LineChart BarChart PieChart Sample1 Sample2 Sample3 …

哪吒汽车与经纬恒润合作升级,中央域控+区域域控将于2024年落地

近日&#xff0c;在2024哪吒汽车价值链大会上&#xff0c;哪吒汽车与经纬恒润联合宣布合作升级&#xff0c;就中央域控制器和区域域控制器展开合作&#xff0c;合作成果将在山海平台新一代车型上发布。 哪吒汽车首席技术官戴大力、经纬恒润副总裁李伟 经纬恒润在智能驾驶领域拥…

百度Apollo | 实车自动驾驶:感知、决策、执行的无缝融合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测 目录 多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现DBO-BiLSTM多变量时间序…

Ubuntu 申请 SSL证书并搭建邮件服务器

文章目录 Log 一、域名连接到泰坦&#xff08;Titan&#xff09;电子邮件二、NameSilo Hosting 避坑三、Ubuntu 搭建邮件服务器1. 环境准备2. 域名配置3. 配置 Postfix 和 Dovecot① 安装 Nginx② 安装 Tomcat③ 申请 SSL 证书&#xff08;Lets Encrypt&#xff09;④ 配置 pos…

链表分割(新的错误:开头赋值)

1.单向链表&#xff1a;含有链表内容和下个链表的指针 2.双向链表&#xff1a;含有链表内容和上下两个链表的指针 3.带头和不带头&#xff1a;哨兵位的头结点&#xff08;不存储有效数据&#xff09;&#xff0c;主要区别在于链表为空时会存在一个哨兵位节点&#xff0c;优点…

【C#】基础巩固

最近写代码的时候各种灵感勃发&#xff0c;有了灵感&#xff0c;就该实现了&#xff0c;可是&#xff0c;实现起来有些不流畅&#xff0c;总是有这样&#xff0c;那样的卡壳&#xff0c;总结下来发现了几个问题。 1、C#基础内容不是特别牢靠&#xff0c;理解的不到位&#xff…

WebSocket实现HTML+SpringBoot聊天功能,小程序+SpringBoot聊天功能

目录 一、认识WebSocket 二、HTML实现聊天 三、微信小程序实现聊天 一、认识WebSocket 1.首先博主在初学Java时自我感觉走了很多弯路&#xff0c;因为以前见识短&#xff0c;在接触聊天功能时根本就没能想到有WebSocket这个聊天框架&#xff0c;就只能用底层的UDP或TCP实现聊…

2.Kubernetes基础-1

Kubernetes基础-1 掌握Kubernetes&#xff0c;需要我们有扎实的docker基础。 深入了解pods之前&#xff0c;我们需要&#xff1a; 应用程序已经开发并打包成Docker镜像&#xff0c;并且在Docker存储库&#xff08;如Docker Hub&#xff09;中可用&#xff0c;可下载Kubernet…

【GPU】深入理解GPU硬件架构及运行机制

深入理解GPU硬件架构及运行机制 作者&#xff1a;Tim在路上​ 曾看到有一篇名为《The evolution of a GPU: from gaming to computing》的文章。 这篇文章非常热烈的讨论了这些年GPU的进步&#xff0c;这引发了我们的一些思考: 为什么我们总说GPU比CPU要强大&#xff0c;既然…

unity学习笔记----游戏练习07

一、僵尸攻击和植物的掉血和销毁 当僵尸接触到植物开始攻击时会持续削减植物的血量&#xff0c;当植物血量为零时就销毁当前植物。 在plantManager中&#xff0c; 为植物添加一个血量HP 100&#xff0c; public int HP 100; 在写一个减少血量的方法&#xff0c;来减少血…

心理学大纲

简介 psychology&#xff0c;“psyche”(ψυχή):意为"soul"(灵魂)&#xff0c;即对我们灵魂的研究 我的学习的目的 了解人精神世界的模型&#xff0c;人格的形成]&#xff0c;作为观察分析他人内心的理论指导&#xff0c;便于我实践了解情绪的机理&#xff0c;…