Javase ------> 泛型

news2024/11/25 20:40:56

Jdk自从5.0后引入泛型之后一直没有删除,而且在我们的集合框架中进场能使用的到,今天我们就详细介绍一下泛型的一些特性和使用须知,希望能对你的编程学习带来一些帮助.

1.什么是泛型

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?

顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),

然后在使用/调用时传入具体的类型(类型实参)。

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,

操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。

 2.泛型的使用

这里我们引用一个例子

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

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(110);
        list.add("aaa");
        for (int i = 0; i < list.size(); i++) {
            String item = (String)list.get(i);
            System.out.println(item);
        }
    }
}

这里显然产生了错误,ArrayList可以存放任意类型的数据,例子中我添加了一个String类型的数据和一个Integer的数据,但是我都以String类型取出,这就是不可取的,,但是我们如果在声明的时候就给加上一个String泛型,这样如果我添加100,就会在编译期间就报错,同时也提高了代码的可读性.

3.泛型的特性 

泛型实际上只在编译阶段起作用,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。

对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型,我们可以用以下代码加以证明.

 

4.泛型的使用

泛型的定义和使用:在Java中,可以用“<>”来定义泛型。泛型可以定义在类、接口和方法上。在定义泛型时,可以使用一个或多个类型参数,例如<T>、<T, U>等。在使用泛型时,可以用具体的类型来替代类型参数,例如ArrayList<String>、HashMap<Integer, String>等,以下,我们将以泛型类,泛型泛型接口,泛型方法来介绍泛型.

注:泛型的类型参数不能是简单类型,可以是Integer这样的封装类,也可以是自定义类型,但是不能是int这样的简单类型.

 4.1 泛型类

我们先举个例子说明,泛型类的使用

以下示例中,使用“Box<String>”来创建一个可以存储字符串的“Box”对象。在对象创建后,可以使用“set”方法来设置字符串,并使用“get”方法来获取字符串。由于使用了泛型,无需进行类型转换,代码更加简洁和安全。

public class Box<T> {  
    private T item;  
  
    public void set(T item) {  
        this.item = item;  
    }  
  
    public T get() {  
        return item;  
    }  
}

Box<String> stringBox = new Box<String>();  
stringBox.set("Hello World!");  
String item = stringBox.get();  
System.out.println(item); // 输出 "Hello World!"

 泛型类的判断(本质上就是有一个不确定的类型)

先给一个泛型类Order

public class Order<T> {
    //声明了类的泛型参数以后,就可以在类中使用此泛型参数

    T t;//看成有一个类型就是T,可以看成String...
    int OrderId;

    public Order(T t, int orderId) {
        this.t = t;
        OrderId = orderId;
    }

    public Order() {
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public int getOrderId() {
        return OrderId;
    }

    public void setOrderId(int orderId) {
        OrderId = orderId;
    }

    @Override
    public String toString() {
        return "Order{" +
                "t=" + t +
                ", OrderId=" + OrderId +
                '}';
    }
    public <E> ArrayList<E> copy(E[] arr)
    {
        ArrayList <E> list  = new ArrayList<>();
        for(E e : list)
        {
            list.add(e);
        }
        return list;
    }

}
public class SubOrder1 extends Order{
}
//不是泛型类

public class SubOrder2 extends Order<Integer>{
}
//不是泛型类,因为这个时候子类的泛型已经为确定的类型了

public class SubOrder3<T> extends Order<T>{
    public void show()
    {
        System.out.println(t);
    }

}//是泛型类,因为这个时候子类延续了父类的泛型T

public class SubOrder4<E> extends Order<Integer>{
}
//是泛型类,因为这个时候子类的泛型和父类声明的泛型类型不是同一种

public class SubOrder4<T,E> extends Order<T>{
}
//是泛型类

使用说明:要使用泛型类就一路都用,否则就别用,泛型如果没有指明就擦除了,默认用Object,但不等价于Object().

注:不能new E[],但是可以E [ ] elements = (E [ ])new Object[capacity]);因为这时候E是不确定的.

泛型类中声明的泛型参数不能在static方法中使用.因为我们可以在继承或者实例化的时候确定泛型类型,但是类去调用静态方法的时候,此时这个泛型还不确定.

4.1.2 类型推断(JDK7)

这里我们的泛型类的声明也可以是这样的

Box<String> box = new Box<>();

这时候编译器会自动进行类型推断.

或者我们也可以这样写

Box box = new Box("hello");
Box box = new Box(666);

这里不写泛型类型默认就是Object类型的.

4.2 泛型接口

和泛型方法类型,这里不做过多讲解,举一个例子

public interface GenericInterface<T> {  
    T performAction(T input);  
}


public class StringAction implements GenericInterface<String> {  
    @Override  
    public String performAction(String input) {  
        return input.toUpperCase();  
    }  
}

在这个示例中,定义了一个名为“StringAction”的类,它实现了泛型接口“GenericInterface<String>”。这个类实现了“performAction”方法,将传入的字符串转换为大写并返回。由于使用了泛型接口,这个类可以处理任意类型的字符串,提高了代码的可重用性。

