JAVA泛型详细学习

本文深入讲解Java泛型的基础概念及应用技巧,包括泛型的作用、泛型通配符的使用,以及如何在类、接口和方法中应用泛型。通过对比非泛型集合类与泛型集合类的实例,展示泛型带来的类型安全性优势。

泛型

之前对泛型一直没有系统的学习,直到学习函数式编程时才发现还是有很多空缺,现在就系统的学习一下。

1. 概述

泛型在Java中还是比较重要的,提供了编译时的类型检查。泛型的解释是参数化的类型。这还是比较好理解的,就是将类型作为一个参数提供给方法或者类,就和方法的形参是类似的,不过写法不一样。在我们调用方法的时候才会确定具体需要的类型。泛型可以用在类,接口,方法上,被称为泛型类,泛型接口,泛型方法。

2. 对比

可能说的还是有点抽象了,举个大家常用的例子对比一下就知道了,我们现在想要存一组数字

List list = new ArrayList();
list.add(100);	//int型数据
list.add("20");	//String类型数据
for (int i = 0; i < list.size(); i++){
    Integer item = (Integer)list.get(i);	//这一步会在运行时报类型转换异常
	System.out.println(item);
}
List<Integer> list = new ArrayList<>();
list.add(100);
list.add("20");	//这一步将在编译时报错

从上面这两个代码中我们就能看出不使用泛型的话,编译时期是无法发现类型错误的,而运行时会可能会产生类型转换异常,这是因为在向list中存入数据的时候没有对存入数据的类型进行约束。而使用泛型的话将强制我们传入的数据类型与之匹配,否则就无法通过编译。这里强调一点泛型仅在编译时有效,运行时无效

3. 泛型通配符

在介绍泛型的使用之前,需要先了解几个通配符:

  • T:type,表示一个Java类型
  • K:key,代表键值对中的key
  • V:value,代表键值对中的value
  • E:element,代表集合中的element
  • ?:标识不确定的Java类型

这些通配符都可以使用 super,extends来定义上界和下界,super就表示必须是某个类或它的超类,extends表示是某个类或它的子类

3.1 T 和 ?

T代表一个Java类型(注意这里说的是一个),在同一个类型或方法中,T不管使用多少次,都代表相同的类型。而?则表示不确定的java类型,?代表的类型可能不一致。并且T是可以当作一个类型来使用的,而?不是可以的

栗子

T t = test();	//正确✔
? u = test();	//错误❌

//param1和param2类型相同,param3和param4类型不一定相同
public <T extends Number> void test(T param1, T param2, <? extends Object> param3, <? extends Object> param4){
    
}

4. 使用

前面说了泛型使用有三种,泛型类,泛型接口,泛型方法。

4.1 泛型类

格式:类型名称后面加<泛型通配符>

public class Test<T>{
    // 这里指定属性类型为T
    private T arg;
    // 构造函数参数指定为泛型
    public Test(T arg){
        this.arg = arg
    }
}

根据在3.1节讲的,在同一个类型或方法中,T不管使用多少次,都代表相同的类型。这个Test类中所有的T都代表同一个类型。

Test<Integer> test = new Test<Integer>("123"); //编译不通过
Test<Integer> test = new Test<Integer>(123);  //编译通过

4.2 泛型接口

和泛型类大致相同,值得注意的是,实现接口时也要将泛型带上

public insterface MyMap<T>{
    public T print();
    public void set (T param);
}
// 必须添加泛型,否则编译不同通过
public class MyMapImpl<T> implements MyMap<T>{
    
}

4.3 泛型方法

泛型方法相对泛型类来说稍微难一些,泛型方法的定义是需要在权限修饰符和返回类型之间增加<泛型通配符>。public <T> void print(T param)只是使用了泛型通配符定义参数的方法不是泛型方法,如:public void print(T param)

泛型类型中可以有泛型方法,但如果有定义的通配符相同,则以泛型方法中的通配符为准。T可以当作一个类型来使用

public class Test<T> {
    // 泛型方法形参中的T和泛型类中的T不是同一个类型。
    public <T> void print(List<T> params){
        for(T item : params){
            ...
        }
    }
}

5. 总结

