编程知识 cdmana.com

A deeper understanding of Java generics

1. introduction

jdk5.0 Introduced in Java Generic , The goal is to reduce mistakes , And add an extra layer of abstraction to the type . This article will briefly introduce Java The generics in 、 The goal behind generics and how to use generics to improve code quality .

2. Why use generics

Imagine a scenario , We hope to use Java Create a list to store Integer; The code might be written like this :

List list = new LinkedList(); list.add(new Integer(1));  Integer i = list.iterator().next();  Copy code 

 

It's amazing , The compiler will prompt for the last line . It doesn't know what type of data is returned . therefore , The compiler prompts for an explicit conversion :

Integer i = (Integer) list.iterator.next();  Copy code 

 

There is no convention to guarantee that the return type of a list is Integers . The defined list can contain any object . We only know that we retrieve the list by checking the context . When viewing types , It can only guarantee that it is a Object, Therefore, explicit conversion is needed to ensure that the type is safe .

This conversion can be noisy , We know that the data type in this list is Integers . If you switch , It's also messing up our code . If the programmer makes a mistake in an explicit transformation , It may result in throwing and Type related runtime error .

If programmers can express their intention to use a particular type , And the compiler can ensure the correctness of this type , So it's going to be easier .

This is the core idea behind generics .

We change the first line of the previous code snippet to read :

List<Integer> list = new LinkedList<>();  Copy code 

 

By adding the diamond operator containing the type <>, Let's narrow the list down to Integer   type , The specified type is saved in the list . The compiler can enforce the type at compile time .

In smaller programs , It looks like a trivial addition . But in larger programs , This can increase significant robustness and make the program easier to read .

3. Generic methods

Generic methods are methods written with a single method declaration , You can call... With different types of parameters . The compiler will ensure that the type used is correct . Here are some properties of generic methods :

  • A generic method has a type parameter before the return type of the method declaration ( Diamond operator for parcel type )

  • Type parameters can be bounded ( The boundary will be explained later in this article )

  • Generic methods can have different type parameters , These parameters are separated by commas in the method signature

  • The method body of a generic method is the same as that of a normal method

An example of defining a generic method to convert an array to a list :

public <T> List<T> fromArrayToList(T[] a) {        return Arrays.stream(a).collect(Collectors.toList()); }  Copy code 

 

In the previous example , In the method declaration <T> Indicates that the method will handle generic types T. Even if the method returns void, It needs to be done as well . As mentioned above , Method can handle multiple generic types , under these circumstances , All generic types must be added to the method declaration , for example , If we want to modify the above method to handle types T And type G , It should be written like this :

public static <T, G> List<G> fromArrayToList(T[] a, Function<T, G> mapperFunction) {     return Arrays.stream(a)       .map(mapperFunction)       .collect(Collectors.toList()); }  Copy code 

 

We're passing a function , The function will have T An array of type elements is converted to contain G List of type elements . for example , take Integer Convert to String Representation form :

@Test public void givenArrayOfIntegers_thanListOfStringReturnedOK() {     Integer[] intArray = {1, 2, 3, 4, 5};     List<String> stringList       = Generics.fromArrayToList(intArray, Object::toString);       assertThat(stringList, hasItems("1", "2", "3", "4", "5")); }  Copy code 

 

Oracle It is recommended to use uppercase letters for generic types , And choose more descriptive letters to represent the type of form , For example, in Java Collection ,T Used of type ,K The key ,V Indicated value .

3.1. Generic boundaries

As mentioned earlier , Type parameters can be bounded . Bounded means “ Limit ”, We can limit the types of methods that can be accepted .

for example , You can specify a method to accept a type and all its subclasses ( ceiling ) Or a type, all its superclasses ( Lower limit ).

To declare the upper bound type , We use keywords after types extends, Follow the upper limit to use . for example :

public <T extends Number> List<T> fromArrayToList(T[] a) {     ... }  Copy code 

 

The keyword is used here extends Indicates the type T Extend the upper limit of the class , Or implement the upper limit of the interface .

3.2. Multiple boundaries

Types can also have multiple upper bounds , As shown below :

<T extends Number & Comparable>  Copy code 

 

