Java 泛型:概念、语法和应用

简介: Java 泛型:概念、语法和应用

随着 Java 编程语言的不断发展和更新,Java 1.5 版本引入了一项全新的特性——Java 泛型(Java Generic),这一特性为 Java 程序员提供了一种更加灵活、安全和通用的编程技术。本文将全面介绍 Java 泛型的概念、语法和应用,并提供一些示例代码来帮助您更好地理解和使用 Java 泛型。


一、什么是 Java 泛型?


Java 泛型(Java Generic)是一种编程技术,它允许程序员在编写 Java 类、接口和方法时定义泛型类型参数,这些类型参数可以在代码中表示不同的类型,使得代码变得更加通用、可重用和类型安全。Java 泛型还提供了运行时类型检查机制,可以在运行时捕获类型错误,从而避免出现类型转换异常等常见问题。


二、为什么要使用泛型


需求:存放学生的成绩

//在集合中使用泛型之前的情况:
    @Test!
    public void test(){
        ArrayList list = new ArrayList();
        list.add(99);
        list.add(98);
        list.add(97); 
        }


存在问题:

问题一:类型不安全

list.add("Tom");
• 1

问题二:强转时,可能出现ClassCastException


for(Object score : list){
            int stuScore = (Integer) score;
            System.out.println(stuScore);
  }


在集合中使用泛型的情况:以ArrayList为例


    @Test
    public void test1(){
       ArrayList<Integer> list =  new ArrayList<Integer>();
        list.add(78);
        list.add(87);
        list.add(99);
        list.add(65);
//        list.add("Tom");
//编译时,就会进行类型检查,保证数据的安全
        for(Integer score : list){        //避免了强转操作
            int stuScore = score;
            System.out.println(stuScore);
        }     
    }


三、Java 泛型的语法


Java 泛型的核心语法包括类型参数、类型变量、类型通配符和上下界限制。


  • 1. 类型参数

Java 泛型定义了一组类型参数,这些类型参数可以在类、接口或方法的声明中使用,以表示可以适用于多种不同类型的代码。类型参数使用尖括号(<>)包裹,并且通常使用单个大写字母表示。例如:


class MyGenericClass<T> {}
• 1

上述代码中,类 MyGenericClass 定义了一个泛型类型参数 T,它可以用来表示任何数据类型。

  • 2. 类型变量

类型变量是指在使用泛型类型参数时所定义的具体类型,通常使用小写字母表示。例如:


MyGenericClass<Integer> myGenericInt = new MyGenericClass<Integer>();


上述代码中,我们使用泛型类型参数 T 来定义一个整数类型变量 myGenericInt,并且在实例化类对象时将类型参数 T 替换为具体类型 Integer。


  • 3. 类型通配符

  • 类型通配符使用问号 ? 表示,表示可以接受任意类型的参数。例如:

List<?> myList;



上述代码中,我们定义了一个泛型列表 List,并使用类型通配符 ? 表示可以接受任何类型的数据。


4. 上下界限制

上下界限制用来限制类型参数的范围,包括上界限制和下界限制。


上界限制

上界限制用来限制类型参数的范围,表示类型参数必须是指定类型或指定类型的子类。例如:



class MyGenericClass<T extends Number> {}
• 1

         

上述代码中,我们定义了一个泛型类型参数 T,并使用上界限制 extends Number 表示类型参数必须是 Number 类型或其子类类型。


  1. 下界限制
    下界限制用来限制类型参数的范围,表示类型参数必须是指定类型或指定类型的父类。例如:
void myMethod(List<? super Integer> myList) {}



上述代码中,我们定义了一个方法 myMethod,并使用下界限制 super Integer 表示方法参数必须是 Integer 类型或其父类类型的列表。


四、Java 泛型的应用



Java 泛型可以应用于类、接口、方法等各种代码块中,下面我们将逐一介绍这些用法。

  • 1. 类泛型
    类泛型就是在定义一个类时,在其中定义一个包含泛型类型参数的变量。例如:


java
public class MyGenericClass {
private T element;
public MyGenericClass(T element) {
    this.element = element;
}
public T getElement() {
    return element;
}
public void setElement(T element) {
    this.element = element;
}


上述代码中,我们定义了一个泛型类 MyGenericClass,它的类型参数为 T,我们在其中定义了一个变量 element,它的类型为 T,这样就可以用来存储任意类型的数据。

  • 2. 方法泛型


方法泛型就是在方法的声明中使用泛型类型参数。例如:


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


上述代码中,我们定义了一个泛型方法 printArray,它接受一个泛型数组类型作为参数,使用 for-each 循环遍历数组并打印出每个元素的字符串表示。

