Java 知识量:11 - 45 - 220
泛型(Generics)是Java编程语言中的一种特性,它允许程序员在类、接口和方法中使用类型参数。泛型的主要目的是提高代码的可重用性和可读性。
使用泛型可以使代码适用于各种数据类型,同时保留编译时类型安全的优点。在Java中,泛型是在JDK 5.0中引入的,并且现在被广泛应用在各种数据结构和类库中。
泛型的工作原理是,在定义类、接口或方法时,可以用一个类型参数来代表某种数据类型。在实际使用时,可以将这个类型参数替换为任何你需要的数据类型。
Java泛型是一种允许在类、接口或方法上指定类型参数的功能。这些类型参数在实例化类、实现接口或调用方法时可以由任意类型替换。这样可以使代码更加灵活,且类型安全。
类型参数声明看起来像这样: <T>,这里的 T 是类型参数的名称。这个 T 可以是任何有效的标识符,但通常使用单个大写字母。也可以使用多个类型参数,例如 <K, V>,这里的 K 和 V 是两个不同的类型参数。
下面是一个泛型类和一个泛型方法的示例:
public class Box<T> { private T t; // T stands for "Type" public void set(T t) { this.t = t; } public T get() { return t; } } public class Main { public static void main(String[] args) { Box<Integer> integerBox = new Box<>(); integerBox.set(new Integer(10)); System.out.printf("整数值为 :%d\n\n", integerBox.get()); Box<String> stringBox = new Box<>(); stringBox.set(new String("Hello World")); System.out.printf("字符串为 :%s\n", stringBox.get()); } }
在这个例子中,Box 是一个泛型类,T 是它的类型参数。在 main 方法中,创建了两个 Box 对象:一个是 Box<Integer>,另一个是 Box<String>。在创建这些对象时,将 T 替换为 Integer 和 String。这样,每个 Box 对象都可以保存特定类型的值。
Java菱形语法(Diamond Syntax)是Java 7中引入的一种针对泛型的语法特性,其本质是一种语法糖,用于简化泛型代码的书写和提高代码的可读性。
在Java 7之前,在实例化一个泛型类或调用一个泛型方法时,需要在尖括号中指定泛型参数类型。例如,在Java 7之前,需要这样来创建一个List对象:
List<String> list = new ArrayList<String>();
而在Java 7及以后的版本中,可以省略掉泛型参数类型,编译器会自动推断出正确的类型。因此,使用菱形语法可以将上述代码简化为:
List<String> list = new ArrayList<>();
在这个例子中,尖括号<>中的内容被省略了,就像是一个菱形,因此这种语法被称为“菱形语法”。
菱形语法的优点除了简化代码和提高代码可读性之外,还可以减少代码中的错误,特别是在使用复杂的泛型类型时。例如,在使用嵌套泛型的例子中,使用菱形语法可以使代码更加清晰,避免在类型参数中重复输入类型名称的可能性,从而减少错误的发生。
注意:菱形语法只能用于实例化时的泛型参数,而不能用于方法调用或类型定义中的泛型参数。
Java的类型擦除(Type Erasure)是一个关于Java泛型的重要概念。在Java中,泛型是通过在类、接口和方法上添加类型参数来实现的。然而,在编译后的字节码中,这些类型参数的相关信息会被擦除,这就是所谓的类型擦除。
类型擦除的主要原因是为了使Java语言在添加泛型后仍然保持与旧版本的兼容性。因为在Java泛型被引入之前,Java的所有类型都是在编译期确定的,而不是在运行时确定的。因此,类型擦除可以保证在运行时不会出现类型不匹配的问题。
类型擦除的规则如下:
泛型信息不会被保存在运行时,即泛型类型在运行时都会被替换为它们的边界类型(如果有的话),或者替换为Object类型(如果没有边界的话)。
对于一个泛型类,如果它的类型参数没有被明确指定,那么它的所有类型参数都会被替换为Object类型。
对于一个泛型方法,如果它的类型参数没有被明确指定,那么它的所有类型参数都会被替换为Object类型。
对于一个泛型接口,如果它的类型参数没有被明确指定,那么它的所有类型参数都会被替换为Object类型。
例如,以下的泛型类:
public class Box<T> { private T t; }
在编译后,实际上变成了:
public class Box { private Object t; }
这就是Java的类型擦除机制。
可以使用类型参数来创建可重用的代码。类型参数类似于方法参数,只不过它们用于类型而不是值。类型参数在Java的泛型编程中非常有用。泛型是Java 5引入的特性,允许程序员在类、接口和方法上声明类型参数。
下面是一个简单的Java泛型类示例:
public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } }
在这个例子中,T是一个类型参数。可以使用任何非保留字的名称,但通常使用单个大写字母。这个Box类可以用来存储任何类型的对象,因为可以用任何类型实例化它。例如:
Box<Integer> integerBox = new Box<>(); integerBox.set(new Integer(10)); System.out.printf("整数值为 :%d\n\n", integerBox.get()); Box<String> stringBox = new Box<>(); stringBox.set(new String("Hello World")); System.out.printf("字符串为 :%s\n", stringBox.get());
在这个例子中,创建了两个Box对象:一个是Integer类型,另一个是String类型。通过使用类型参数,可以写出可以处理多种数据类型的代码,而不必为每一种数据类型编写一个单独的类。
在 Java 泛型中,通配符(Wildcard)用于表示不确定的类型参数。使用通配符可以使代码更加灵活,同时保持类型安全。
通配符的基本语法是:<?>,其中 ? 表示未知的类型参数。
通配符在 Java 泛型中有以下几种用法:
1、上限通配符(Upper Bounded Wildcard):<? extends T>,表示类型参数是 T 或者 T 的任意父类。示例:
List<? extends Number> list = new ArrayList<>(); list.add(123); // 允许添加 Integer 类型 list.add(new Double(456.78)); // 允许添加 Double 类型 list.add("abc"); // 编译错误,不允许添加 String 类型 Number num = list.get(0); // 允许获取 Number 类型 Integer intValue = list.get(0); // 编译错误,不允许获取 Integer 类型
2、下限通配符(Lower Bounded Wildcard):<? super T>,表示类型参数是 T 或者 T 的任意子类。示例:
List<? super Integer> list = new ArrayList<>(); list.add(123); // 允许添加 Integer 类型 list.add(new Double(456.78)); // 允许添加 Double 类型 list.add("abc"); // 允许添加 String 类型 Integer intValue = list.get(0); // 允许获取 Integer 类型 Double doubleValue = list.get(0); // 允许获取 Double 类型 String strValue = list.get(0); // 允许获取 String 类型
3无限制通配符(Unbounded Wildcard):<?>,表示类型参数可以是任意类型。示例:
List<?> list = new ArrayList<>(); list.add(123); // 允许添加 Integer 类型 list.add(new Double(456.78)); // 允许添加 Double 类型 list.add("abc"); // 允许添加 String 类型 Integer intValue = list.get(0); // 编译错误,不允许获取 Integer 类型 Double doubleValue = list.get(0); // 编译错误,不允许获取 Double 类型 String strValue = list.get(0); // 编译错误,不允许获取 String 类型
使用通配符时,需要注意以下几点:
通配符只能在方法参数、返回值和局部变量中使用,不能在类、接口和方法声明中使用。
通配符不能用于基本类型,如 int、double 等。可以使用其对应的包装类型,如 Integer、Double 等。
通配符不能用于数组类型。可以使用集合类型,如 List、Set 等。
Java泛型方法是定义在类或接口中的具有泛型参数的方法。Java泛型方法定义的基本语法格式为:
public <T> void functionName(T parameterName) { // method body }
其中,<T>是泛型参数列表,可以有一个或多个,一般放置在返回值前。T称为类型变量,表示一个类型占位符,在方法调用时将会被具体的类型替换。
例如,下面是一个使用泛型方法的例子:
public class Box<T> { public <U> void printBoxContents(U contents) { System.out.println(contents); } }
在这个例子中,Box类定义了一个泛型方法printBoxContents,它的参数是一个泛型参数U。当Box类的实例被创建时,将会用实际的类型替换泛型类型。
注意:泛型方法不影响它所在的类的类型。即使一个类定义了泛型方法,该类仍然可以是非泛型的。另外,如果一个方法是静态的,那么它不能使用泛型类的类型参数,所以如果需要让一个静态方法使用泛型能力,必须将它定义为泛型方法。
Copyright © 2017-Now pnotes.cn. All Rights Reserved.
编程学习笔记 保留所有权利
MARK:3.0.0.20240214.P35
From 2017.2.6