如何快速理解并掌握Java泛型的概念和使用方法

Java泛型(Generics)是Java SE 5引入的一种语言特性,旨在增强类型安全性和代码的重用性。泛型允许类、接口和方法操作对象的特定类型,同时在编译时进行类型检查。通过使用泛型,我们可以编写更通用、更灵活的代码,而无需在每个新类型时都重复实现相同的逻辑。

一、泛型的基本概念

泛型的核心思想是参数化类型,即将类型参数化,使代码可以操作多种类型,而无需指定具体的类型。例如,可以创建一个泛型类或方法,使其能够处理任意类型的对象,而不仅仅是某一种特定类型。

1. 泛型类

泛型类是包含一个或多个类型参数的类。类型参数用尖括号<>括起来,并放在类名之后。例如:

public class Box<T> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

在上述示例中,Box类是一个泛型类,其中T是类型参数。我们可以用不同的类型来实例化这个类:

public class GenericClassDemo {
    public static void main(String[] args) {
        Box<String> stringBox = new Box<>();
        stringBox.setContent("Hello");
        System.out.println("String content: " + stringBox.getContent());

        Box<Integer> integerBox = new Box<>();
        integerBox.setContent(123);
        System.out.println("Integer content: " + integerBox.getContent());
    }
}
2. 泛型方法

泛型方法是定义了一个或多个类型参数的方法。类型参数在方法的返回类型之前声明。例如:

public class GenericMethodDemo {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.println(element);
        }
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = {"A", "B", "C"};

        printArray(intArray);
        printArray(strArray);
    }
}

在上述示例中,printArray方法是一个泛型方法,其中T是类型参数。该方法可以处理任意类型的数组。

3. 泛型接口

与泛型类类似,泛型接口也可以定义类型参数。例如:

public interface Pair<K, V> {
    K getKey();
    V getValue();
}

public class OrderedPair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public OrderedPair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public K getKey() {
        return key;
    }

    @Override
    public V getValue() {
        return value;
    }
}

在上述示例中,Pair接口和OrderedPair类都是泛型的,可以使用不同的类型来创建实例:

public class GenericInterfaceDemo {
    public static void main(String[] args) {
        Pair<String, Integer> pair = new OrderedPair<>("One", 1);
        System.out.println("Key: " + pair.getKey());
        System.out.println("Value: " + pair.getValue());
    }
}
二、泛型的使用方法

泛型在Java中有多种应用方式,包括限定泛型类型、泛型通配符和泛型方法等。

1. 类型边界

可以使用类型边界来限制类型参数的范围。Java提供了上界和下界来定义类型边界。

上界

上界通过关键字extends指定,表示类型参数必须是指定类型或其子类型。例如:

public class Box<T extends Number> {
    private T content;

    public void setContent(T content) {
        this.content = content;
    }

    public T getContent() {
        return content;
    }
}

在上述示例中,T必须是Number类或其子类的类型。

下界

下界通过关键字super指定,表示类型参数必须是指定类型或其父类型。例如:

public class LowerBoundDemo {
    public static void addNumber(List<? super Integer> list) {
        list.add(10);
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        addNumber(numberList);
        System.out.println(numberList);
    }
}

在上述示例中,方法addNumber接受一个元素类型为Integer或其父类型的列表。

2. 通配符

通配符?用于表示未知类型,主要用于以下几种情况:

无界通配符

无界通配符表示任何类型。例如:

public class UnboundedWildcardDemo {
    public static void printList(List<?> list) {
        for (Object elem : list) {
            System.out.println(elem);
        }
    }

    public static void main(String[] args) {
        List<String> strList = Arrays.asList("A", "B", "C");
        printList(strList);

        List<Integer> intList = Arrays.asList(1, 2, 3);
        printList(intList);
    }
}

在上述示例中,printList方法可以接受任何类型的列表。

有界通配符

有界通配符分为上界通配符和下界通配符。

