首页 > 编程语言 >[JAVA]什么是泛型?泛型在Java中的应用

[JAVA]什么是泛型?泛型在Java中的应用

时间:2024-08-21 09:53:42浏览次数:13  
标签:JAVA List 类型 new 泛型 Java 方法 public

目录

1.初识泛型的应用

2.创建自定义泛型类

3.利用较小范围的泛型方法定义

4.了解泛型通配符,什么是泛型通配符?


1.初识泛型的应用

       —所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。

       —定义泛型,可以在编译阶段就检测到类型不匹配的错误,而不是在运行时才发现。

       —允许在定义类,接口,方法时使用类型形参(泛型),这个类型形参将在声明变量,创建对象,调用方法时动态的指定,进而让程序具备编译时检查能力,例如,定义了一个List<String>,就不能向其中添加整数。

2.创建自定义泛型类

自定义泛型类,需要在类名后增加“<标识符>”,如下所示

public  class  SampleClass <T>{...} 

关于标识符命名:

<T> 与 <E> 的区别

标识符的字母本身并无强制要求,常见写法有两种:

<T> 是Type单词的首字母,说明传入的是类型

<E> 是Element元素的首字母,代表是集合中的元素

泛型类如何创建呢?

用代码来描述,首先我们创建一个类CollectionUtils,根据创建自定义泛型类方法在类名后增加

<标识符>

import java.util.ArrayList;
import java.util.List;
import java.util.Random;   //生成随机数



