课时97:泛型通配符

简介: 本文围绕Java泛型展开,深入探讨其在解决对象强制转换安全隐患的同时所引发的新问题,特别是引用传递处理方面的困境。通过实际代码示例,详细介绍通配符问号及其扩展(设置泛型上限和下限)的使用方法与作用,帮助读者理解这些概念在Java编程中的重要性及应用场景。1.泛型引发的问题2.通配符问号的使用3.通配符的扩展:设置泛型上限和下限

课时97:泛型通配符

摘要:本文围绕Java泛型展开,深入探讨其在解决对象强制转换安全隐患的同时所引发的新问题,特别是引用传递处理方面的困境。通过实际代码示例,详细介绍通配符问号及其扩展(设置泛型上限和下限)的使用方法与作用,帮助读者理解这些概念在Java编程中的重要性及应用场景。

1. 泛型引发的问题

2. 通配符问号的使用

3. 通配符的扩展:设置泛型上限和下限


01、 泛型引发的问题


Java泛型在帮助开发者解决对象强制转换带来的安全隐患的同时,也产生了新的问题,其中较为突出的是引用传递处理问题。

1.1 案例程序展示

首先看一个简单的Java程序示例。定义一个泛型类`Message<T>`:

class Message<T> {
    private T content;
 
    public void setContent(T content) {
        this.content = content;
    }
 
