泛型让代码更安全,注解让代码更简洁,反射让代码更灵活。
目录
- [1. 泛型基础](#1. 泛型基础)
- [2. 泛型方法](#2. 泛型方法)
- [3. 类型边界](#3. 类型边界)
- [4. 注解基础](#4. 注解基础)
- [5. 反射机制](#5. 反射机制)
- [6. 实战案例](#6. 实战案例)
- [7. 总结](#7. 总结)
- 参考资源
1. 泛型基础
1.1 为什么需要泛型?
在泛型出现之前,集合使用Object存储元素:
java
// 旧写法(没有泛型)
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0); // 需要强制转换,可能出错
使用泛型后:
java
// 新写法(使用泛型)
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0); // 自动类型安全,无需强制转换
1.2 泛型类
java
// 通用容器类
public class Box<T> {
private T content;
public Box(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
@Override
public String toString() {
return "Box{" + content + "}";
}
}
// 使用泛型类
public class BoxDemo {
public static void main(String[] args) {
Box<String> stringBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(123);
System.out.println(stringBox); // Box{Hello}
System.out.println(intBox); // Box{123}
}
}
1.3 多类型参数
java
// 键值对容器
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
@Override
public String toString() {
return "Pair{key=" + key + ", value=" + value + "}";
}
}
// 使用多类型参数
public class PairDemo {
public static void main(String[] args) {
Pair<String, Integer> pair = new Pair<>("age", 25);
System.out.println(pair); // Pair{key=age, value=25}
}
}
2. 泛型方法
2.1 定义泛型方法
java
public class GenericMethods {
// 泛型方法:在返回类型前声明类型参数
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
// 返回泛型类型的泛型方法
public static <T extends Comparable<T>> T findMax(T[] array) {
T max = array[0];
for (T element : array) {
if (element.compareTo(max) > 0) {
max = element;
}
}
return max;
}
public static void main(String[] args) {
Integer[] numbers = {3, 1, 4, 1, 5, 9, 2, 6};
String[] fruits = {"apple", "banana", "orange"};
System.out.print("数字:");
printArray(numbers);
System.out.print("水果:");
printArray(fruits);
System.out.println("最大数字:" + findMax(numbers));
System.out.println("最大水果:" + findMax(fruits));
}
}
3. 类型边界
3.1 上界(extends)
限制泛型必须是某个类或接口的子类:
java
// 数值型容器,只能存放Number及其子类
public class NumberBox<T extends Number> {
private T number;
public NumberBox(T number) {
this.number = number;
}
public double doubleValue() {
return number.doubleValue();
}
}
// 可比较的容器
public class ComparableBox<T extends Comparable<T>> {
private T value;
public ComparableBox(T value) {
this.value = value;
}
public boolean isGreaterThan(T other) {
return value.compareTo(other) > 0;
}
}
3.2 通配符
java
public class WildcardDemo {
// 上界通配符:只读
public static double sum(List<? extends Number> list) {
double total = 0;
for (Number num : list) {
total += num.doubleValue();
}
return total;
}
// 下界通配符:只写
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 5; i++) {
list.add(i);
}
}
// 无界通配符
public static void printList(List<?> list) {
for (Object item : list) {
System.out.print(item + " ");
}
System.out.println();
}
public static void main(String[] args) {
List<Integer> integers = List.of(1, 2, 3);
List<Double> doubles = List.of(1.1, 2.2, 3.3);
System.out.println("整数和:" + sum(integers));
System.out.println("浮点数和:" + sum(doubles));
List<Number> numberList = new ArrayList<>();
addNumbers(numberList);
System.out.println("添加的数字:" + numberList);
printList(integers);
printList(doubles);
}
}
4. 注解基础
4.1 什么是注解?
注解是元数据,提供关于程序元素但不影响程序执行的信息。
java
@Override // 标记方法重写父类方法
public String toString() {
return "Hello";
}
@SuppressWarnings("unchecked") // 抑制警告
List<String> list = new ArrayList<>();
@Test // 标记测试方法
public void testMethod() {
// 测试代码
}
4.2 内置注解
java
public class AnnotationDemo {
@Override
public String toString() {
return "重写toString";
}
@Deprecated
public void oldMethod() {
System.out.println("过时的方法");
}
@SuppressWarnings("unchecked")
public void uncheckedOperation() {
List raw = new ArrayList();
raw.add("Hello");
List<String> typed = raw;
}
}
4.3 自定义注解
java
import java.lang.annotation.*;
// 定义注解
@Retention(RetentionPolicy.RUNTIME) // 保留到运行时
@Target(ElementType.METHOD) // 只能用在方法上
public @interface LogExecutionTime {
String value() default ""; // 注解元素,有默认值
}
// 定义另一个注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Validate {
int minLength() default 0;
int maxLength() default Integer.MAX_VALUE;
boolean required() default true;
}
5. 反射机制
5.1 什么是反射?
反射是Java在运行时获取类信息并操作类的能力:
java
import java.lang.reflect.*;
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("java.lang.String");
// 获取类信息
System.out.println("类名:" + clazz.getName());
System.out.println("简单名:" + clazz.getSimpleName());
// 获取方法
System.out.println("\n公共方法:");
for (Method method : clazz.getMethods()) {
if (method.getDeclaringClass() == clazz) {
System.out.println(" " + method.getName());
}
}
}
}
5.2 动态创建对象
java
import java.lang.reflect.*;
public class DynamicObjectCreation {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("java.util.ArrayList");
// 创建实例
Object list = clazz.getDeclaredConstructor().newInstance();
// 调用方法
Method addMethod = clazz.getMethod("add", Object.class);
addMethod.invoke(list, "Hello");
addMethod.invoke(list, "World");
Method sizeMethod = clazz.getMethod("size");
int size = (int) sizeMethod.invoke(list);
System.out.println("列表大小:" + size);
Method toStringMethod = clazz.getMethod("toString");
System.out.println("列表内容:" + toStringMethod.invoke(list));
}
}
6. 实战案例
6.1 基于注解的字段验证器
java
import java.lang.annotation.*;
import java.lang.reflect.*;
// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface NotBlank {
String message() default "不能为空";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Email {
String message() default "邮箱格式不正确";
}
// 验证器
public class Validator {
public static <T> List<String> validate(T object) throws IllegalAccessException {
List<String> errors = new ArrayList<>();
Class<?> clazz = object.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
if (field.isAnnotationPresent(NotBlank.class)) {
String value = (String) field.get(object);
if (value == null || value.trim().isEmpty()) {
NotBlank annotation = field.getAnnotation(NotBlank.class);
errors.add(field.getName() + ": " + annotation.message());
}
}
if (field.isAnnotationPresent(Email.class)) {
String value = (String) field.get(object);
if (value != null && !value.matches("^.+@.+\\..+$")) {
Email annotation = field.getAnnotation(Email.class);
errors.add(field.getName() + ": " + annotation.message());
}
}
}
return errors;
}
}
// 使用示例
class RegistrationForm {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
public RegistrationForm(String username, String email) {
this.username = username;
this.email = email;
}
}
class ValidatorDemo {
public static void main(String[] args) throws Exception {
RegistrationForm form = new RegistrationForm("", "invalid-email");
List<String> errors = Validator.validate(form);
if (errors.isEmpty()) {
System.out.println("验证通过!");
} else {
System.out.println("验证失败:");
errors.forEach(error -> System.out.println(" - " + error));
}
}
}
7. 总结
本篇我们学习了:
✅ 泛型类和方法 :类型参数的定义和使用
✅ 类型边界 :extends、super关键字
✅ 通配符 :上界、下界、无界通配符
✅ 类型擦除 :泛型的实现机制和限制
✅ 注解 :内置注解、自定义注解、元注解
✅ 反射:运行时获取类信息、动态操作对象
核心要点:
- 泛型提供编译时类型安全
- 类型擦除是泛型的实现机制,有其限制
- 注解是元数据,不改变程序逻辑
- 反射可以在运行时操作类,但要注意性能
下一篇预告: 《Java从零到熟练(九):并发编程基础》
- 学习多线程编程
- 理解线程同步和锁
- 掌握并发集合和线程池
参考资源
下一篇: Java从零到熟练(九):并发编程基础