Java高级应用——泛型

文章目录

    • 泛型
      • 泛型化的由来概念
      • 简介:
      • 自定义泛型
      • 注意事项
        • 说明
        • 注意

泛型

泛型化的由来概念

  1. 强类型语言的需求:在早期的编程语言中,程序员需要在编写代码时指定变量的具体类型。这种静态类型检查的方式可以确保类型的一致性,但也带来了一些限制。在处理不同类型的数据时,需要为每个类型写不同的代码,这导致了重复劳动和代码冗余。
  2. 参数化类型的引入:为了解决上述问题,研究人员开始思考如何实现能够处理多种类型的通用代码。参数化类型的概念应运而生。参数化类型允许在定义数据结构、函数或类时使用类型参数,使得这些结构可以适用于多种类型。

简介:

  1. 类型参数:

    • Java泛型使用类型参数(Type Parameters)来表示泛型类型。

    • 类型参数用尖括号(<>)括起来,放在类、接口、方法的名称后面。

    • 例如,List中的T就是一个类型参数。

  2. 泛型类:

    • 通过在类的定义中使用类型参数,可以创建泛型类。

    • 泛型类可以在实例化时指定具体的类型参数。

    • 例如,List就是一个泛型类,可以用List表示整数类型的列表,用List表示字符串类型的列表。

  3. 泛型接口:

    • 与泛型类类似,可以定义泛型接口。

    • 泛型接口可以在实现时指定具体的类型参数。

    • 例如,Comparable就是一个泛型接口,用于比较两个对象的大小。

  4. 泛型方法:

    • 除了类和接口,还可以定义泛型方法。

    • 泛型方法在方法声明中使用类型参数,可以在调用时根据实际情况推断或指定类型参数。

    • 例如, T getValue()就是一个泛型方法,返回类型和参数类型都可以是泛型。

  5. 通配符:

    • Java泛型还支持通配符(Wildcard)机制。

    • 通配符用?表示,表示未知类型。

    • 通配符可以用于方法参数、类型限定和泛型实例化等场景。

    • 例如,List表示一个未知类型的列表。

  6. 类型限定:

    • 可以对泛型进行类型限定,即指定泛型参数必须是某个类或接口的子类型。

    • 例如,表示泛型参数必须是Number类或其子类。

  7. 类型擦除:

    • Java的泛型是通过类型擦除(Type Erasure)实现的。

    • 在编译时,泛型的类型信息会被擦除,泛型类型参数会被替换为其边界类型或Object。

    • 这是为了保持与Java旧版本的兼容性。

  8. 泛型数组:

    • Java不允许直接创建泛型数组,因为数组是具体化的,而泛型是擦除的。

    • 可以使用通配符或类型转换来处理泛型数组相关的操作。

  9. 泛型的类型推断:

    • Java 7引入了菱形操作符(Diamond Operator),可以通过省略类型参数来进行类型推断。

    • 例如,List list = new ArrayList<>(),其中的<>可以省略。

  10. 泛型和继承:

    • 在泛型中,子类型和父类型之间的关系与非泛型的类型参数一样。

    • 例如,ListList的子类型。

自定义泛型

