【Java】Generics in Java(二)

简介: 【Java】Generics in Java

【Java】Generics in Java(一)https://developer.aliyun.com/article/1395318

Bounded Generics 有限泛型

This is an advanced version of Generics. We can restrict more and achieve more type safety with bounded Generics.

这是泛型的高级版本。通过有界泛型,我们可以限制更多,实现多的类型安全

Let’s say we have an AnimalPrinter class which can only print animal details. No other objects are allowed to be used with it. How to achieve this?

假设我们有一个AnimalPrinter类,它只能打印动物的详细信息。不允许使用其他对象。如何实现?


public class Animal {  
    private final String name;  
    private final String color;  
    private final Integer age;  
    public Animal(String name, String color, Integer age) {  
        this.name = name;  
        this.color = color;  
        this.age = age;  
    }  
    public String getName() {  
        return name;  
    }  
    public String getColor() {  
        return color;  
    }  
    public Integer getAge() {  
        return age;  
    }  
    @Override  
    public boolean equals(Object o) {  
        if (this == o) return true;  
        if (o == null || getClass() != o.getClass()) return false;  
        Animal animal = (Animal) o;  
        return Objects.equals(name, animal.name) && Objects.equals(color, animal.color) && Objects.equals(age, animal.age);  
    }  
    @Override  
    public int hashCode() {  
        return Objects.hash(name, color, age);  
    }  
}  
public class Cat extends Animal {  
    public Cat(String name, String color, Integer age) {  
        super(name, color, age);  
    }  
}  
public class Dog extends Animal {  
    public Dog(String name, String color, Integer age) {  
        super(name, color, age);  
    }  
}
public class AnimalPrinter<T extends Animal> {  
    private final T animalData;  
    public AnimalPrinter(T animalData) {  
        this.animalData = animalData;  
    }  
    public void print() {  
        System.out.println("Name::: " + animalData.getName());  
        System.out.println("Color::: " + animalData.getColor());  
        System.out.println("Age::: " + animalData.getAge());  
    }  
}

In this class, T extends Animal part does the job! We have limited our generic for Dog and Cat!


AnimalPrinter<Cat> animalPrinter1 = new AnimalPrinter<>(new Cat("Jim", "brown", 2));  
animalPrinter1.print();  
AnimalPrinter<Dog> animalPrinter2 = new AnimalPrinter<>(new Dog("Rocky", "black", 5));  
animalPrinter2.print();

If we try to define the printer with another Object type, compiler will complain like this => “Type parameter ‘java.lang.Object’ is not within its bound; should extend ‘generics.Animal’

如果我们尝试使用其他对象类型定义打印机,编译器将发出如下警告 => "类型参数'java.lang.Object'不在其绑定范围内;应该扩展'generics.Animal'"。

Multiple Bounds 多重边界

Let’s say we want to add some more features to the Printer generic. We can achieve it like this.

比方说,我们想为打印机通用程序添加更多的功能。我们可以这样实现


public class AnimalPrinter<T extends Animal & Serializable> {  
    ..................  
}

I have provided Serializable functionality using Serializable interface. There are important things to remember here.

  • We must implement interface in our child classes(Cat and Dog).
  • Class should come first and the & and interface.
  • Only 1 class can be extended since Java does not support multiple inheritance.

我使用Serializable接口提供了Serializable功能。这里有一些重要的事情需要记住。

  • 我们必须在子类(Cat和Dog)中实现接口。
  • 类应该放在前面,然后是 &接口
  • 由于Java不支持多重继承,所以只能扩展一个类。

Wildcards With Generics 通用通配符

Wildcards are represented by the question mark ? in Java, and we use them to refer to an unknown type. This can be used as a parameter type with Generics. Then it will accept any type. I have used a List of any object as a method argument using wild card, in the below code.

通配符在Java中用问号 ? 表示,我们用它来代指未知类型。通配符在Java中用问号 ? ,然后它将接受任何类型。在下面的代码中,我使用通配符将任意对象的List作为方法参数。