注:虽然我们只定义了一个泛型接口,但是我们可以传入无数种类型给泛型参数,使得代码很灵活.

4.3 通配符

通配符就是一个?,它是为了解决泛型类型不兼容问题而出现的,我们之前说过泛型的类型本质上是一样的,我们知道Number是Integer的父类,那么泛型参数为Integer的元素是否能添加到参数为Number中呢?答案是否定的

由此我们得到一个结论:泛型对应多个版本,但是版本之间是不兼容的,为了解决这种不兼容的问题,通配符由此诞生.

4.3.1 通配符的使用
  1. 表示任意类型:可以使用“?”来表示任意类型,例如List<?>表示一个可以存储任意类型的列表。
  2. 表示任意类型的父类:可以使用“? extends T”来表示任意类型是T的子类或者T本身,例如List<? extends Number>表示一个可以存储Number或其子类的列表。
  3. 表示任意类型的子类:可以使用“? super T”来表示任意类型是T的父类或者T本身,例如List<? super Integer>表示一个可以存储Integer或其父类的列表。

 下面我举例说明

1.

List<?> list = new ArrayList<>();
//这个示例中,使用通配符“?”来表示list可以存储任意类型的数据。
//但是由于通配符表示不确定的类型,所以在获取list中的元素时,
//无法确定具体的类型,需要进行类型转换


//类型转换:先用instanceOf方法判断,再转换即可

2.

List<? extends Number> list = new ArrayList<>();
//这个示例中,使用通配符“? extends Number”来表示list可以存储Number或其子类的数据。
//在获取list中的元素时,可以确定元素是Number或其子类,无需进行类型转换。

3.

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

//这个示例中,使用通配符“? super Integer”来表示list可以存储Integer或其父类的数据。
//在获取list中的元素时,可以确定元素是Integer或其父类,无需进行类型转换。

注:在使用通配符时,不能对通配符进行写入操作,即不能向通配符表示的集合中添加元素。这是因为通配符表示不确定的类型,无法确定添加的元素是否符合集合的要求。如果需要进行写入操作,可以使用具体的类型来替代通配符。

例:

public class NumberBox<T extends Number> {  
    private T item;  
  
    public void set(T item) {  
        this.item = item;  
    }  
  
    public T get() {  
        return item;  
    }  
}

NumberBox<Integer> intBox = new NumberBox<>();  
intBox.set(42);  
int value = intBox.get(); // 无需进行类型转换,因为T是Integer类型  
System.out.println(value); // 输出 42

 5. 泛型方法

问:使用了泛型参数的方法就是泛型方法吗?答案是否定的

public class NumberBox<T extends Number> {  
    private T item;  
  
    public void set(T item) {  
        this.item = item;  
    }  
  
    public T get() {  
        return item;  
    }  
}

比如这里的get和set方法就不是泛型方法.

泛型方法举例:

//错误的,这里会将E当做某一个类的名字
public E(E e)
{
    return null;
}



public E<E>(E e)
{
    return null;
}

所以,我们总结出泛型方法的格式

:权限修饰符  <T> 返回值类 方法名(形参列表){}

//通常在形参列表或返回值类型中会出现泛型参数T

说明:在声明泛型方法时,一定要加泛型参数

泛型方法在调用时.一定要指明其具体类型.

例:

public <E>ArrayList<E> fromArrayToList(E[] arr)
{
    ArrayList<E> list = new ArrayList<>();
    for(E e:arr)
    {
        list.add(e);
    }
    return list;
}

这个方法是可以声明为静态的,因为无所谓谁来调用,只要调用时声明泛型即可.

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

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

相关文章

c# 中的类

