Java 中的泛型:您从不知道自己需要的救星

想象一下:您是一名 Java 开发人员,从事涉及处理大量不同数据类型的复杂项目。你有你的列表、你的地图、你的集合,它们都充满了不同种类的对象。试图跟踪所有这些是一场噩梦,而且您一直担心不小心将错误类型的对象传递给方法或函数。但不要害怕,我的开发伙伴,因为有一个解决你的困境的方法:泛型。

泛型是 Java 中的一项功能,它允许您编写可以处理多种数据类型的代码。将它们视为占位符,在您使用它们时可以用实际类型替换。它们是在 Java 5 中引入的,从此成为该语言的重要组成部分。但是历史课已经讲完了,让我们深入研究一些代码示例。

假设您正在从事一个涉及对对象列表进行排序的项目。如果没有泛型,你可能会这样写:

List unsortedList = new ArrayList();
unsortedList.add("apple");
unsortedList.add("banana");
unsortedList.add(42); //我们向字符串列表中添加了一个整数
Collections.sort(unsortedList);

这段代码可能会编译而不会出现任何错误,但是当您运行它时,您将得到一个 ClassCastException,因为您正试图对同时包含字符串和整数的列表进行排序。但不要害怕,因为使用泛型,我们可以完全避免这个问题:

List<String> unsortedList = new ArrayList<>();
unsortedList.add("apple");
unsortedList.add("banana");
unsortedList.add(42); // 编译器错误:类型不兼容
Collections.sort(unsortedList);

通过指定我们的列表应该只包含字符串,我们已经消除了向它添加整数的可能性。当我们尝试添加一个整数时,编译器会捕获它并给我们一个错误。这似乎是一个很小的改进,但它可以为您省去很多麻烦。

但泛型的力量并不止于此。假设您正在处理一个需要返回特定类型对象的方法。如果没有泛型,你可能会这样写:

public Object getObject() {
    //这里是一些代码
    return someObject;
}

这个方法可以返回任何类型的对象,这在某些情况下可能没问题,但不是很具体。使用泛型,我们可以让我们的代码更精确:

public <T> T getObject(Class<T> clazz) {
    //这里是一些代码
    return clazz.cast(someObject);
}

现在我们的方法可以返回任何类型的对象,只要我们在调用该方法时指定我们想要的类型即可。例如:

String myString = getObject(String.class);
Integer myInteger = getObject(Integer.class);

通过使用泛型,我们使代码更灵活,同时也更具体。这是双赢的。

现在让我们来看看我在日常工作中遇到的这种情况:

我在这个庞大的遗留代码库中工作,数据库中有超过一千个类和表。基本代码最初是用 Java 7 编写的,后来升级到 Java 8。你明白了!在这种特定情况下,我们无法重构所有基本代码以在我们拥有的所有类中实现 Builder Factories。这是一项艰巨而痛苦的任务。在这种情况下,仿制药救了我的命!我已经实现了一个通用类,可以在我想要的任何类中使用 Builder 模式!看一下类:

public class Builder<T> {
    // Supplier 是一个函数式接口,它不接受任何参数并返回一个值。
    // 在这种情况下,Supplier 用于创建泛型类型 T 的新实例。
    private final Supplier<T> instantiator;
    
    // 一个 Consumer 函数列表,其中每个 Consumer 以某种方式修改一个 T 实例。
    private final List<Consumer<T>> instanceModifiers = new ArrayList<>();

    // 采用 T 实例的构造函数
    public Builder(Supplier<T> instantiator) {
        this.instantiator = instantiator;
    }

    //静态工厂方法,该方法使用给定的实例器创建新的生成器
    public static <T> Builder<T> of(Supplier<T> instantiator) {
        return new Builder<>(instantiator);
    }

    // 该方法接受一个bicconsumer和一个U类型的值,并向列表中添加一个新的Consumer
    // 给定的值。
    public <U> Builder<T> with(BiConsumer<T, U> consumer, U value) {
        Consumer<T> c = instance -> consumer.accept(instance, value);
        instanceModifiers.add(c);
        return this;
    }

    // 方法使用实例化器创建T的新实例,应用所有的instancemodifier
    // 应用于它,并返回结果。
    public T build() {
        T value = instantiator.get();
        instanceModifiers.forEach(modifier -> modifier.accept(value));
        instanceModifiers.clear();
        return value;
    }
}

这个类允许我们实现构建器模式,而不必修改代码库中的每个类。我们可以简单地创建一个Builder类的新实例,并用它来构建任何类型的对象。让我们看一些代码示例:

public class Person {
    private String name;
    private int age;
    private String address;

    // getters and setters
}

// 使用构建器创建Person对象
Person person = Builder.of(Person::new)
                .with(Person::setName, "John Doe")
                .with(Person::setAge, 30)
                .build();

在这个例子中,我们使用Builder类来创建一个Person对象。我们首先创建该类的一个新实例Builder并通过引用传入一个新Person对象。然后我们使用该with方法来设置对象的name和字段。最后,我们调用创建最终对象的方法。

另一个例子:

public class Car {
    private String make;
    private String model;
    private int year;

    public Car(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    // getters and setters
}

// 使用构建器创建Car对象
Car car = Builder.of(() -> new Car(null, null, 0))
            .with(Car::setMake, "Toyota")
            .with(Car::setModel, "Camry")
            .with(Car::setYear, 2021)
            .build();

在这个例子中,我们使用Builder类来创建一个Car对象。我们遵循与之前相同的模式,创建该类的一个新实例Builder并通过引用传入一个新Car对象。然后,我们使用该with方法设置对象的makemodelyear字段Car。最后,我们调用build创建最终Car对象的方法。

总之,Java 中的泛型可以成为处理复杂数据类型的开发人员的救星。它们允许我们编写更灵活和更具体的代码,这可以让我们免于很多麻烦。因此,下次您处理 Java 项目时,请记住使用泛型。你未来的自己会感谢你。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值