If T One of the types of extensions is class ( namely Number, It must be placed first in the list of boundaries . otherwise , Will cause compile time errors .

4. Use wildcards

Wildcard in Java Chinese question mark ““ Express , They are used to refer to an unknown type . Wildcards are especially useful when using generics , Can be used as a parameter type , But the first thing to consider is an important comment .

as everyone knows ,Object It's all Java The supertype of a class , however ,Object Is not a supertype of any set .( It may be a little winding , Let's have a good taste )

for example ,List<Object> No List<String> The supertype of , take List<Object> A variable of type is assigned to List<String> Variables of type will cause compiler errors .

This is to prevent possible conflicts when adding heterogeneous types to the same collection .

The same rules apply to any set of types and their subtypes . Take a look at this example :

public static void paintAllBuildings(List<Building> buildings) {     buildings.forEach(Building::paint); }  Copy code 

 

If we imagine a subtype Building, example House, So we can't combine this method with House Lists are used together , Even if House yes Building Subtypes of . If you need to use this method with a type build and all its subtypes , The bounded wildcard can achieve the following functions :

public static void paintAllBuildings(List<? extends Building> buildings) {     ... }  Copy code 

 

Now? , This method can deal with Building Type and all its subtypes . This is called the upper bound wildcard , The type Building It's the upper bound .

Wildcards can also be specified with a lower bound , Where the unknown type must be a supertype of the specified type . have access to super Keyword followed by a specific type to specify the lower bound , for example ,<? super T> Indicates an unknown type , It is T(=T And all of its parents ) Superclass of .

5. Type Erasure

Generics are added to Java To ensure type safety , And make sure that generics don't cause overhead at run time , At compile time, the compiler applies a name called type erasure The process of .

Type erase removes all type parameters , And replace them with their boundaries , If the type parameter is unbounded , Is replaced by Object. therefore , The compiled bytecode contains only ordinary classes 、 Interfaces and methods , To ensure that no new types are generated . At compile time Object The correct type is also applied . Here is an example of type erasure :

public <T> List<T> genericMethod(List<T> list) {     return list.stream().collect(Collectors.toList()); }  Copy code 

 

Use type erase , Unbounded type T Replace with Object, As shown below :

// for illustration public List<Object> withErasure(List<Object> list) {     return list.stream().collect(Collectors.toList()); }   // which in practice results in public List withErasure(List list) {     return list.stream().collect(Collectors.toList()); }  Copy code 

 

If the type is bounded , At compile time, the type is replaced with binding :

public <T extends Building> void genericMethod(T t) {     ... }  Copy code 

 

Changes occur after compilation :

public void genericMethod(Building t) {     ... }  Copy code 

 

6. Generics and raw data types

Java One limitation of generics in is that type parameters cannot be primitive types

for example , The following cannot be compiled :

List<int> list = new ArrayList<>(); list.add(17);  Copy code 

 

To understand why raw data types don't work , Just remember Generics are compile time features , This means that the type will be erased , All generic types are implemented as Object class . For example , Let's look at the list of add Method :

List<Integer> list = new ArrayList<>(); list.add(17);  Copy code 

 

add The method is declared as follows :

boolean add(E e);  Copy code 

 

And will be compiled as :

boolean add(Object e);  Copy code 

 

therefore , Type parameters must be convertible to Object. Because the base type does not inherit from Object, So you can't use them as type parameters however ,Java The type of packing is provided for them , And automatic packing and unpacking :

Integer a = 17; int b = a;  Copy code 

 

therefore , If we want to create a list that can hold integers , We can use wrappers :

List<Integer> list = new ArrayList<>(); list.add(17); int first = list.get(0);  Copy code 

 

The compiled code is equivalent to :

List list = new ArrayList<>(); list.add(Integer.valueOf(17)); int first = ((Integer) list.get(0)).intValue();  Copy code 

 

Java Future versions of may allow generics to use raw data types .Valhalla Engineering aims to improve the way generics are handled . The idea is to realize JEP 218 Generic specialization described in .

7. summary

Java Generics are right for Java A powerful complement to language , Because it makes the programmer's job easier , It's also less likely to make mistakes . Generics enforce type correctness at compile time , also , most important of all , Can implement generic algorithms , It doesn't add any extra overhead to our application .


author : Big guy out of the pot

版权声明
本文为[Sleeping devil's lies]所创,转载请带上原文链接,感谢

Scroll to Top