Java 泛型详解
Java泛型(Generics)是Java语言的一个重要特性,它允许在定义类、接口和方法时使用类型参数。通过泛型,可以编写更加灵活、可重用的代码,并且可以在编译时进行类型检查,从而避免运行时的类型错误。
1. 基本概念
- 类型参数:泛型中的类型参数通常用大写字母表示,如 T、E、K、V 等。
- 泛型类:使用类型参数定义的类。
- 泛型接口:使用类型参数定义的接口。
- 泛型方法:使用类型参数定义的方法。
2. 泛型类
\\\`java public class Box { private T content;
public void setContent(T content) { this.content = content; }
public T getContent() { return content; } } \\\`
使用:
\\\`java Box stringBox = new Box<>(); stringBox.setContent("Hello"); System.out.println(stringBox.getContent()); // 输出: Hello
Box intBox = new Box<>(); intBox.setContent(123); System.out.println(intBox.getContent()); // 输出: 123 \\\`
3. 泛型接口
java public interface Container
实现:
\\\`java public class ListContainer implements Container { private List items = new ArrayList<>();
@Override public void add(T item) { items.add(item); }
@Override public T get(int index) { return items.get(index); }
@Override public int size() { return items.size(); } } \\\`
使用:
java Container
4. 泛型方法
\\\`java public class Util {
public static
- array) {
for (T element : array) { System.out.print(element + " "); } System.out.println(); } } \\\`
使用:
\\\`java
- stringArray = {"One", "Two", "Three"};
Util.printArray(stringArray); // 输出: One Two Three
- intArray = {1, 2, 3};
Util.printArray(intArray); // 输出: 1 2 3 \\\`
5. 类型通配符
- 无界通配符:? 表示未知类型。
- 上界通配符: extends t> 表示类型必须是 T 或其子类。
- 下界通配符: super t> 表示类型必须是 T 或其父类。
\\\`java public class WildcardExample { public static void printList(List> list) { for (Object element : list) { System.out.print(element + " "); } System.out.println(); }
public static void addNumbers(List extends number> list) { for (Number element : list) { System.out.print(element + " "); } System.out.println(); }
public static void addStrings(List super string> list) { list.add("Hello"); list.add("World"); } } \\\`
使用:
\\\`java List intList = Arrays.asList(1, 2, 3); WildcardExample.printList(intList); // 输出: 1 2 3
List numberList = Arrays.asList(1.0, 2.0, 3.0); WildcardExample.addNumbers(numberList); // 输出: 1.0 2.0 3.0
List objectList = new ArrayList<>(); WildcardExample.addStrings(objectList); System.out.println(objectList); // 输出: \[Hello, World\] \\\`
常见面试题
1. 什么是Java泛型?
Java泛型是一种允许在定义类、接口和方法时使用类型参数的技术。它使得代码更加灵活和可重用,并且可以在编译时进行类型检查,从而避免运行时的类型错误。
2. 泛型的好处是什么?
- 类型安全:编译时进行类型检查,避免了运行时的类型转换错误。
- 代码复用:可以通过泛型编写通用的类和方法,适用于多种类型。
- 消除强制类型转换:减少了显式的类型转换,使代码更简洁。
3. 什么是类型擦除?
类型擦除是Java编译器处理泛型的方式。编译器在编译期间会将泛型类型替换为它们的原始类型(通常是 Object),并在需要的地方插入类型检查和强制转换。这样做的目的是保持与旧版本Java的兼容性。
4. 为什么不能创建泛型数组?
因为Java的泛型在运行时会被擦除,而数组在运行时需要知道其元素的确切类型,因此不能创建泛型数组。例如,new T[10] 是非法的。
5. 什么是通配符?有哪些种类?
通配符用于表示未知类型或类型的范围:
- 无界通配符:?
- 上界通配符: extends t>
- 下界通配符: super t>
6. List<Object>和 List>的区别是什么?
- List<Object> 可以存储任何对象,但不能直接添加子类型对象(除了 null)。
- List> 表示一个包含未知类型的列表,可以读取元素,但不能添加元素(除了 null)。
7. ArrayList和 ArrayList extends object>的区别是什么?
- ArrayList
是一个只能存储 String 对象的列表。 - ArrayList extends object> 是一个可以存储任何对象的列表,但具体类型未知,因此不能添加元素(除了 null)。
8. 什么时候使用泛型?
当你需要编写通用的、类型安全的代码时,应该使用泛型。例如,容器类、工具类和算法类都可以从泛型中受益。
9. 泛型类和泛型方法有什么区别?
- 泛型类:在整个类的范围内使用类型参数。
- 泛型方法:只在方法的范围内使用类型参数,类本身不需要泛型化。
10. 如何解决泛型方法中的类型推断问题?
Java编译器通常可以根据上下文自动推断出泛型方法的类型参数。如果推断失败,可以显式指定类型参数,例如:
\\\`java
Util.printArray(new String\[ \]{"One", "Two", "Three"});
\\\`
11. 什么是PECS原则?
PECS原则是指“Producer Extends, Consumer Super”,即:
- 如果你需要从集合中获取元素(生产者),使用 extends。
- 如果你需要向集合中添加元素(消费者),使用 super。
12. 泛型和反射结合使用时需要注意什么?
由于类型擦除,泛型信息在运行时不可用。因此,在使用反射时,无法直接获取泛型参数的具体类型。可以通过 Type 接口及其子接口(如 ParameterizedType)来获取一些泛型信息,但这仍然有限。
总结
Java泛型是一个强大的工具,能够提高代码的灵活性和安全性。理解泛型的基本概念、类型通配符以及常见的面试题,有助于在实际开发中更好地应用泛型,并在面试中展现出扎实的Java基础。
本文暂时没有评论,来添加一个吧(●'◡'●)