上界通配符

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

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1, 2, 3);
        printList(intList);

        List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
        printList(doubleList);
    }
}

在上述示例中,printList方法接受元素类型为Number或其子类型的列表。

下界通配符

public class LowerBoundedWildcardDemo {
    public static void addNumber(List<? super Integer> list) {
        list.add(10);
    }

    public static void main(String[] args) {
        List<Number> numberList = new ArrayList<>();
        addNumber(numberList);
        System.out.println(numberList);

        List<Object> objectList = new ArrayList<>();
        addNumber(objectList);
        System.out.println(objectList);
    }
}

在上述示例中,addNumber方法接受元素类型为Integer或其父类型的列表。

三、泛型在集合框架中的应用

Java集合框架广泛使用了泛型,使得集合类在类型安全性和灵活性上得到了极大的提升。以下是一些常见的泛型集合类及其应用:

1. List

List接口及其实现类如ArrayListLinkedList等都使用了泛型。例如:

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

public class GenericListDemo {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("Hello");
        stringList.add("World");

        for (String str : stringList) {
            System.out.println(str);
        }
    }
}

在上述示例中,List<String>表示一个存储String类型元素的列表。

2. Set

Set接口及其实现类如HashSetTreeSet等也使用了泛型。例如:

import java.util.HashSet;
import java.util.Set;

public class GenericSetDemo {
    public static void main(String[] args) {
        Set<Integer> integerSet = new HashSet<>();
        integerSet.add(1);
        integerSet.add(2);
        integerSet.add(3);

        for (Integer num : integerSet) {
            System.out.println(num);
        }
    }
}

在上述示例中,Set<Integer>表示一个存储Integer类型元素的集合。

3. Map

Map接口及其实现类如HashMapTreeMap等也使用了泛型。例如:

import java.util.HashMap;
import java.util.Map;

public class GenericMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);

        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
    }
}

在上述示例中,Map<String, Integer>表示一个存储键为String类型、值为Integer类型的映射。

四、泛型的高级用法
1. 类型擦除

Java泛型是通过类型擦除实现的,这意味着在编译时泛型信息会被移除,替换为其原始类型(通常是Object)。这也意味着无法在运行时获取泛型类型的信息。例如:

public class ErasureDemo {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        List<Integer> integerList = new ArrayList<>();
        
        System.out.println(stringList.getClass() == integerList.getClass()); // true
    }
}

在上述示例中,虽然stringListintegerList是不同类型的列表,但在运行时它们的类型是相同的。

2. 泛型与反射

由于类型擦除的存在,在使用反射时处理泛型类型需要特别小心。例如:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflectionGenericDemo {
    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList<>();
        list.add("Hello");

        Method method = list.getClass().getMethod("add", Object.class);
        method.invoke(list, 123);

        for (Object obj : list) {
            System.out.println(obj);
        }
    }
}

在上述示例中,通过反射将Integer类型的元素添加到List<String>中,这在编译时不会报错,但在运行时会导致逻辑错误。

3. 泛型数组

由于类型擦除的限制,Java不支持直接创建泛型数组。例如:

public class GenericArrayDemo<T> {
    private T[] array;

    @SuppressWarnings("unchecked")
    public GenericArrayDemo(int size) {
        array = (T[]) new Object[size]; // 需要强制类型转换
    }

    public void set(int index, T value) {
        array[index] = value;
    }

    public T get(int index) {
        return array[index];
    }

    public static void main(String[] args) {
        GenericArrayDemo<String> stringArray = new GenericArrayDemo<>(10);
        stringArray.set(0, "Hello");
        System.out.println(stringArray.get(0));
    }
}

在上述示例中,需要通过强制类型转换创建泛型数组,并使用@SuppressWarnings("unchecked")注解来抑制编译器警告。

