49天精通Java,第14天,Java泛型方法的定义和使用

在这里插入图片描述

目录

    • 一、基本介绍
      • 1、Java泛型的基本语法格式为:
      • 2、在使用泛型时,还需要注意以下几点:
    • 二、泛型的优点
      • 1、类型安全
      • 2、消除强制类型转换
      • 3、更高的效率
      • 4、潜在的性能收益
    • 三、常见泛型字母含义
    • 四、使用泛型时的注意事项
    • 五、泛型的使用
      • 1、泛型类
      • 2、泛型接口
      • 3、泛型通配符
      • 4、泛型方法
    • 六、Java泛型上下边界
      • 1、上边界
      • 2、下边界
    • 七、泛型擦除

大家好,我是哪吒。

一、基本介绍

Java泛型(Generics)是一种强类型约束机制,用于在编译时检查代码的类型安全性。它可以让程序员定义一些具有通用性的类、接口和方法,以便在后续使用中可以适用于不同的数据类型。

1、Java泛型的基本语法格式为:

public class Student<T> {
    private T value;

    public void setValue(T value) {
        this.value = value;
    }

    public T getValue() {
        return value;
    }
}

在上面的示例代码中,我们定义了一个泛型类MyClass,其中T表示类型参数(Type Parameter)。在类的成员变量和方法中,我们都可以使用T来代替实际的数据类型,从而实现对不同数据类型的支持。

通过使用泛型,可以大大提高代码的可读性和类型安全性,并且避免了需要进行强制类型转换的繁琐操作。同时,泛型还可以提高代码的重复利用率,减少代码量,提高开发效率。

2、在使用泛型时,还需要注意以下几点:

  1. 泛型只能使用引用类型,不能使用基本类型;
  2. 不能创建泛型数组,但可以使用泛型集合;
  3. Java的泛型是通过类型擦除(type erasure)实现的,在编译期间会被转换为原始类型,因此无法在运行时获取泛型类型的具体信息;
  4. Java中的泛型不支持协变和逆变,但Java SE 8及以上版本引入了一些新特性来支持函数式编程中的协变和逆变。

二、泛型的优点

1、类型安全

泛型的主要目的是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在非常高的层次上验证类型假设。没有泛型,这些假设就只能存在于系统开发人员的头脑中。

通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误就可以在编译时被捕获了,而不是在运行时当作ClassCastException展示出来。将类型检查从运行时挪到编译时有助于Java开发人员更早、更容易地找到错误,并可提高程序的可靠性。

2、消除强制类型转换

泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。尽管减少强制类型转换可以提高使用泛型类的代码的累赞程度,但是声明泛型变量时却会带来相应的累赞程度。在简单的程序中使用一次泛型变量不会降低代码累赞程度。但是对于多次使用泛型变量的大型程序来说,则可以累积起来降低累赞程度。所以泛型消除了强制类型转换之后,会使得代码加清晰和筒洁。

3、更高的效率

在非泛型编程中,将筒单类型作为Object传递时会引起Boxing(装箱)和Unboxing(拆箱)操作,这两个过程都是具有很大开销的。引入泛型后,就不必进行Boxing和Unboxing操作了,所以运行效率相对较高,特别在对集合操作非常频繁的系统中,这个特点带来的性能提升更加明显。

4、潜在的性能收益

泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,Java系统开发人员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的JVM的优化带来可能。

三、常见泛型字母含义

格式: 类名<字母列表>

  1. T Type表示类型
  2. K V 分辨表示键值对中的key value
  3. E 代表Element
  4. ?表示不确定的类型

四、使用泛型时的注意事项

1、在定义一个泛型类时,在“<>”之间定义形式类型参数,例如:“class TestGen<K,V>”,其中“K”,“V”不代表值,而是表示类型。

2、实例化泛型对象时,一定要在类名后面指定类型参数的值(类型),一共要有两次书写。

3、使用泛型时,泛型类型必须为引用数据类型,不能为基本数据类型,Java中的普通方法,构造方法,静态方法中都可以使用泛型,方法使用泛型之前必须先对泛型进行声明,可以使用任意字母,一般都要大写。

4、不可以定义泛型数组。

5、在static方法中不可以使用泛型,泛型变量也不可以用static关键字来修饰。

6、根据同一个泛型类衍生出来的多个类之间没有任何关系,不可以互相赋值。

7、泛型只在编译器有效

五、泛型的使用

泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法

1、泛型类

