Day 13:Java 泛型与反射

理论知识

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;
    }
}

总结

  1. 泛型

    • 通过泛型,Java 提供了类型安全的集合操作,避免了类型转换的错误。
    • 使用通配符 ? extends T? super T 可以灵活地操作泛型类型。
    • 泛型的类型擦除机制使得泛型在编译后变成了原始类型,无法在运行时获取泛型类型的信息。
  2. 反射

    • 反射提供了在运行时获取类信息、调用方法、修改字段的能力,非常适合框架和工具的开发。
    • 反射的效率较低,使用时需要权衡性能和灵活性。
  3. 工作中的使用

    • 泛型:广泛应用于集合类、工具类等场景,提供类型安全的操作。
    • 反射:常用于 Java 框架(如 Spring)中,进行依赖注入、动态代理等操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值