[Java基础系列第2弹]泛型:一种提高代码复用性和灵活性的技术

一、什么是泛型?

        泛型(Generics)是一种编程技术,它可以让我们在定义类、接口或方法时,使用一个或多个类型参数(Type Parameter),而不是具体的类型。这样,我们就可以在实例化或调用时,根据需要指定具体的类型,从而实现代码的复用性和灵活性。

        例如,我们可以定义一个泛型类List,它表示一个元素类型为T的列表。T是一个类型参数,它可以是任何类型。当我们创建一个List对象时,我们可以指定T的具体类型,比如List表示一个字符串列表,List表示一个整数列表,等等。

二、为什么要使用泛型?

泛型有以下几个优点:

  • 提高代码的复用性。我们可以用同一个泛型类或方法来处理不同类型的数据,而不需要为每种类型都写一个专门的类或方法。
  • 提高代码的安全性。我们可以在编译时检查类型的匹配,避免在运行时出现类型转换错误。
  • 提高代码的可读性。我们可以用有意义的类型参数来表示数据的特征,而不是用通用的Object或其他基类。

三、如何使用泛型?

要使用泛型,我们需要遵循以下几个步骤:

  • 定义泛型类、接口或方法。我们需要在类、接口或方法名后面加上一对尖括号(<>),并在其中写上一个或多个类型参数。例如:
public class List {
  // 类体
}

public interface Comparable {
  // 接口体
}

public static  void sort(T[] array) {
  // 方法体
}
  • 实例化泛型类或调用泛型方法。我们需要在创建对象或调用方法时,指定类型参数的具体类型。例如:
List names = new List<>(); // 创建一个字符串列表
names.add("Alice");
names.add("Bob");

Comparable c = new Comparable<>() { // 创建一个整数比较器
  @Override
  public int compareTo(Integer o) {
    return this - o;
  }
};

Integer[] numbers = {3, 1, 4, 2};
sort(numbers); // 调用泛型方法排序
  • 使用泛型类、接口或方法。我们可以像使用普通的类、接口或方法一样,使用泛型类、接口或方法。只是在使用类型参数时,要注意它们的范围和限制。例如:
public class List {
  private T[] elements; // 使用类型参数作为数组元素类型
  private int size;

  public List() {
    elements = (T[]) new Object[10]; // 创建一个Object数组并强制转换为T数组
    size = 0;
  }

  public void add(T element) {
    if (size == elements.length) {
      resize(); // 扩容
    }
    elements[size++] = element; // 添加元素
  }

  public T get(int index) {
    if (index < 0 || index >= size) {
      throw new IndexOutOfBoundsException(); // 抛出异常
    }
    return elements[index]; // 返回元素
  }

  private void resize() {
    T[] newElements = (T[]) new Object[elements.length * 2]; // 创建一个新数组并强制转换为T数组
    System.arraycopy(elements, 0, newElements, 0, size); // 复制原数组元素到新数组
    elements = newElements; // 更新引用
  }
}

四、泛型的高级特性

除了基本的使用方式外,泛型还有一些高级的特性,比如:

  • 泛型继承。我们可以让一个泛型类继承另一个泛型类,或者实现一个泛型接口。例如:
public class Stack extends List { // 栈类继承列表类
  // 类体
}

public class Student implements Comparable { // 学生类实现比较器接口
  // 类体
}
  • 泛型限定。我们可以在定义类型参数时,指定它们的上界(Upper Bound)或下界(Lower Bound),来限制它们的取值范围。例如:
public static  double sum(T[] array) { // 定义一个类型参数T,它必须是Number或其子类
  double sum = 0;
  for (T t : array) {
    sum += t.doubleValue(); // 调用Number的方法
  }
  return sum;
}

public static void print(List list) { // 定义一个通配符类型?,它必须是Integer或其父类
  for (Object o : list) {
    System.out.println(o); // 打印对象
  }
}
  • 泛型擦除。泛型是一种编译时的技术,它在运行时会被擦除(Erasure),也就是说,泛型类或方法在运行时会变成普通的类或方法,类型参数会被替换为它们的上界或Object。这样做的目的是为了保持与旧版本的Java代码的兼容性。

但是,这也带来了一些限制,比如:

  • 我们不能使用instanceofnew操作符来操作泛型类型。
  • 我们不能使用基本类型作为类型参数。
  • 我们不能在静态域或方法中使用类型参数。
  • 我们不能直接获取泛型类型的Class对象。

五、总结

泛型是一种提高代码复用性和灵活性的技术,它可以让我们在定义类、接口或方法时,使用类型参数来代替具体的类型,从而实现代码的通用性和可扩展性。泛型还有一些高级的特性,比如泛型继承、泛型限定和泛型擦除,它们可以让我们更灵活地使用泛型。


这里是热爱编程的小高,希望和大家共同进步~

你可能感兴趣的:(Java,java,开发语言)