Click “Java Base” above and select “Set as star”

Be a positive person, not a negative person!

Source code boutique column

  • Original | Java 2019 super god road, very ~

  • Chinese detailed annotation of open source project

  • RPC framework Dubbo source code analysis

  • Network application framework Netty source code analysis

  • RocketMQ source code parsing

  • Database middleware Sharding-JDBC and MyCAT source code analysis

  • Source code parsing for Job scheduling middleware, Elastice-job

  • Distributed Transaction middleware TCC-transaction source code analysis

  • Eureka and Hystrix source code parsing

  • Java concurrent source code

Source: http://rrd.me/eqC4T

  • preface

  • Benefits of generics

  • Wildcards in generics

    • The usual T, E, K, V?

    • ? Unbounded wildcard

    • The upper bound wildcard <? extends E>

    • The lower wildcard <? super E>

    • ? And T

  • The difference between Class and Class

  • summary


preface

Java Generics is a new feature introduced in JDK 5. Generics provide compile-time type-safety checks that allow developers to detect illegal types at compile time.

The nature of generics is parameterized typing, which means that the data type being operated on is specified as a parameter.

Benefits of generics

In the absence of generics, arguments can be “arbitrary” by referring to the type Object. The disadvantage of “arbitrary” is that explicit casts are required, which require the developer to be able to predict the actual parameter types. In the case of a cast error, the compiler may not give an error until runtime, which is itself a security risk.

The advantage of generics, then, is that type safety can be checked at compile time, and all casts are automatic and implicit.

public class GlmapperGeneric<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public static void main(String[] args) {// do nothing} / public void noSpecifyType(){GlmapperGeneric glmapperGeneric = new GlmapperGeneric(); glmapperGeneric.set("test"); // Cast String test = (String) glmappergeneric.get (); System.out.println(test); Int specifyType(); int specifyType(); int specifyType(); int specifyType(); int specifyType(); int specifyType(); int specifyType(); glmapperGeneric.set("test"); String test = glmappergeneric.get (); System.out.println(test); }}Copy the code

SpecifyType methods in this code omit casting to check type safety at compile time and can be used on classes, methods, and interfaces.

Wildcards in generics

When we define generic classes, generic methods, and generic interfaces, we often encounter different wildcards, such as T, E, K, V, and so on. What do these wildcards mean?

The usual T, E, K, V?

Essentially, these are wildcards, no difference, just code conventions. For example, in the above code, T can be replaced with any letter between A and Z without affecting the normal operation of the program. However, if T is replaced with other letters, the readability may be weaker. In general, T, E, K, V, right? Here’s the deal:

  • ? Represents an indeterminate Java type

  • T (type) indicates a specific Java type

  • K and V are key values in Java key values

  • E stands for Element

?Unbounded wildcard

Let’s start with a small example. The original text is here.

I have a parent Animal and several subclasses like dog, cat, etc. Now I need a list of animals. My first thought is something like this:

List<Animal> listAnimalsCopy the code

But the boss did have this idea:

List<? extends Animal> listAnimalsCopy the code

Why use wildcards instead of simple generics? Wildcards don’t really mean much when you declare local variables, but they are very important when you declare an argument to a method.

static int countLegs (List<? extends Animal > animals ) { int retVal = 0; for ( Animal animal : animals ) { retVal += animal.countLegs(); } return retVal; }static int countLegs1 (List< Animal > animals ){ int retVal = 0; for ( Animal animal : animals ) { retVal += animal.countLegs(); } return retVal; }public static void main(String[] args) { List<Dog> dogs = new ArrayList<>(); CountLegs (dogs); / / error countLegs1 (dogs); }Copy the code

When countLegs1 is called, it flutters red with the following error message:


So, if you’re unsure or don’t care about the type you’re actually operating on, you can use unrestricted wildcards (a question mark in Angle brackets, i.e.) to indicate that you can hold any type. As in countLegs, the last class is qualified, but it doesn’t care what type it is, so all subclasses of Animal passed in can be supported without an error. CountLegs1 doesn’t.

The upper bound wildcard <? extends E>

Last: Declared with the extends keyword to indicate that the parameterized type may be the specified type or a subclass of that type.

Using extends in a type parameter means that the parameter in the generic must be E or a subclass of E. This has two benefits:

  • If the type passed is not E or a subclass of E, the compilation fails

  • The E method can be used in generics, otherwise you have to cast to E to use it

private <K extends A, E extends B> E test(K arg1, E arg2){    E result = arg2;    arg2.compareTo(arg1);    //.....    return result;}Copy the code

If there are more than one upper limit of type parameters in the type parameter list, separate them with commas

The lower wildcard <? super E>

Lower bound: declared with super, indicating that the parameterized type may be the specified type or a parent of the type, up to Object

Using super in type parameters indicates that the parameters in the generic must be E or a parent of E.

private <T> void test(List<? super T> dst, List<T> src){ for (T t : src) { dst.add(t); }}public static void main(String[] args) { List<Dog> dogs = new ArrayList<>(); List<Animal> animals = new ArrayList<>(); new Test3().test(animals,dogs); } class Dog extends Animal {}Copy the code

The DST type is “greater than or equal to” SRC, where “greater than or equal to” means that DST represents a greater range than SRC, so a container that can hold DST can also hold SRC.

? And T


? And T are indeterminate types, the difference is that we can operate on T, but right? No, like this:

T = operate(); // No? car = operate();Copy the code

To summarize briefly:

T is a definite type, usually used in the definition of generic classes and generic methods,? Is an indeterminate type that is usually used for calling code and parameters of generic methods and cannot be used to define classes and generic methods.

Difference 1: T is used to ensure consistency of generic parameters

Public <T extends Number> voidTest (List<T> dest, List<T> SRC) Public voidTest (List<? extends Number> dest, List<? extends Number> src)Copy the code

As in the following code, the convention T is a subclass of Number, but the declaration is a String, so it will float red error.


There is no guarantee that two lists will have the same element type

GlmapperGeneric<String> glmapperGeneric = new GlmapperGeneric<>(); List<String> dest = new ArrayList<>(); List<Number> src = new ArrayList<>(); glmapperGeneric.testNon(dest,src);Copy the code

The above code does not generate an error from the compiler, but when operating inside testNon methods (such as assignment), the dest and SRC types still need to be cast.

Difference 2: Type parameters can be multi-qualified but wildcards cannot


Use the ampersand symbol to set Multi Bounds, specifying that the generic type T must be a common subtype of MultiLimitInterfaceA and MultiLimitInterfaceB, at which point the variable T has all qualified methods and properties. In the case of wildcards, because it is not a deterministic type, it cannot be multiqualified.

Difference 3: Wildcards can be superclass-qualified while type parameters cannot

The type parameter T has only one type qualification:

T extends ACopy the code

But wildcards? Two kinds of qualification can be made:

? extends A? super ACopy the code

The difference between Class and Class

That was introduced, right? And T, so for Class

and

< p style = “max-width: 100%; clear: both; min-height: 1em; Class < T > Class

>

The most common use is in reflection scenarios, which are illustrated here with an emission code.

// Create a multiLimit object by reflection. We need to use the cast MultiLimit MultiLimit = (MultiLimit)Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();Copy the code

For the above code at runtime, if the reflective type not MultiLimit class, so must be submitted to the Java lang. ClassCastException error.

In this case, you can use the following code instead to check for type problems directly at compile time:


Class

When instantiated, T is replaced with a concrete Class. Class
< span style = “box-sizing: border-box! Important; Can represent any type, so it is mainly used for declarative restrictions. For example, we can declare this:

Public Class<? > clazz; Public Class<T> clazzT;Copy the code

So you can define a Class when you don’t know what type of Class to declare.


Public Class

clazzT; In this case, you have to make the current class also specify T,

public class Test3<T> { public Class<? > clazz; Public Class<T> clazzT;Copy the code

summary

This article has pieced together a few points in JAVA generics for your reference. If there are any improper places in the article, please correct them.



Welcome to join my knowledge planet to discuss architecture and exchange source code. To join, long press the qr code below oh:

Has been updated in knowledge planet source code parsing as follows:

If you like this post, like it, forward it.

Life is good. See you tomorrow. · ω ·. ノ ♡