    public T getContent() {
        return this.content;
    }
}
```
 
    public static void main(String[] args) {
        Message<String> msg = new Message<>();
        msg.setContent("www.mldn.cn");
        fun(msg)
再编写一个测试方法`fun`:
    public static void fun(Message<String> temp) {
        System.out.println(temp.getContent());
    }    }
}


这段代码实现了一个基本的引用传递,在这个示例中,`fun`方法仅能接收`Message<String>`类型的对象。

image.png

1.2 泛型类型兼容性问题

问题的关键在于fun()方法上,如果真的希望`fun`方法能接收任意泛型类型的`Message`对象,例如将其参数类型改为`Message<Integer>`,会出现编译错误,提示不兼容类型,`Message<Integer>`无法转换为`Message<String>`。这就暴露出了泛型在引用传递时的问题:当需要处理多种泛型类型时,代码的兼容性和灵活性受到了限制。这个时候它只能接受“message<string>”类型。

image.png

1.3 方法重载的困境

有开发者可能会想到通过方法重载来解决这个问题,例如定义多个不同参数类型的`fun`方法:

public static void fun(Message<String> temp) {
    // 方法体
}
 
public static void fun(Message<Integer> temp) {
    // 方法体
}

然而,这种做法会导致名称冲突,因为在Java中,方法重载要求方法的参数类型或个数不同,而泛型类型在方法签名中并不被视为不同的参数类型。如果不断添加不同泛型类型的重载方法,当泛型类型众多时,代码将变得冗长且难以维护。

1.4 不使用泛型的风险

如果不设置泛型,代码虽然能够编译和执行,但会带来严重的安全隐患。例如:

public class JavaDemo {
public static void main(String args[]) {
        Message<Integer> msgA = new Message<Integer>;
        Message<Integer> msgB = new Message<String>;
        msg.setContent(110);
        fun(msgA);
        msgB.setContent(“www.mldn.cn”);
        fun(msgB);
    }
}
    public static void fun(Message temp) {
        System.out.println(temp.getContent());
    }

image.png

如果我们在编译一个temp.setContent(1.1)。在这个例子中,由于没有泛型的约束,`setContent`方法可以接受任意类型的数据,这可能导致数据类型不一致的错误,在实际编程中会引发难以排查的问题。

image.png

 

02、 通配符问号的使用


为了解决上述问题,可以使用通配符问号(`?`)。在方法参数中使用`Message<?>`,表示该方法可以接收任意泛型类型的`Message`对象,但不能修改其内容,只能获取数据。

2.1 通配符的作用示例

修改`fun`方法如下:

public static void fun(Message<?> temp) {
    System.out.println(temp.getContent());
}

此时,`fun`方法可以接收不同泛型类型的`Message`对象,如`Message<String>`、`Message<Integer>`等,同时避免了因类型不兼容导致的编译错误,并且保证了数据的安全性,防止在方法内部意外修改数据。

 

03、 通配符的扩展:设置泛型上限和下限

3.1 设置泛型上限

使用`? extends 类型`来设置泛型上限,表示该泛型类型必须是指定类型或其子类型。例如,`? extends Number`表示泛型类型只能是`Number`或`Number`的子类。

public static void fun(Message<? extends Number> temp) {
    // 方法体
}

在这种情况下,如果传递给`fun`方法的`Message`对象的泛型类型不是`Number`或其子类型,将会出现编译错误。

image.png

删掉string后执行成功。

  image.png

3.2 设置泛型下限

使用`? super 类型`来设置泛型下限,表示该泛型类型必须是指定类型或其父类型。例如,`? super String`表示泛型类型只能是`String`或其父类(如`Object`)。

public static void fun(Message<? super String> temp) {
    // 方法体
}

image.png

当传递给`fun`方法的`Message`对象的泛型类型不符合下限要求时,同样会出现编译错误。

image.png

更改msgA.setcontent(“www.mldn.cn“),再一次执行

image.png

Java泛型在解决对象强制转换安全隐患的同时,带来了引用传递处理的问题。通配符问号及其扩展(设置泛型上限和下限)为解决这些问题提供了有效的途径。


通配符问号允许方法接收任意泛型类型的对象,同时限制对其内容的修改,保证数据安全;泛型上限和下限则进一步细化了对泛型类型的约束,提高了代码的安全性和可读性。在学习和使用Java系统类库时,会频繁遇到这些概念的应用,因此深入理解并掌握它们对于Java编程至关重要。

相关文章
|
JavaScript 前端开发 编译器
看完这篇文章,不再害怕Vue3的源码(一)
看完这篇文章,不再害怕Vue3的源码
|
JavaScript
源码学习:Vite中加载环境变量(loadEnv)的实现
源码学习:Vite中加载环境变量(loadEnv)的实现
7894 0
|
9月前
|
设计模式 Java 开发者
课时92:案例分析一(获取类信息)
本文通过具体的Java开发案例,深入讲解抽象类与接口的相关知识,旨在巩固概念,引导读者深入思考,并掌握接口在实际编程中的应用,同时强调代码编写规范。 在Java编程中,抽象类与接口是极为核心的概念,它们也是众多设计模式的综合体现。在后续的学习过程中,开发者会频繁接触到系统提供的接口和抽象类。 因此,深入理解并巩固这些概念至关重要。在接口与抽象类都可使用的情况下,应优先选用接口,这是因为接口能有效避免单继承的局限性。接下来,将通过实际案例对相关概念进行分析。
119 4
|
9月前
|
Java C语言
课时8:Java程序基本概念(标识符与关键字)
课时8介绍Java程序中的标识符与关键字。标识符由字母、数字、下划线和美元符号组成,不能以数字开头且不能使用Java保留字。建议使用有意义的命名,如student_name、age。关键字是特殊标记,如蓝色字体所示。未使用的关键字有goto、const;特殊单词null、true、false不算关键字。JDK1.4后新增assert,JDK1.5后新增enum。
193 4
|
前端开发 数据库 数据安全/隐私保护
【项目实战】登录与注册业务的实现(前端+后端+数据库)
【项目实战】登录与注册业务的实现(前端+后端+数据库)
3055 0
【项目实战】登录与注册业务的实现(前端+后端+数据库)
|
存储 缓存 关系型数据库
如何优化大表的查询速度?
本文介绍了优化大数据表查询速度的方法。关键点包括:1) 创建索引以加快查询;2) 优化查询语句,避免全表扫描;3) 使用缓存来提高查询效率,利用内存访问速度快和IO操作少的优势;4) 提升硬件配置,如使用固态硬盘和增加内存;5) 数据归档和分离,减少主表数据量;6) 实施数据库分片,如分库分表技术,以分散数据并提高并发性能。分库分表包括只分库、只分表(横向和纵向)以及两者结合,常见的分库分表中间件有ShardingSphere、MyCAT、TDDL和Vitess。这些策略通常结合使用,以应对大数据量查询的挑战。
940 1
|
SQL Java 数据库连接
深入 MyBatis-Plus 插件:解锁高级数据库功能
Mybatis-Plus 提供了丰富的插件机制,这些插件可以帮助开发者更方便地扩展 Mybatis 的功能,提升开发效率、优化性能和实现一些常用的功能。
1427 26
深入 MyBatis-Plus 插件:解锁高级数据库功能
|
8月前
|
Oracle 安全 关系型数据库
【Oracle】使用Navicat Premium连接Oracle数据库两种方法
以上就是两种使用Navicat Premium连接Oracle数据库的方法介绍,希望对你有所帮助!
1628 28
|
Unix Linux 测试技术
Linux系统之wget命令的基本使用
【8月更文挑战第4天】Linux系统之wget命令的基本使用
690 5
|
12月前
|
监控 数据可视化 项目管理
关键路径法在项目管理中的实践:从理论到落地的全过程
使用关键路径法(CPM),为你的项目梳理清晰的“优先级”与“全局策略”。
1548 2
关键路径法在项目管理中的实践:从理论到落地的全过程

热门文章

最新文章