  • 3. 接口泛型

接口泛型就是在接口声明中使用泛型类型参数。例如:

public interface MyGenericInterface<T> {
    public T doSomething();
}


上述代码中,我们定义了一个泛型接口 MyGenericInterface,它声明了一个泛型方法 doSomething,返回值类型为 T。


五、Java 泛型的示例


下面我们来看一些 Java 泛型的示例代码,以帮助读者更好地理解和使用 Java 泛型。

  1. 类泛型的示例
public class MyContainer<T> {
    private T element;
    public MyContainer(T element) {
        this.element = element;
    }
    public T getElement() {
        return element;
    }
    public void setElement(T element) {
        this.element = element;
    }
    public static void main(String[] args) {
        MyContainer<Integer> myInt = new MyContainer<>(10);
        MyContainer<String> myString = new MyContainer<>("Hello, World!");
        System.out.println(myInt.getElement());
        System.out.println(myString.getElement());
    }
}



这是一个基于泛型的容器类 MyContainer,它可以存储不同类型的数据,并提供了访问元素和设置元素的方法。通过在类声明中加入一对尖括号 <>,其中的变量 T 表示泛型类型参数,可以使该类变得更加通用和灵活。

在 MyContainer 类的主函数中,我们使用泛型类型参数来创建两个不同类型的实例对象分别存储 Integer 和 String 类型的值,并分别获取元素并输出到控制台。这样,就可以在避免类型转换异常的同时,实现了类型安全和代码复用的效果。


方法泛型的示例


public class MyGenericMethod {
    public static <T> T pickOne(T a, T b) {
        return Math.random() < 0.5 ? a : b;
    }
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "World";
        Integer int1 = 10;
        Integer int2 = 20;
        System.out.println(pickOne(str1, str2));
        System.out.println(pickOne(int1, int2));
    }
}


这是一个使用泛型的方法 pickOne,它接受两个相同类型的参数,并以等概率随机返回其中一个参数。在方法声明的 中,T 表示泛型类型参数,使得该方法可以接受任意类型的参数并且不需要进行类型转换。

在类的主函数中,我们分别创建了两个字符串和两个整数对象,并将它们作为参数传递给了 pickOne 方法,然后输出所返回的结果。在输出语句中,也没有指定具体的数据类型,而是由编译器自动推导出了正确的类型。这样,就可以实现代码复用和类型安全的效果。


接口泛型的示例


public interface MyGenericInterface<T> {
    public T doSomething();
}
public class MyGenericClass implements MyGenericInterface<String> {
    @Override
    public String doSomething() {
        return "Hello, World!";
    }
    public static void main(String[] args) {
        MyGenericClass myGeneric = new MyGenericClass();
        System.out.println(myGeneric.doSomething());
    }
}


这是一个使用泛型接口的示例代码,其中 MyGenericInterface 是一个泛型接口,定义了一个类型参数 T 和一个无参数的方法 doSomething,它返回一个泛型类型 T 的结果对象。

在 MyGenericClass 类中,我们实现了泛型接口 MyGenericInterface,并将泛型类型参数 T 替换为具体类型 String。在 doSomething 方法中,我们返回了一个字符串类型的结果对象 “Hello, World!”。

在类的主函数中,我们创建了一个 MyGenericClass 类的对象,并调用了 doSomething 方法获取它的返回值,并将其输出到控制台。通过使用泛型接口,我们可以灵活地定义和实现不同类型的接口,并保证类型安全和代码复用的效果。


六、总结

总结✌️

泛型的使用 jdk 5.0新增的特性

在集合中使用泛型: 总结:

① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。

② 在实例化集合类时,可以指明具体的泛型类型

③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。 比如:add(E e) —>实例化以后:add(Integer e)

注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换

如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。

相关文章
|
1月前
|
人工智能 安全 Java
Java和Python在企业中的应用情况
Java和Python在企业中的应用情况
54 7
|
5天前
|
存储 Java 程序员
Java的基础概念一
### Java编程基础简介 #### 一、注释 注释用于解释代码,不会参与编译和运行。Java支持三种注释: - **单行注释**:以 `//` 开头。 - **多行注释**:以 `/* ... */` 包围。 - **文档注释**:通常用于生成开发文档。 #### 二、关键字 关键字是被Java赋予特定含义的英文单词,全部小写,且在代码编辑器中有特殊颜色标记。常用的如 `class` 表示定义一个类。
Java的基础概念一
|
5天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
27 2
|
28天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
121 6
|
26天前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
30 2
|
27天前
|
Java
java do while 的语法怎么用?
java do while 的语法怎么用?
39 3
|
1月前
|
关系型数据库 MySQL Java
MySQL索引优化与Java应用实践
【11月更文挑战第25天】在大数据量和高并发的业务场景下,MySQL数据库的索引优化是提升查询性能的关键。本文将深入探讨MySQL索引的多种类型、优化策略及其在Java应用中的实践,通过历史背景、业务场景、底层原理的介绍,并结合Java示例代码,帮助Java架构师更好地理解并应用这些技术。
37 2
|
3天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
5天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
5天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。