自定义泛型是Java中强大的特性之一,它允许在类、接口和方法中定义参数化类型。

  1. 类型参数声明:

    • 在自定义泛型中,您需要使用类型参数来表示参数化类型。
    • 类型参数可以是任何合法的标识符,通常使用大写字母作为类型参数的名称(例如:TEK等)。
    • 类型参数声明放置在类、接口或方法的名称后面,用尖括号(<>)括起来。
  2. 泛型类:

    • 泛型类允许在类的定义中使用类型参数,从而创建参数化类型。

    • 类型参数可以在实例化时指定具体的类型。

    • 泛型类的方法和成员变量可以使用类型参数来定义其类型。

    • 示例:

      public class MyGenericClass<T> {
          private T value;
      
          public void setValue(T value) {
              this.value = value;
          }
      
          public T getValue() {
              return value;
          }
      }
      
  3. 泛型接口:

    • 泛型接口允许在接口的定义中使用类型参数,从而创建参数化类型。

    • 类型参数可以在实现时指定具体的类型。

    • 泛型接口的方法可以使用类型参数来定义其参数和返回类型。

    • 示例:

      public interface MyGenericInterface<T> {
          T performAction(T value);
      }
      
  4. 泛型方法:

    • 泛型方法允许在方法声明中使用类型参数,从而创建参数化方法。

    • 类型参数可以在调用时根据实际情况推断或指定类型参数。

    • 泛型方法的类型参数声明在方法的修饰符和返回类型之间。

    • 示例:

      public class MyGenericClass {
          public <T> void myGenericMethod(T value) {
              // 泛型方法的实现
          }
      }
      
  5. 类型边界:

    • 您可以对泛型进行类型限定,即指定泛型参数必须是某个类或接口的子类型。

    • 使用关键字 extends 表示类型边界,后跟限定的类型。

    • 示例:

      public class MyGenericClass<T extends Number> {
          // 类型参数必须是Number类或其子类
      }
      
  6. 通配符:

    • 通配符是一种用于表示未知类型的特殊类型参数。

    • 使用问号(?)表示通配符。

    • 通配符可以用于方法参数、类型限定和泛型实例化等场景。

    • 示例:

      public void processList(List<?> list) {
          // 使用通配符处理未知类型的列表
      }
      
  7. 类型擦除:

    • Java的泛型是通过类型擦除(Type Erasure)实现的。

    • 在编译时,泛型的类型信息会被擦除,泛型类型参数会被替换为其边界类型或Object

    • 泛型在运行时是不可见的,称为类型擦除。

    • 示例:

      List<Integer> list = new ArrayList<>();
      

      编译后的代码:

      List list = new ArrayList();
      
  8. 泛型数组:

    • Java不允许直接创建泛型数组,因为数组是具体化的,而泛型是擦除的。
    • 可以使用通配符或类型转换来处理泛型数组相关的操作。

注意事项

说明

在声明自定义泛型类之后,我们可以在类的内部(例如属性、方法、构造器)使用该类的泛型。这样可以在类的内部使用泛型参数来指定具体的类型。

在创建自定义泛型类的对象时,可以指定泛型参数类型。一旦指定了类型参数,类内部所有使用泛型参数的地方都会被具体化为指定的类型。

如果在创建自定义泛型类的对象时没有指定泛型参数类型,则泛型会被擦除,泛型对应的类型将按照Object处理,但并不等同于Object。

根据经验,如果使用了泛型,就应该一直使用泛型。如果不使用泛型,就不应该在类的任何地方使用泛型。

在泛型的指定中,必须使用引用类型,不能使用基本数据类型。必须使用包装类来替代基本数据类型。

除了创建泛型类的对象之外,当子类继承泛型类或实现泛型接口时,也可以确定泛型结构中的泛型参数。

如果在向泛型类提供子类时,子类也无法确定泛型的类型,则可以继续使用泛型参数。还可以在现有的父类泛型参数的基础上添加新的泛型参数。

注意

泛型类可以有多个参数,此时应将多个参数一起放在尖括号内,例如:

从JDK 7.0 开始,可以简化泛型操作,例如:ArrayList flist = new ArrayList<>();

如果泛型结构是接口或抽象类,则无法创建泛型类的对象。

不能使用new E[]来创建泛型数组,但可以使用(E[])new Object[capacity],其中ArrayList源码中的声明为Object[] elementData,而不是泛型参数类型的数组。

在类或接口上声明的泛型在本类或本接口中代表特定的类型,但不能在静态方法中使用类的泛型。

异常类不能带有泛型。

以上是关于自定义泛型的一些注意事项和约束。使用泛型时请遵循这些规则,以确保代码的正确性和一致性。

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