//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Student<T> {
    //key这个成员变量的类型为T,T的类型由外部指定
    private T key;
    //泛型构造方法形参key的类型也为T,T的类型由外部指定
    public Student(T key){
        this.key = key;
    }
    //泛型方法getKey的返回值类型为T,T的类型由外部指定
    public T getKey(){
        return key;
    }
 
    public static void main(String[] args) {
        //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
        //传入的实参类型需与泛型的类型参数类型相同,即为Integer.
        Student<Integer> student = new Student<Integer>(123456);
        //传入的实参类型需与泛型的类型参数类型相同,即为String.
        Student<String> str= new Student<String>("哪吒编程");
        System.out.println("泛型测试,key is "+student .getKey());
        System.out.println("泛型测试,key is "+str.getKey());
    }
}

泛型参数就是随便传的意思!

Student student1 = new Student("哪吒编程");
Student student2 = new Student(4444);
Student gstudent3 = new Student(55.55);
Student student4 = new Student(false);

2、泛型接口

泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中,可以看一个例子:

//定义一个泛型接口
public interface Generator<T> {
    public T next();
}

当实现泛型接口的类,未传入泛型实参时:

/**
 * 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
 * 即:class FruitGenerator<T> implements Generator<T>{
 * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
 */
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}

当实现泛型接口的类,传入泛型实参时:

package javase.genericity;
 
import java.util.Random;
 
public class FruitGenerator implements  Generator<String>{
    String[] fruits = new String[]{"apple","banana","Pear"};
    @Override
    public String next() {
        Random random = new Random();
        System.out.println(fruits[random.nextInt(3)]);
        return fruits[random.nextInt(3)];
    }
 
    public static void main(String[] args) {
        FruitGenerator ff = new FruitGenerator();
        ff.next();
    }
}

3、泛型通配符

Java泛型通配符(wildcard)用于表示某个类型参数可以接受任意类型的实参,采用“?”作为通配符。

在使用泛型时,有时候需要定义一个方法或类,能够接受多种类型的参数。这时就可以使用泛型通配符来实现。Java中有三种泛型通配符:extends、super和无限制通配符。

(1)extends通配符

表示该类型参数是某个特定类型的子类或本身,可以接受该类型及其子类的实参。

例如:

public void printList(List<? extends Number> list) {
    for (Number n : list) {
        System.out.println(n);
    }
}

(2)super通配符

表示该类型参数是某个特定类型的超类或本身,可以接受该类型及其父类的实参。

例如:

public void addList(List<? super Integer> list) {
    list.add(1);
    list.add(2);
    list.add(3);
}

(3)无限制通配符

表示该类型参数可以接受任意类型的实参。

例如:

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

泛型通配符只能用于方法参数、返回值和局部变量等地方,不能用于类的定义中。同时,在使用泛型通配符时应该遵循PECS原则(Producer Extends, Consumer Super),即生产者使用extends通配符,消费者使用super通配符,以保证类型安全。

4、泛型方法

Java中的泛型方法是指在方法名称前加上的方法,它可以接受任意类型的参数。

下面是一个简单的示例:

public class GenericExample {  
    public <T> T[] createArray(T[] array) {  
        return array;  
    }  
}

在上面的示例中,createArray方法接受一个T[]类型的参数,并返回一个T[]类型的数组。在方法体中,我们可以使用array参数来创建一个T[]类型的数组。

需要注意的是,泛型方法的参数类型必须与方法体中的参数类型相同。如果方法体中的参数类型与方法名称前加上的参数类型不同,则编译器会报错。

六、Java泛型上下边界

Java泛型上下边界是指在定义泛型时,我们可以通过指定类型参数的上限或下限来限制实际参数的类型范围。

1、上边界

使用extends关键字来限制类型参数的上限,表示该类型参数必须是指定类型的子类或本身。

public class MyClass<T extends Number> {
    // 类定义
}

在上面的示例中,我们使用extends关键字将类型参数T的上限指定为Number类,表示只有Number及其子类才能作为实参传递进来。

2、下边界

使用super关键字来限制类型参数的下限,表示该类型参数必须是指定类型的超类或本身。

public class MyClass<T super Integer> {
    // 类定义
}

在上面的示例中,我们使用super关键字将类型参数T的下限指定为Integer类,表示只有Integer及其父类才能作为实参传递进来。