Java泛型提供了一种强大的机制,用于在编写通用代码时增强类型安全性和代码重用性。通过泛型,我们可以创建通用的类、接口和方法,而不必在每次需要处理新类型时重新实现相同的逻辑。泛型在Java集合框架中得到了广泛应用,极大地提高了代码的可读性和安全性。

黑马程序员免费预约咨询

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

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

相关文章

Linux用docker安装ElasticsearchSpringBoot整合ES

一. 部署Elasticsearch 1. docker查询docker容器中的es docker search elasticsearch 2. 安装&#xff08;PS&#xff1a;查看自己的springBoot的版本号 对应的es版本安装&#xff09; docker pull elasticsearch:7.6.23. 查看已安装的docker镜像 docker images4. 创建挂…

再论Web应用在医学研究中构建数据收集问卷(stremlit_survey包体验)

再论Web应用在医学研究中构建数据收集问卷&#xff08;Streamlit_survey包体验&#xff09; 概述 医学队列研究是临床研究的重要形式&#xff0c;这种研究通过收集临床诊疗过程中产生的数据而阐述疾病相关的因素。在临床数据收集过程中&#xff0c;Web APP体现出了一定的优势…

SpringBoot项目本地运行正常,jar包运行时前端报错403:No mapping for......

SpringBoot项目本地运行正常&#xff0c;jar包运行时前端报错403&#xff1a;No mapping for… 提示&#xff1a;在部署jar包到云服务器上之前&#xff0c;一定要在本地运行jar包&#xff0c;查看前端代码是否运行正常&#xff0c;若报错的话可以节省很多时间 方式&#xff1a;…

Linux命令篇(六):vi/vim专项

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝您生活愉快&#xff01; 文章目录 一、什么是vim二…

弘君资本:如何看待股价波动?

在股票商场上股价的动摇无疑是投资者最为关怀的话题之一&#xff0c;面临股价的起伏不定投资者往往会感到迷茫和焦虑。对于怎么看待股价动摇&#xff0c;弘君资本下面就为我们具体介绍一下。 股价动摇是股市运转的常态&#xff0c;股市是国民经济的晴雨表&#xff0c;股票价格…

关于大模型是否开源的分析

引言 随着科技的迅速发展&#xff0c;大模型技术成为推动人工智能前沿的引擎&#xff0c;而开源与闭源之争成为这场技术风暴中的一道独特风景。特斯拉CEO马斯克的言论将开源的旗帜高高举起&#xff0c;宣示着技术的共享和合作的时代已经来临。然而&#xff0c;在数字化时代&am…

机器视觉检测--光源

一&#xff0c;环形光源 较为常见的LED光源之一&#xff0c;提供基本的照明作用。 随着光源距离产品的工作距离LWD变化而产生的亮度分布&#xff0c;如下图暖色表示亮&#xff1b;冷色表示暗。 同时该图示是针对特定一款大小的环形光源的数据&#xff08;下同&#xff09;。 二…

【二进制部署k8s-1.29.4】八、worker端安装kubelet和cotainerd

文章目录 简介 一.安装containerd1.1.安装containerd1.2.生成containerd配置文件并启动 二.安装kubelet并配置启动文件2.1.准备kubelet配置文件及证书2.2.安装kubelet2.3.配置启动脚步 三.将node节点加入集群注意事项 简介 本章节主要讲解安装containerd和kubelet,containerd主…

【Android】使用EventBus进行线程间通讯

EventBus 简介 EventBus&#xff1a;github EventBus是Android和Java的发布/订阅事件总线。 简化组件之间的通信 解耦事件发送者和接收者 在 Activities, Fragments, background threads中表现良好 避免复杂且容易出错的依赖关系和生命周期问题 Publisher使用post发出…

什么是公有云?与私有云的区别

公有云是指第三方提供商通过公共Internet为用户提供的云服务&#xff0c;用户可以通过Internet访问云并享受各类服务&#xff0c;包括并不限于计算、存储、网络等。公有云服务的模式可以是免费或按量付费。 微 思 | 好 课 推 荐 &#xff08;全国直播&#xff09; 【公有云】华…