//实现随机选择List中的元素
public class CollectionUtils <E>{               //类后增加泛型<E>
    private List<E> data =new ArrayList();      //自定义泛型类中,与声明的泛型类保持一致
    public void add(E element)                   //向当前List中新增一个元素
    {                
        data.add(element);
    }


在以上代码中

ArrayList ( ):

是Java中ArrayList类中的一个默认构造参数

public class CollectionUtils<E>:

定义了一个名为CollectionUtils的类,并引入了一个类型参数E,这使得该类具有通用性,可以处理不同类型的元素。

private List<E> data = new ArrayList();

创建了一个列表data,用于存储类型为 E 的元素。

public void add(E element):

定义了一个方法add,它接受一个类型为 E 的参数element,并将其添加到 data 列表中

这意味着,无论 E 具体是什么类型(比如整数,字符串,自定义类等),CollectionUtils类都能够·处理和存储这种类型的元素,并通过add方法进行添加操作

定义好自定义泛型类后,我们继续在类中写入方法,利用Java中的Random随机数类写一个randomSelect方法,生成随机数

public E randomSelect(){
   int idx = new Random().nextInt(data.size());//生成一个0(包含)到data集合元素数量(不包含)之间的随机整数,并将其赋值给变量idx
   E ret = data.get(idx);   
   return ret; 
}

在以上代码中

public E randomSelect(){:

定义了名为randomSelect方法,类型与自定义泛型类一致 

int idx = new Random().nextInt(data.size()); :

new Random() 创建了一个Random类的对象,用于生成随机数。

nextInt(data.size()): 调用Random对象的nextInt方法,作用是生成指定范围内的随机整数,并将data.size()作为参数传递进去。

data.size()返回的是列表data中元素的数量。

data.get(idx) 

获取 data 集合中索引为 idx 的元素,并将其赋值给变量 ret ,这里的 E 表示这个返回的元素的类型是在类定义时指定的泛型类型。

定义完 泛型类和编写好生成随机数方法后,就可以编写主函数添加数据

  public static void main(String[] args) {
        CollectionUtils<String> utils= new CollectionUtils<>();// 创建了一个用于存储字符串的 CollectionUtils 对象 utils
        utils.add("张三");
        utils.add("李四");
        utils.add("王五");
        utils.add("赵六");
        String name=utils.randomSelect();   //调用随机数方法,将生成的随机数存储在字符串name里
        System.out.println(name);         //打印name
        
    }

运行结果

 多次运行  发现能产生不同的值,实现了自定义泛型类后生成随机数方法。

自定义泛型类是定义在类级别上的一个泛型,作用于整个类的实例化对象,一旦确定了具体的类型参数,该类的所以方法和成员变量都将使用这个类型,有时候,我们可能只需要将泛型定义在方法体中,不需要定义在整个类别,利用泛型方法,它仅作用于该方法内部,不会影响类的其他部分或其他方法。

3.利用较小范围的泛型方法定义

泛型方法

允许在类没有声明泛型的前提下让方法独立使用泛型进行开发

public <T> List <T> transferToList (T[] array){

 我们首先在PtMethod类下定义一个泛型方法transferToList

public class PtMethod {
public <T>List<T> transferToList(T[] array) {  //定义泛型方法体
    List<T> list =new ArrayList<>();  //创建一个空的ArrayList,利用了泛型,这个列表只能存储类型为T的元素
    for (T item:array){   //增强for循环遍历输入的数组,类型为T              
        list.add(item);   //将数组中的元素逐个添加到ArrayList中
    }
    return list;
}

public <T>List<T> transferToList(T[] array) :

表明这是一个泛型方法,接受一个类型为T的数组作为参数,并返回一个包含相同类型元素的List<T>.

<T>:

表示这是一个泛型方法,类型参数T可以在调用方法时确定具体的类型

然后在主函数main方法中创建数组并调用方法 


 public static void main(String[] args) {
        PtMethod ptMethod=new PtMethod();  //创建一个ptMethod类对象,用于调用transferToList方法
        String[] array =new String[]{"A","B","C","D","E"};//创建字符串数组
        List<String> list=ptMethod.transferToList(array);//调用peMethod对象的transferToList方法,将字符串数组转化为字符串列表。
        System.out.println(list);
    }
}

上面代码中哪里体现了泛型呢?

首先是我们定义的泛型方法 
 


public <T>List<T> transferToList(T[] array) 

<T>表示类型参数,可以在调用这个方法时指定具体类型,例如在main方法中调用这个方法时,传递一个字符串数组,此时T就被推断为String类型,这个方法会返回一个包含String类型元素列表

在方法内部的体现则是

List<T> list =new ArrayList<>(); 

它创建了一个泛型列表,存储类型为T的元素,在调用泛型方法时,根据传入的数组类型确定T的具体类型,从而保证列表只能存储特定类型元素。例如,当传入字符串数组时,这个列表就只能存储字符串

List<Shape> shapeList = new ArrayList<>;
obj.doSth(shapeList); 
4.了解泛型通配符,什么是泛型通配符?

假设我们有一个方法需要处理各种不同类型的集合,例如打印集合中的元素,如果没有泛型通配符,则可以需要为每种类型的集合单独编写一个方法,而利用了泛型通配符则可以用一个方法处理多种类型的集合。因为通配符?表示未知类型

比如我们定义一个方法   <Shape>是泛型

public void doSth(List<Shape> shapeList)

调用时使用Shape类型是允许的

List<Shape>shapeList = new ArrayList<>;
obj.doSth(shapeList);

如果我们在调用过程中使用Shape的子类Circle就会报错 

List<Circle>circleList = new ArrayList<>;
obj.doSth(circleList);

 因为泛型只支持关于类型的精准匹配,如果是其子类的话,传入doSth方法里也是不支持的,为了解决这样的问题,我们需要增加泛型通配符来进行描述

泛型的匹配规则

为了增加泛型的匹配范围,泛型通配符 <?> 应运而生

<?> 通配符与匹配范围

<?> 代表所有类型均可传入

public void doSth(List <?> shapeList)

我们可以在使用泛型的时候增加一个问号(通配符),意味着在当前泛型里写问号的位置上出现任何类型数据都可以接受 

 通常搭配extends与super限定范围

extends关键字代表必须传入Shape或者子类才通过检查

public void doSth(List <? extends Shape > shapeList)

表示只要是Shape和它的子类都是可以在泛型中使用的,这也决定了使用泛型类型的上限最高是Shape,不能够再使用其他类

super关键字代表必须传入Rectangle或者其父类才能通过检查

public void doSth(List <? super Rectangle > shapeList)

表示我们在这里传入使用的类型最低是Rectangle自己或它的父类

通过extends和super关键字,我们就可以用来决定传入泛型类型的范围,下面通过代码形式来理解

我们在开发工具中新建一个包,命名为ShapePro,在包中分别新建Shape(父类),Circle类,ShapeUtiles测试类 

Shape(父类)

public class Shape {
    public void draw(){

    }
}

Circle类(继承父类)

public class Circle extends Shape{
    public void draw(){
        System.out.println("屏幕上画了一个圆");
    }

ShapeUtiles类

import java.util.ArrayList;
import java.util.List;

//通过泛型通配符如何限定使用范围
public class ShapeUtiles {
    public void drawAll(List<? extends Shape> shapeList){ //定义泛型 
        for (Shape shape : shapeList){ 
        shape.draw();
    }
}

    public static void main(String[] args) {
        ShapeUtiles utiles =new ShapeUtiles(); //实例化
        List<Circle> circleList =new ArrayList<>();//因为定义了泛型方法只要是继承父类Shape的子类都可以使用
        utiles.drawAll(circleList);
    }
}

 public void drawAll(List<? extends Shape> shapeList) :

在类中定义了一个方法drawAll,并自定义了泛型方法,类型为Shape的子类型,利用定义泛型方法,保证了在遍历这个列表时,其中的元素都可以安全调用Shape类中定义的方法,而shapeList是一个参数名称

for (Shape shape : shapeList){ shape.draw();:

遍历shapeList列表中的每一个元素,并将当前元素赋值给shape变量,然后调用当前shape对象的draw方法

在以上代码中,我们可以看到通过定义了泛型通配符限制了泛型类型的范围,处理集合时,只能接受Shape类和它的子类,这样可以确保在处理集合时,只操作特定范围内的对象,避免类型不匹配的错误。

总结

  • 泛型提供编译时检查错误
  • 自定义泛型类使用<T>声明
  • <?>是泛型通配符
  • extends决定泛型的上限
  • super决定泛型的下限

标签:JAVA,List,类型,new,泛型,Java,方法,public
From: https://blog.csdn.net/2301_79757798/article/details/141325853

相关文章

  • 783java jsp SSM校园兼职管理系统(源码+文档+开题+运行视频+讲解视频)
      项目技术:SSM+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8......
  • 777java jsp SSM水果蔬菜商品商城管理系统(源码+文档+运行视频+讲解视频)
     项目技术:SSM+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8/1......
  • 782java jsp SSM课程辅助教学网站系统(源码+文档+开题+运行视频+讲解视频)
     项目技术:SSM+Maven+Vue等等组成,B/S模式+Maven管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8/1......
  • 基于Java+SpringBoot+Vue的房屋租赁管理系统的设计与实现
    基于Java+SpringBoot+Vue的房屋租赁管理系统的设计与实现前言✌全网粉丝20W+,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌......
  • java opencv 获取图中物品的倾斜角度(单个物品,如果存在多个物品,建议先将多个物品处理成
    //1、先连上opencv包System.setProperty("java.awt.headless","false");System.out.println(System.getProperty("java.library.path"));URLurl=ClassLoader.getSystemResource("lib/opencv/opencv_java4100.dll");System.load(url.g......
  • 深入Java虚拟机JVM类加载学习笔记
    1.类加载过程----------以及风中叶老师在他的视频中给了我们一段程序,号称是世界上所有的Java程序员都会犯的错误加载---验证---准备---解析---初始化---使用---卸载诡异代码如下:packagetest01;classSingleton{ publicstaticSingletonsingleton=newSingleton();......
  • 学习Java第八周
    子类只能从被扩展的父类获得成员变量、方法和内部类(包括内部接口、枚举),不能获得构造器和初始化块。2.Java类只能有一个直接父类,实际上,Java类可以有无限多个间接父类。3.如果定义一个Java类时并未显式指定这个类的直接父类,则这个类默认扩展java.lang.Object类4.super限定public......
  • Lodash 使用详解:提升 JavaScript 开发效率的利器
    引言在现代JavaScript开发中,处理数组、对象、字符串等数据类型的操作频繁且复杂。尽管JavaScript本身已经提供了一些内置方法,但它们有时不够直观,或者在处理复杂场景时显得笨拙。Lodash是一个功能丰富的JavaScript实用工具库,它提供了简洁、高效的API来处理这些常见......
  • 深入理解Java中的Bytecode操作与ASM框架
    引言Java字节码是Java虚拟机(JVM)执行的一种中间语言,它是Java源代码编译后的结果。字节码操作是指直接操作Java类文件的字节码,通过修改字节码可以进行一些动态的、灵活的程序操作。在实际开发中,字节码操作有诸多应用场景,如性能优化、代码生成、运行时代理等。ASM框架是一个强大......
  • Java并发编程 - 基础(悲观锁与synchronized)(偏向锁、轻量级锁、锁优化)
    Java并发编程中的悲观锁和synchronized关键字,以及Java内存模型中的锁优化机制(如偏向锁、轻量级锁)都是非常重要的概念。下面将详细介绍这些内容。悲观锁(PessimisticLocking)悲观锁假设数据会发生冲突,因此在读取数据时就加锁,以防止其他线程修改数据。这种方式虽然能保......