理论知识
1. 泛型(Generics)
泛型是 Java 中一种强大的机制,允许在类、接口和方法中定义类型参数,以增强代码的灵活性和类型安全。
泛型的定义与使用
泛型使得 Java 类、接口或方法能够操作指定类型的数据,而不必在编译时指定具体的类型。例如,List<T>
表示一种支持泛型类型 T
的列表,可以是任何类型的集合,而无需在编写代码时指定具体类型。
- 定义一个泛型类:
// 定义泛型类
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public static void main(String[] args) {
// 使用泛型类
Box<Integer> integerBox = new Box<>();
integerBox.setValue(10);
System.out.println("Integer Value: " + integerBox.getValue());
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
System.out.println("String Value: " + stringBox.getValue());
}
}
通配符(Wildcard)
? extends T
:表示上界通配符,允许类型是 T 或其子类。? super T
:表示下界通配符,允许类型是 T 或其父类。
import java.util.List;
public class WildcardExample {
public static void printList(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3);
printList(intList); // List of Integer
List<Double> doubleList = List.of(1.1, 2.2, 3.3);
printList(doubleList); // List of Double
}
}
泛型的类型擦除机制
泛型在编译时会被擦除,编译后的字节码中不再保留泛型类型信息。类型擦除是 Java 泛型的核心特性,泛型类型被替换为它的原始类型。例如,List<String>
和 List<Integer>
在运行时都被看作 List
类型。
2. 反射(Reflection)
反射是 Java 提供的一种强大功能,可以在运行时检查和操作类的属性、方法、构造函数等信息。通过反射,可以动态地加载类、获取类的信息、调用方法,甚至修改字段值。
Class 对象的获取方式
Class.forName()
:通过类的完全限定名获取 Class 对象。.class
:通过类的字面值获取 Class 对象。getClass()
:通过对象获取 Class 对象。
public class ReflectionExample {
public static void main(String[] args) throws Exception {
// 通过 Class.forName() 获取 Class 对象
Class<?> cls1 = Class.forName("java.util.ArrayList");
System.out.println(cls1.getName());
// 通过 .class 获取 Class 对象
Class<?> cls2 = ArrayList.class;
System.out.println(cls2.getName());
// 通过对象获取 Class 对象
ArrayList<String> list = new ArrayList<>();
Class<?> cls3 = list.getClass();
System.out.println(cls3.getName());
}
}
动态调用方法和操作属性
反射允许动态调用方法和修改字段值,这对于构建灵活的框架和工具非常有用。
import java.lang.reflect.Method;
public class ReflectMethodExample {
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
public static void main(String[] args) throws Exception {
// 获取 Class 对象
Class<?> cls = ReflectMethodExample.class;
// 获取方法对象
Method method = cls.getMethod("sayHello", String.class);
// 创建对象实例
ReflectMethodExample example = new ReflectMethodExample();
// 使用反射调用方法
method.invoke(example, "World");
}
}
操作字段(Field)
通过反射,可以获取字段并修改其值,即使是私有字段。
import java.lang.reflect.Field;
public class ReflectFieldExample {
private String name;
public static void main(String[] args) throws Exception {
ReflectFieldExample obj = new ReflectFieldExample();
// 获取 Class 对象
Class<?> cls = ReflectFieldExample.class;
// 获取字段
Field field = cls.getDeclaredField("name");
field.setAccessible(true); // 使私有字段可以访问
// 修改字段值
field.set(obj, "John Doe");
// 获取字段值
System.out.println("Name: " + field.get(obj));
}
}
实践操作
1. 泛型方法:获取集合中的最大值
编写一个泛型方法,接受一个集合,返回集合中的最大值。
import java.util.List;
public class GenericMax {
public static <T extends Comparable<T>> T getMax(List<T> list) {
if (list == null || list.isEmpty()) {
return null;
}
T max = list.get(0);
for (T element : list) {
if (element.compareTo(max) > 0) {
max = element;
}
}
return max;
}
public static void main(String[] args) {
List<Integer> intList = List.of(1, 2, 3, 4, 5);
System.out.println("Max value: " + getMax(intList));
List<String> stringList = List.of("apple", "banana", "cherry");
System.out.println("Max value: " + getMax(stringList));
}
}
2. 使用反射打印任意对象的所有字段及其值
编写一个工具类,使用反射打印任意对象的所有字段及其值。
import java.lang.reflect.Field;
public class ReflectUtil {
public static void printFields(Object obj) throws IllegalAccessException {
Class<?> cls = obj.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 使私有字段可以访问
Object value = field.get(obj);
System.out.println(field.getName() + ": " + value);
}
}
public static void main(String[] args) throws IllegalAccessException {
Person person = new Person("John", 30);
printFields(person);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
总结
-
泛型:
- 通过泛型,Java 提供了类型安全的集合操作,避免了类型转换的错误。
- 使用通配符
? extends T
和? super T
可以灵活地操作泛型类型。 - 泛型的类型擦除机制使得泛型在编译后变成了原始类型,无法在运行时获取泛型类型的信息。
-
反射:
- 反射提供了在运行时获取类信息、调用方法、修改字段的能力,非常适合框架和工具的开发。
- 反射的效率较低,使用时需要权衡性能和灵活性。
-
工作中的使用:
- 泛型:广泛应用于集合类、工具类等场景,提供类型安全的操作。
- 反射:常用于 Java 框架(如 Spring)中,进行依赖注入、动态代理等操作。