首页 > 编程语言 >Java泛型Generics​入门详解

Java泛型Generics​入门详解

时间:2023-11-24 19:02:11浏览次数:39  
标签:Java ArrayList 类型 void Generics 泛型 static public

Java泛型Generics

泛型基础知识

  • 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
  • 泛型的格式:<数据类型>
  • 注意:泛型只能支持引用数据类型。如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型,此时可以往集合中添加任意的数据类型。带来一个坏处是由于多态的存在,我们在获取数据的时候,无法使用他的特有行为。此时推出了泛型,可以在添加数据的时候就把类型进行统一。而且我们在获取数据的时候,也避免了强转,使用上非常的方便。
    泛型的优点
    ●统一数据类型。
    ●把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
    Java中的泛型是伪泛型,也即仅存在Java源码中,在编译后的.class文件中泛型信息将不复存在,这种行为称为泛型的擦除。
    泛型的注意点
  • 泛型中不能写基本数据类型
  • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
  • 如果不写泛型,类型默认是Object

自定义泛型

泛型可以在很多地方进行定义。

  • 类后面 泛型类
  • 方法上面 泛型方法
  • 接口后面 泛型接口

泛型类

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

格式:

修饰符class类名<类型>{
}

举例:

public class ArrayList<E>{
}

创建该类对象时,E就确定类型。此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,一般可以写成:T、E、K、V等。

泛型方法

方法中形参类型不确定时,可以使用类名后面定义的泛型<E>。

方法中形参类型不确定时

方案①:使用类名后面定义的泛型 所有方法都能用

方案②:在方法申明上定义自己的泛型 只有本方法能用

格式:

修饰符<类型> 返回值类型 方法名(类型变量名){
}

举例:

Public <T> void show(T t){
}

此处T可以理解为变量,但是不是用来记录数据的,而是记录类型的,可以写成:T、E、K、V等。

如下代码中包含一个addAll方法,注意泛型占位符要放在修饰符的后面,本例中是static关键字后面。

import java.util.ArrayList;

public class ListUtil {
 private ListUtil(){}

 public static<E> void addAll(ArrayList<E> list, E e1, E e2, E e3, E e4, E e5){
 list.add(e1);
 list.add(e2);
 list.add(e3);
 list.add(e4);
 list.add(e5);
 }
}

泛型接口

格式:

修饰符interface接口名<类型>{
}

举例:

public interface List<E>{
}

泛型接口的重点是如何使用一个泛型接口。

  • 方式1:实现类给出具体类型
  • 方式2:实现类延续泛型,创建对象时再确定

如下:

class MyArrayList2 implements List<String>{

}

class MyArrayList2<E> implements List<E>{

}

泛型的通配符

泛型不具备继承性,但是数据具备继承性。如下代码method方法要求一个ArrayList<Object>类型的参数,而如果传入子类Date(Object是所有类型的父类)的对象列表则会报错。

import java.util.ArrayList;
import java.util.Date;

public class GenericsDemo {
 public static void main(String[] args) {
 ArrayList<Object> list = new ArrayList<>();
 ArrayList<Date> dlist = new ArrayList<>();

 method(dlist); // 报错。泛型不具备继承性,但是数据具备继承性。

 // 如果要让method方法不报错则应使用list包含Date对象
 // 则可以先向list对象中添加Date对象
 list.add(new Date());
 list.add(new Date());

 method(list); // 不会报错。体现出数据具备继承性
 }

 public static void method(ArrayList<Object> l){

 }
}

有时候类或方法虽然不确定类型,但是希望只能传递具有继承关系的一类类型时,我们就可以使用泛型的通配符

?也表示不确定的类型,他也可以进行类型的限定

  • ?: 与字符占位符一样,单独用表示所有类型
  • ? extends E:表示可以传递E或者E所有的子类类型
  • ? super E:表示可以传递E或者E所有的父类类型

应用场景

1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。

2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符泛型的通配符。

关键点:可以限定类型的范围。

import java.util.ArrayList;

public class GenericsDemo2 {

 public static void main(String[] args) {
 
 }

 public static void method1(ArrayList<?> p){ // 直接使用?时不用在修饰符后的尖括号类声明?问号

 }

 public static void method2(ArrayList<? extends Ye> p){

 }

 public static void method3(ArrayList<? super Fu> p){

 }
}

// 爷爷类
class Ye{}
// 父亲类
class Fu extends Ye{}
// 儿子类
class Zi extends Fu{}


综合练习

需求:

定义一个继承结构:

Java泛型Generics​入门详解_泛型


属性:名字,年龄

行为:吃东西

波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干

狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼

泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭

哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家

测试类中定义一个方法用于饲养动物

public static void keepPet(ArrayList<???>list){
//遍历集合,调用动物的eat方法
}

要求1:该方法能养所有品种的猫,但是不能养狗

要求2:该方法能养所有品种的狗,但是不能养猫

要求3:该方法能养所有的动物,但是不能传递其他类型


import java.util.ArrayList;
import java.util.Iterator;

public class TestMain {
 public static void main(String[] args) {
 Cat c1 = new LihuaCat();
 }

 // 需求1
 public static void keepPet1(ArrayList<? extends Cat> cats){
 Iterator<? extends Cat> citer = cats.iterator();
 while (citer.hasNext()){
 citer.next().eat();
 }
 }