Nginx企业级负载均衡:技术详解系列(18)—— 作为上传服务器

你好&#xff0c;我是赵兴晨&#xff0c;97年文科程序员。 在上一期的技术分享中&#xff0c;我们探讨了如何高效搭建Nginx下载服务器&#xff0c;并讨论了长连接优化策略。那么今天&#xff0c;咱们进一步了解Nginx的另一面——作为上传服务器的配置技巧。 作为上传服务器&a…

Ollama 如何排除故障

Ollama 日志 Mac 有时&#xff0c;Ollama 可能无法如你所愿运行。解决问题的一个好方法是查看日志。在 Mac 上&#xff0c;你可以通过运行以下命令来查看日志&#xff1a; cat ~/.ollama/logs/server.logLinux 在使用 systemd 的 Linux 系统上&#xff0c;可以用这个命令查…

Elastic Security 在 AV-Comparatives 的恶意软件防护测试中表现出色

作者&#xff1a;Jamie Hynds, Tamarian Del Conte, Roxana Gheorghe 针对真实恶意软件提供 100% 防护&#xff0c;零误报 Elastic Security 在最近的 AV-Comparatives 恶意软件防护测试中取得了显著的成绩&#xff0c;防护率达到 100%&#xff0c;且对真实恶意软件样本无误报…

Proteus 安装报错There is a problem with this Windows lnstaller package

Proteus 安装常见问题 1.安装秘钥(许可证)的时候报错 报错信息如下所示&#xff1a; There is a problem with this Windows lnstaller package. A program required for this instalt to compiete coutd notbe run,contact your support personnet or packagevendor. 这个是…

通用代码生成器应用场景六,为完善的应用系统收集需求

通用代码生成器应用场景六&#xff0c;为完善的应用系统收集需求 使用急就章功能可以开发一个简单的应用先凑和着使用。此应用系统也可以成为完善的应用系统的原型和祖先。如果您新规划一个完善的应用系统&#xff0c;您可以先使用通用代码生成器生成一个临时使用的系统&#x…

【VAE-base】VAE最简单代码实现(纯全连接层实现变分自编码机)

VAE &#xff08;Variational Autoencoder&#xff09; 代码&#xff1a;https://github.com/AntixK/PyTorch-VAE/blob/master/models/vanilla_vae.py 论文&#xff1a;Auto-Encoding Variational Bayes 核心参考1 https://github.com/lyeoni/pytorch-mnist-VAE/blob/master/p…

IPD推行成功的核心要素(八)市场管理与产品规划保证做正确的事情

产品开发管理是“正确地执行项目”&#xff0c;而市场管理及产品规划关注“执行正确的项目”&#xff0c;可以说后者对产品的成功更为关键。要实现产品的持续成功&#xff0c;还得从源头的市场管理抓起。成功的产品开发&#xff0c;必须面向市场需求&#xff0c;由需求牵引创新…

FlyMcu串口下载STLINK Utility

FlyMcu是串口下载 STLINK Utility是STLINK下载 生成hex文件 打开hex文件&#xff0c;点击开始编程 在编程之前&#xff0c;需要配置BOOT引脚&#xff0c;让STM32执行BootLoader&#xff0c;否则点击开始编程&#xff0c;程序会一直卡住。第一步STM32板上有跳线帽&#xf…

SuperSocket 服务器与客户端双向通讯

1、使用AppSession 的Send方法就可以向连接到的客户端发送数据。服务器端代码如下。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;//引入命名空间 using SuperSocket.Common; using SuperSocket.So…

【机器学习】逻辑回归:原理、应用与实践

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 逻辑回归&#xff1a;原理、应用与实践引言1. 逻辑回归基础1.1 基本概念1.2 Sig…