什么是泛型?---通俗易懂

什么是泛型?

泛型(Generics)是一种在编程中提供类型安全和代码复用的机制。

泛型允许在定义类、接口、方法时不指定具体的类型,而是在使用时再明确。这样做的好处有很多:

  1. 提高了代码的复用性:通过使用泛型,可以编写一个通用的逻辑,适用于多种不同的类型,而无需为每种类型都单独编写类似的代码。
  2. 增强了类型安全性:可以避免在运行时出现类型转换错误。例如,如果一个方法期望接收整数类型,使用泛型可以确保不会错误地传入其他类型的数据。

比如说,在 Java 中,我们可以定义一个泛型类 Box<T> 来表示一个可以存储任意类型对象的盒子:

class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

在这个例子中,Box类是一个泛型类,其中T是类型参数。T可以在Box类的定义中用作变量类型。可以创建 Box 的不同类型实例,如 Box<Integer> 用于存储整数,Box<String> 用于存储字符串。

为什么需要泛型?

在没有泛型的情况下,我们可能需要为每个数据类型都编写相应的类或方法,这样会导致代码冗余,并且难以维护。而有了泛型,我们可以将类型作为参数传递给类或方法,使其具有通用性,可以处理多种类型的数据。

  1. 适用于多种数据类型执行相同的代码

    private static int add(int a, int b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }
    
    private static float add(float a, float b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }
    
    private static double add(double a, double b) {
        System.out.println(a + "+" + b + "=" + (a + b));
        return a + b;
    }

    如果没有泛型,要实现不同类型的加法,每种类型都需要重载一个add方法;通过泛型,我们可以复用为一个方法:

    private static <T extends Number> double add(T a, T b) {
        System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
        return a.doubleValue() + b.doubleValue();
    }

 基本语法

泛型的基本语法包括泛型类、泛型接口和泛型方法。

泛型类

public class Box<T> {
    private T content;
    public void setContent(T content) {
        this.content = content;
    }
    public T getContent() {
        return content;
    }
}

泛型接口

public interface Container<T> {
    void add(T item);
    T get(int index);
}

泛型方法

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

使用示例

泛型类使用

Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
System.out.println(content);

泛型方法使用

Integer[] intArray = {1, 2, 3, 4, 5};
Util.printArray(intArray);

String[] strArray = {"A", "B", "C"};
Util.printArray(strArray);

好啦,到这就可以啦,下面的是扩展,可以了解

泛型的实现原理

Java 的泛型实现采用了类型擦除的方式。这意味着在编译阶段,泛型类型的信息会被擦除,替换为其上限类型(如果没有指定上限类型,则默认是 Object 类型)。

例如,对于 List<String> 这样的泛型类型,在编译后的字节码中,它会被视为 List 。在运行时,实际上并不存在具体的泛型类型信息。

这样做的好处是保持了 Java 字节码的向后兼容性,但也带来了一些限制,比如不能在运行时获取泛型的具体类型参数。

如何编写一个泛型类?

首先,按照某种类型,例如:String,来编写类:

public class Pair {
    private String first;
    private String last;
    public Pair(String first, String last) {
        this.first = first;
        this.last = last;
    }
    public String getFirst() {
        return first;
    }
    public String getLast() {
        return last;
    }
}

然后,把特定类型String替换为T,并申明<T>

public class Pair<T> {
    private T first;
    private T last;
    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }
    public T getFirst() {
        return first;
    }
    public T getLast() {
        return last;
    }
}

类型参数 <T>

类型参数是用于定义泛型类、接口和方法时的占位符,表示某种类型。

在泛型中,<T>中的 T 确实是自定义的,常见的类型参数有:

  • T:表示类型(Type)。
  • E:表示集合元素(Element)。
  • K``和 V`:分别表示键(Key)和值(Value)。
  • N:表示数字(Number)。
  • S, U, V等:用于多个类型参数的情况。

但是,这些都是约定俗成的,并不是强制的。你可以使用任何合法的字母或标识符作为泛型参数。

使用多个类型参数

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

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

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

在这个例子中,Pair类使用了两个类型参数KV,分别表示键和值。

虽然可以使用任意字母作为类型参数,但使用有意义的字母(如TEKV等)更有助于代码的可读性和理解。如果你的代码涉及多个类型参数,建议选择有意义的字母来表示不同的类型。

类型参数使用示例

定义一个泛型类 Box

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");
String content = stringBox.getContent();

通配符 <?>

通配符是用于实例化泛型类型时表示未知类型的占位符,用来表示不确定的类型,常见的有三种:

  1. 无界通配符<?>,表示任意类型。
  2. 有界通配符(上界)<? extends T>,表示类型必须是T或者T的子类。
  3. 有界通配符(下界)<? super T>,表示类型必须是T或者T的父类。

通配符使用示例

定义一个方法来处理任何类型的Box

public static void printBox(Box<?> box) {
    System.out.println(box.getContent());
}

调用这个方法:

Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
printBox(stringBox);

Box<Integer> intBox = new Box<>();
intBox.setContent(123);
printBox(intBox);

在这个例子中,<?>是一个无界通配符,表示方法printBox可以接受任何类型的Box

限定类型参数示例

有时候需要对类型参数进行限制,例如只允许某个类型及其子类:

public class NumberBox<T extends Number> {
    private T number;

    public void setNumber(T number) {
        this.number = number;
    }

    public T getNumber() {
        return number;
    }
}

在这个例子中,T被限定为Number类型及其子类。

总结:泛型是Java中强大的特性,通过参数化类型提高了代码的复用性和类型安全性。理解和合理使用泛型可以显著提升代码的质量和可维护性。

  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值