 // 需求2
 public static void keepPet2(ArrayList<? extends Dog> dogs){
 Iterator<? extends Dog> citer = dogs.iterator();
 while (citer.hasNext()){
 citer.next().eat();
 }
 }

 // 需求3
 public static void keepPet3(ArrayList<? extends Animal> animals){
 Iterator<? extends Animal> citer = animals.iterator();
 while (citer.hasNext()){
 citer.next().eat();
 }
 }
}

泛型小结

1.什么是泛型?

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

2.泛型的好处?

●统一数据类型

●把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。

3.泛型的细节?

●泛型中不能写基本数据类型

●指定泛型的具体类型后,传递数据时,可以传入该类型和他的子类类型

●如果不写泛型,类型默认是Object

4.哪里定义泛型?

●泛型类:在类名后面定义泛型,创建该类对象的时候,确定类型

●泛型方法:在修饰符后面定义方法,调用该方法的时候,确定类型

●泛型接口:在接口名后面定义泛型,实现类确定类型,实现类延续泛型

5.泛型的继承和通配符

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

●泛型的通配符:?

? extend E

? super E

6.使用场景

●定义类、方法、接口的时候,如果类型不确定,就可以定义泛型

●如果类型不确定,但是能知道是哪个继承体系中的,可以使用泛型的通配符










标签:Java,ArrayList,类型,void,Generics,泛型,static,public
From: https://blog.51cto.com/tangxiaohu/8550899

相关文章

  • Java登陆第十三天——网络编程(三)DatagramSocket
    DatagramSocket使用DatagramSocket(数据套接字)可以进行UDP程序的开发,此类可以建立单向地、不可靠地、快速地通信。在UDP编程中,混淆了服务端和客户端的概念。因为通信是单向的,所以身份可以随时切换。(也有人把TCP称作服务端客户端,UDP称作发送端和接收端)DatagramSocket类常用......
  • java多线程学习之路-不能理解
    1importjava.util.concurrent.CountDownLatch;23/**4*颠覆理解的,为什么不会出问题,执行多次,结果都是正确,并且一致5*/6classMyData{7inta=5;//可预定总座位数8intb=0;//已预定座位数910publicvoidyd(){11if(b<......
  • Java Web实现文件下载的几种方式
    文件下载可以说是网站的基础功能,要实现最下载功能,有一种最基本的方法,那就是将超链接的href属性指向对应的资源文件。如下面连接指向了百度首页的图片:​ ​I'mtheindexofBaidu​​但这种方式的缺陷也是很明显的,目录信息被获取,不利于信息安全。其实信息安全还是其次,主要还是......
  • JAVA进阶 —— 方法引用
    原文链接:https://blog.csdn.net/hdakj22/article/details/129453599一、内容概述方法引用可以拆分为方法和引用两方面:方法引用:把已经有的方法拿过来用,当作函数接口中抽象方法的方法体。::(方法引用符)但是要注意:并不是所有的方法都可以直接引用,需要满足以下四种条件引用......
  • JavaScript数组中的常用函数解析
    1.splice方法当使用splice()方法时,可以传递不同的参数来实现不同的操作。以下是splice()方法的参数说明:array.splice(start,deleteCount,item1,item2,...);start:必需,指定要进行操作的起始索引位置。如果该值为负数,则表示从数组末尾开始计算的偏移量。例如,-1表示倒数第......
  • java 关于 Finalizer 过多导致内存(Res)缓慢上涨
     病因:事情的起因是由Flume的项目采集问题引发的.测试人员发现用top命令查看采集进程的Res一直不断上涨姿势.所以怀疑是内存泄漏.  一,对症下药首先,第一步肯定是先瞅瞅代码,看看有没有那些资源啥的没关闭,正如读者所想----没有发现.二,通过辅助工具最......
  • 这篇保证你彻底搞懂Java NIO的Selector事件选择器
     Selector提供选择执行已经就绪的任务的能力,使得多元I/O成为可能,就绪选择和多元执行使得单线程能够有效率地同时管理多个I/Ochannel。C/C++许多年前就已经有select()和poll()这两个POSIX(可移植性操作系统接口)系统调用可供使用。许多os也提供相似的功能,但对Java程序......
  • Java实验报告五
    实验五实验名称:文件与I/O流实验目的:掌握文件与输入输出流的使用。实验时间:(2学时)实验类型:验证型实验内容:1.创建类:FindFile.java,遍历当前目录,打印目录中文件名称,目录打印”isDirectory”,文件打印“isfile”。修改程序打印当前目录及子目录信息。提示:当前目录名用......
  • JavaWeb中的文件的上传和下载
    文件上传1.要有一个form标签,method=post请求2.form标签的encType属性的值必须为multipart/form-data值3.在from标签中使用inputtype=file添加上传的文件4.编写服务器代码接收上传的数据Content-Type:表示提交的数据类型enctype="multipart/form-data":表示提交的数据,以多段(每......
  • Java线程生命周期
    操作系统线程生命周期操作系统线程生命状态有5种。初始状态(New)进程正在被创建时的状态。仅为线程对象开辟了一块堆内存,实际上线程在操作系统层面还未创建。就绪状态(Ready)可运行,由于其他进程处于运行状态而暂时停止运行运行状态(Running)该进程此时正占用CPU......