public static void printList(List< ?> list) {  
    System.out.println(list);  
}  
printList(  
    Arrays.asList(  
        new Cat("Jim", "brown", 2),  
        new Dog("Rocky", "black", 5)  
    )  
);  
printList(Arrays.asList(50, 60));  
printList(Arrays.asList(50.45, 60.78));  
// output:  
// [generics.Cat@b1fa3959, generics.Dog@62294cd9]  
// [50, 60]  
// [50.45, 60.78]

List can be of any type now!!!

List 现在可以是任意类型的。

1️⃣ Upper Bounded Wild Cards

1️⃣ 上界通配符

Consider this example:

考虑下面的例子


public static void printAnimals(List<Animal> animals) {  
      animals.forEach(Animal::eat);  
}

If we imagine a subtype of Animal, such as a Dog, we can’t use this method with a list of Dog, even though Dog is a subtype of Animal. We can do this with a wild card.

如果我们想象一个 Animal 的子类型,例如 Dog ,我们就不能在 Dog 的列表中使用这个方法,尽管 DogAnimal 的子类型。

我们可以使用通配符来实现。


public static void printAnimals(List<? extends Animal> animals) {  
    ...  
}

Now this method works with type Animal and all its subtypes.

现在该方法适用于 Animal  类型和所有 子类型


printAnimals(  
    Arrays.asList(  
        new Cat("Jim", "brown", 2),  
        new Dog("Rocky", "black", 5)  
    )  
);

This is called an upper-bounded wildcard, where type Animal is the upper bound.

这被称为 上界通配符 ,其中 Animal 类型是上界。

2️⃣ Lower Bounded Wild Cards

2️⃣ 下限通配符

We can also specify wildcards with a lower bound, where the unknown type has to be a super type of the specified type. Lower bounds can be specified using the super keyword followed by the specific type.

我们还可以指定带有下限的通配符,其中未知类型必须是指定类型的 超类型 。可以使用 super 关键字指定下限,后面跟上特定的类型。

Example:

举例


public static void addIntegers(List<? super Integer> list){  
    list.add(new Integer(70));  
}

Generic Methods 通用方法

Imagine we need a method which takes different data types and do something. We can create a Generic method for this and reuse it.

想象一下,我们需要一个接收不同数据类型的方法来做一些事情。我们可以为此创建一个通用方法并重复使用。


public static <T> void call(T data) {  
    System.out.println(data);  
}  
call("hello");  
call(45);  
call(15.67);  
call(5L);  
call(new Dog("Rocky", "black", 5));  
/* output:  
    hello  
    45  
    15.67  
    5  
    generics.Dog@62294cd9  
*/

If we want to return data instead of VOID, we can do that also.

如果我们想返回数据而不是VOID,我们也可以这样做。


public static <T> T getData(T data) {  
    return data;  
}  
System.out.println(getData("Test"));   // output: Test

We can accept multiple data types also in a generic method.

我们也可以在泛型方法中接受多种数据类型。


public static <T, V> void getMultiData(T data1, V data2) {  
    System.out.println("data 1: " + data1);  
    System.out.println("data 2: " + data2);  
}  
getMultiData(50, "Shades of Grey");

I think I have covered almost all the things to be learnt in Generics. So, this would be an ideal article for you to practice Generics in Java. ❤️

我认为已经覆盖了泛型使用的大部分场景. 因此,这将是您练习Java泛型的理想文章。❤️

I will bring you another Java stuff next time.

下次我会给您带来另一款Java产品。

Bye guys! 🙌

再见 🙌

相关文章
|
7月前
|
存储 安全 Java
Java的泛型(Generics)技术性文章
Java的泛型(Generics)技术性文章
33 1
|
7月前
|
存储 安全 Java
Java语言特性:什么是Java中的泛型(Generics)?
Java语言特性:什么是Java中的泛型(Generics)?
68 1
|
7月前
|
安全 Java 编译器
【Java】Generics in Java
【Java】Generics in Java
34 0
|
7月前
|
安全 Java 定位技术
【Java】Generics in Java(一)
【Java】Generics in Java
43 0
|
12天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
10天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
12天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
6天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
6天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
23 3
|
7天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####