需要注意的是,在使用上下边界时,如果同时指定了上下边界,则应该先指定下边界再指定上边界。同时,在使用上下边界时也需要遵循PECS原则(Producer Extends, Consumer Super),即生产者使用extends通配符,消费者使用super通配符,以保证类型安全。

七、泛型擦除

Java泛型擦除是指在Java编译器将泛型类型的代码编译成字节码时,会将所有泛型类型的信息删除,以避免运行时带来的额外开销。

在Java中,泛型只是一种编译时检查机制,并不会影响程序的运行时行为。在编译期间,Java编译器会将泛型类型擦除为原始类型,并在必要时插入强制类型转换语句。

List<String> list = new ArrayList<>();
list.add("哪吒编程");
String s = list.get(0);

然我们使用了泛型类型List,但在编译后,它会被擦除为List,因此get()方法返回的实际类型为Object,并且需要进行强制类型转换才能得到String类型的值。

由于泛型擦除的存在,导致在运行时无法获取泛型类型的具体信息,因此在使用反射和类型转换等相关操作时需要格外小心,以避免产生类型安全问题。

需要注意的是,在Java SE 8及以上版本中,引入了新的特性来支持对函数式接口中的泛型类型进行推断和获取,以及在局部变量初始化时使用类型推断,从而进一步提高了泛型的灵活性和可读性。


在这里插入图片描述

🏆本文收录于,49天精通Java从入门到就业。

全网最细Java零基础手把手入门教程,系列课程包括:基础篇、集合篇、Java8新特性、多线程、代码实战,持续更新中(每周1-2篇),适合零基础和进阶提升的同学。

🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师。

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

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

相关文章

第五章 Vite4+Vue3+Vtkjs 自定义按键组合

一、介绍 因为Vtk.js在按键和按键组合上默认就指定了对应的事件处理,但是我们在使用其他软件的时候可能已经养成了一种习惯,然后也希望使用Vtk.js的时候按键对应的事件也是一致的。比如右键是平移模型,或者说shift+鼠标右键是平移,不管是什么按键的组合,对应的事件是我们…

颠覆认知!“垃圾股”策略长期跑,10年翻100倍、近2年6倍,吊打茅指数!| 邢不行

这是一个非常简单的量化选股策略&#xff0c;它只用到了两个基础选股指标。 代表策略的橙色曲线2010年至今从1元涨到了112元&#xff0c;年化收益43%&#xff1b;在近两年大盘下跌的情况下&#xff0c;这个策略更是逆势翻了6倍。 这个量化策略究竟用了哪两个选股指标&#xf…

java TreeSet 和 TreeMap 源码解读

目录 一、前言 二、TreeSet详解 1.TreeSet简介 2.TreeSet的底层实现 0 准备工作 1 TreeSet构造器 2 匿名内部类实现接口的多态 3 TreeMap构造器 4 add方法 5 put方法和put方法 6 继续添加元素 7 修改比较器的比较原则 三、TreeMap详解 1.TreeMap简介 2.TreeMap的底层实现 0…

拥有良好的社交和友谊会使肠道微生物群更健康

谷禾健康 播种肠道&#xff0c;喂养心灵 在新冠疫情的影响下&#xff0c;我们的生活方式和社交模式都发生了很大的改变。随着社交距离的要求和封锁措施的实施&#xff0c;我们不得不放弃了很多与朋友和家人的互动&#xff0c;这给我们的身心健康带来了很大的影响。 然而&#x…

区块链学习笔记(3)BTC协议

假设有一个大家都信任的中心化机构想要发行数字货币。 该机构由用自己的私钥签名后后发行&#xff0c;任何人都可以通过公钥验证该货币是否为真。 买东西的时候&#xff0c;购买者可以将数字货币发送给卖方&#xff0c;卖方可以也可以通过公钥验证该货币为真后即可完成支付的过…

子网掩码和CIDR

CIDR是什么 网络标识相同的计算机必须同属于同一个链路。例如&#xff0c;架构B类IP网络时&#xff0c;理论上一个链路内允许6万5千多台计算机连接。然而&#xff0c;在实际网络架构当中&#xff0c;一般不会有在同一个链路上连接6万5千多台计算机的情况。因此&#xff0c;这种…

蓝桥杯刷题冲刺 | 倒计时7天

作者&#xff1a;指针不指南吗 专栏&#xff1a;蓝桥杯倒计时冲刺 &#x1f43e;最后一周&#xff0c;复习学过的知识&#xff0c;刷题冲刺&#x1f43e; 文章目录1.高精度除法2.扫地机器人3.数的范围4.A-B 数对1.高精度除法 题目 链接&#xff1a; 794. 高精度除法 - AcWing题…