泛型给我们提供了编译时类型检查的功能,合理的运用泛型可以在很大程度上避免我们运行时抛出类型转化异常,这一点在集合类中体现最明显。泛型仅在编译时发挥作用,运行时没有泛型的概念,所以不要试图比较泛型类。如:new ArrayList<String>().getClass().equals(new ArrayList<Integer>().getClass())测试结果总是相等的。

<think>好的,我现在需要帮助用户寻找Java学习示例和教程。用户提供的引用内容都是关于Java的介绍、基本示例和用途。首先,我要整理这些引用中的信息,看看有哪些可以直接用来回答用户的问题。 用户明确提到想要学习示例和教程,所以需要结构化的回答,分步骤介绍的不同方面,比如方法、类、接口等,每个部分都要有代码示例。根据引用1,可以用于方法、类和接口,引用2提到参数化类,引用3强调类安全和重用组件,引用4提到集合中的使用。这些点都需要涵盖。 接下来,我需要确保回答符合用户给出的系统级指令:使用正确的中文,数学表达式用$...$,独立公式用$$...$$,不过这里可能用不上数学公式,但要注意代码块的格式。同时要生成相关问题,并在回答末尾添加引用标识。 用户可能对的基础概念和应用场景不太清楚,所以需要从简单到复杂逐步讲解,每个部分都给出示例代码,并引用对应的来源。比如,方法的示例可以来自引用1或4,类的示例可能来自引用2或3,接口部分可能来自引用1或4。同时要提到类安全的好处,如引用3所述。 还需要注意避免使用Markdown格式,但用户给的示例中代码块用了三个反引号,这可能是指示正确,但根据用户可见层的说明,可能需要保持结构清晰,用自然的中文分点回答。 最后,生成的相关问题要围绕Java的深入内容,比如类擦除、通配符、最佳实践等,帮助用户进一步学习。引用标识要自然地放在引用内容的末尾,如引用[^1]、[^2]等,根据提供的四个引用来源来分配。 现在需要组织这些信息,确保每个部分都有示例代码,解释清楚,并正确引用来源。检查是否有遗漏的重要概念,比如的好处、类擦除的问题,或者实际应用案例。确保回答逻辑流畅,步骤分明,符合用户的需求。</think>### Java学习示例与教程分步指南 --- #### 一、基础概念 Java的核心是**参数化类**,允许在类、接口或方法中定义类参数,提高代码复用性和类安全性。例如,集合类`ArrayList<T>`中的`T`即为类参数,可指定为`String`或`Integer`。 --- #### 二、方法示例 方法通过类参数声明(如`<T>`)实现类无关操作: ```java // 方法:交换数组元素 public static <T> void swap(T[] array, int i, int j) { T temp = array[i]; array[i] = array[j]; array[j] = temp; } ``` 此方法可处理任意类的数组(如`String[]`或`Integer[]`)[^4]。 --- #### 三、类示例 类在类名后添加类参数`<T>`,用于定义成员变量或方法: ```java // 类:容器类 public class Box<T> { private T content; public void setContent(T content) { this.content = content; } public T getContent() { return content; } } // 使用示例 Box<String> stringBox = new Box<>(); stringBox.setContent("Hello Generics"); ``` 通过`Box<Integer>`可存储整数类,避免强制类转换[^2][^3]。 --- #### 四、接口示例 接口常用于定义通用操作规范,例如比较接口: ```java // 接口:比较器 public interface Comparator<T> { int compare(T o1, T o2); } // 实现接口的字符串比较器 public class StringComparator implements Comparator<String> { @Override public int compare(String s1, String s2) { return s1.length() - s2.length(); } } ``` 此设计支持扩展多种数据类比较逻辑[^4]。 --- #### 五、类限定与通配符 1. **限定类参数**:用`extends`约束类范围 ```java public static <T extends Number> double sum(T a, T b) { return a.doubleValue() + b.doubleValue(); } ``` 此方法仅接受`Number`子类(如`Integer`或`Double`)。 2. **通配符`?`**:增强灵活性 ```java public void printList(List<?> list) { for (Object elem : list) { System.out.println(elem); } } ``` 可处理任意类的`List`(如`List<? extends Number>`)[^4]。 --- #### 六、在集合中的应用 Java集合框架广使用,避免运行时类错误: ```java List<String> names = new ArrayList<>(); names.add("Alice"); // names.add(123); // 编译时报错 String firstName = names.get(0); // 无需强制转换 ``` 通过,编译器会检查元素类一致性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值