【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 的列表中使用这个方法,尽管 Dog 是 Animal 的子类型。
我们可以使用通配符来实现。
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! 🙌
再见 🙌