Java对象内存布局

文章目录1、对象头对象标记Mark Word类元信息&#xff08;又叫类对象指针&#xff09;Class Pointer数组长度&#xff08;Array Length&#xff09;&#xff08;可选&#xff09;2、实例数据&#xff08;对象体&#xff09;3、对齐填充4、指针压缩5、再聊对象头的MarkWord6、JO…

Android ART虚拟机 Space类体系

前言 在ART虚拟机实现中&#xff0c;内存分配和释放的算法是封装在不同的Space中来完成的。而外部使用者只能借助Space及派生类的接口来完成内存的分配与释放。通过阅读这些Space的实现&#xff0c;可以看出ART虚拟机的一个重要的特点就是大量使用映射内存&#xff0c;相较于D…

思维导图软件哪个好?安利八款好用的思维导图软件

当你需要表达和整理复杂的想法、计划和项目时&#xff0c;思维导图软件可以是非常有用的工具。不同的思维导图软件有不同的功能和特点&#xff0c;选择适合自己的软件可以让你更高效地工作和学习。但是你了解思维导图软件哪个好呢&#xff1f;下面就给大家安利八款简单好用的思…

分享99个ASP影音娱乐源码,总有一款适合您

分享99个ASP影音娱乐源码&#xff0c;总有一款适合您 99个ASP影音娱乐源码下载链接&#xff1a;https://pan.baidu.com/s/1pYpAqFUX0xD8KR8GDRyiug?pwd3lja 提取码&#xff1a;3lja Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 我的博客地址&#xff1a;亚…

1Panel开源面板项目GitHub Star数量突破2,000!

截至2023年4月4日18:00&#xff0c;FIT2CLOUD飞致云旗下开源项目——1Panel开源Linux服务器运维管理面板GitHub Star数超过2,000个&#xff01;

IDE装上ChatGPT,一天开发一个系统

昨天白天在写代码&#xff0c;晚上看了一场直播&#xff0c;是两个技术的直播&#xff1a; 一个是技术总监&#xff0c;一个是号称Java之父的余**。 结果Java之父被技术总监吊打。然后匆匆下播。 技术这玩意&#xff0c;真的就是真的&#xff01; 白天我开发了一个系统&…

LeetCode.每日一题 2427. 公因子的数目

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

ModuleNotFoundError: No module named ‘gdal‘

目录 一、问题描述 二、解决方法 一、问题描述 在win系统下使用gdal包的时候&#xff0c;使用下面代码pip安装&#xff1a; conda install glob -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 安装过程中没有报错&#xff0c;但是 import 的时候还是报错了…

Vicuna:与ChatGPT 性能最相匹配的开源模型

Vicuna (由stable diffusion 2.1生成)前言最近由UC Berkeley、CMU、Stanford, 和 UC San Diego的研究人员创建的 Vicuna-13B&#xff0c;通过在 ShareGPT 收集的用户共享对话数据中微调 LLaMA获得。其中使用 GPT-4 进行评估&#xff0c;发现Vicuna-13B 的性能达到了ChatGPT 和 …

脑外伤最怕后遗症?做好这6大家庭护理措施,防止后遗症

脑外伤是生活中常见的一种情况&#xff0c;主要也就是由于意外或者是其他原因造成的脑部外伤。脑外伤也属于神经系统疾病的一种&#xff0c;最主要是因为对脑部的组织细胞以及神经造成了巨大伤害&#xff0c;从而引起的一系列不良症状的疾病&#xff0c;这种时候也就需要做护理…

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台学习前言什么是HRNetV2模型代码下载HRNetV2实现思路一、预测部分1、主干网络介绍a、Section-1b、Section-2c、Section-3d、Section-42、特征整合部分3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS…

python123

文章目录温度转换异常处理百分制成绩转换五分制F正整数AB奇偶求和判断数据类型温度转换异常处理 描述‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪…

数组切分 蓝桥杯 DFS DP

⭐ 数组切分 输入 4 1 3 2 4输出 5⭐ 区间最大值 - 区间最小值 区间长度&#xff1a;说明该区间为连续的自然数 &#x1f920; 暴馊dfs &#xff08;过 50 % 的案例&#xff09; import java.util.*;public class Main {static int mod 1000000007, n;static int res 0…