反射 Activator.CreateInstance class Program {static void Main(string[] args){//反射Type t typeof(Student);object o Activator.CreateInstance(t, 1, "FJ");Student stu o as Student;Console.WriteLine(stu.Name);//动态编程dynamic stu2 Activator.Cre…

【算法】二分相关题目

文章目录 二分相关二分查找在排序数组中查找元素的第一个和最后一个位置寻找峰值x 的平方根0~n-1中缺失的数字## 搜索插入位置 二分相关 二分查找 https://leetcode.cn/problems/binary-search/ 在一个有序数组当中&#xff0c;查找值为target的元素&#xff0c;返回下标 cla…

SSM - Springboot - MyBatis-Plus 全栈体系(十七)

第三章 MyBatis 五、MyBatis 高级扩展 1. mapper 批量映射优化 1.1 需求 Mapper 配置文件很多时&#xff0c;在全局配置文件中一个一个注册太麻烦&#xff0c;希望有一个办法能够一劳永逸。 1.2 配置方式 Mybatis 允许在指定 Mapper 映射文件时&#xff0c;只指定其所在的…

2023年中国家用智能门锁市场发展概况分析:家用智能门锁线上市场销量290.4万套[图]

智能门锁是指区别于传统机械锁的基础上改进的&#xff0c;在用户安全性、识别、管理性方面更加智能化简便化的锁具。智能门锁是门禁系统中锁门的执行部件。智能门锁区别于传统机械锁, 是具有安全性, 便利性, 先进技术的复合型锁具。 智能门锁级别分类 资料来源&#xff1a;共研…

MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving

● MARS: An Instance-aware, Modular and Realistic Simulator for Autonomous Driving&#xff08;基于神经辐射场的自动驾驶仿真器&#xff09; ● https://github.com/OPEN-AIR-SUN/mars ● https://arxiv.org/pdf/2307.15058.pdf ● https://mp.weixin.qq.com/s/6Ion_DZGJ…

flink处理函数--副输出功能

背景 在flink中&#xff0c;如果你想要访问记录的处理时间或者事件时间&#xff0c;注册定时器&#xff0c;或者是将记录输出到多个输出流中&#xff0c;你都需要处理函数的帮助&#xff0c;本文就来通过一个例子来讲解下副输出 副输出 本文还是基于streaming-with-flink这本…

解决SpringBoot Configuration Annotation Processor not configured

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 问题描述 在使用ConfigurationProperties注解和EnableConfigurationProperties注解时&#xff0c;IDEA报错&#xff1a;SpringBoot Configuration Annotation Processor no…

【chainlit】使用chainlit部署chatgpt

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

微服务架构改造案例

最后一个部分&#xff0c;结合我们自己的财务共享平台项目进行了微服务架构改造案例分析。 对于改造前的应用&#xff0c;实际上存在四个方面的问题。 其一是关于高可用性方面的&#xff0c;即传统的单体应用我们在进行数据库水平扩展的时候已经很难扩展&#xff0c;已经出现…

XShell远程连接Ubuntu

环境 系统&#xff1a;Ubuntu 18.04.6 LTS IP&#xff1a;192.168.1.4 ps:查看ubuntu版本 lsb_release -a 查看ubuntu的ip地址 Ubuntu系统准备工作 root权限 打开ubuntu系统后&#xff0c;打开终端&#xff0c;切换为root权限&#xff1a;su root 如果出现su root认证失…

管理经济学基本概念(五):一些基本术语

1、理性-行动者范式 使经济学家行动一致的东西就是采用理性-行动者范式来预判人的行为。简单地说&#xff0c;这个范式认为人们的行动式理性的、优化的和自利的。 2、税后净营业利润 税后经营净利润(NOPAT)是指将公司不包括利息收支的营业利润扣除实付所得税税金之后的数额加…

Acwing 907. 区间覆盖

Acwing 907. 区间覆盖 知识点题目描述思路讲解代码展示 知识点 贪心 题目描述 思路讲解 代码展示 #include <iostream> #include <algorithm>using namespace std;const int N 100010;int n;struct Range {int l, r;bool operator < (const Range &W) …

【day11.02】网络编程脑图

大小端存储&#xff1a; ip地址划分&#xff1a;

MySQL 锁分类和详细介绍

锁是计算机协调多个进程或线程并发访问某一资源的机制&#xff0c;在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源&#xff0c;锁机制是保证数据一致性和并发性的重要手段&#xff0c;它…

软件设计模式系列之二十二——状态模式

1 模式的定义 状态模式是一种行为型设计模式&#xff0c;它允许对象在内部状态发生改变时改变其行为&#xff0c;使得对象的行为看起来像是改变了其类。状态模式将对象的状态抽象成一个独立的类&#xff0c;让对象在不同状态下具有不同的行为&#xff0c;而且可以在运行时切换…

做一个优秀的博士生,时间的付出是必要条件

&#xff0a;图片来自管理学季刊 时间的付出 所有成功的科学家一定具有的共同点&#xff0c;就是他们必须付出大量的时间和心血。这是一条真理。实际上&#xff0c;无论社会上哪一种职业&#xff0c;要想成为本行业中的佼佼者&#xff0c;都必须付出比常人多的时间。有时&…

【知识点随笔分析 | 第六篇】HTTP/1.1,HTTP/2和HTTP/3的区别

前言&#xff1a; 当今互联网已成为人们生活的重要组成部分&#xff0c;而HTTP协议&#xff08;Hypertext Transfer Protocol&#xff09;是支持Web通信的基础。随着Web技术的发展和互联网应用的不断增多&#xff0c;HTTP也在不断演进。本文旨在介绍HTTP的演变过程中的三个重要…

【Godot4.1】Godot实现闪烁效果(Godot使用定时器实现定时触发的效果)

文章目录 准备工作创建Sprite2D创建Timer节点 编写脚本完整代码运行效果 准备工作 如果你希望配置C#编写脚本&#xff0c;可以查看如下教程&#xff1a; Godot配置C#语言编写脚本 创建Sprite2D 首先弄一个用于显示的Sprite2D&#xff0c;右键单击任意节点&#xff0c;然后选…

Transformer在小目标检测上的应用

本篇文章是博主在AI、无人机、强化学习等领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅解。文章分类在AI学…