Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Java generics

2025-01-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article focuses on "how to use Java generics". Friends who are interested may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor learn how to use Java generics.

What is generics?

Generics is a new feature introduced in JDK 5, that is, "parameterized types". Generally speaking, the original specific types are defined by parameterization, and the specific types (type arguments) are passed in when they are used or called.

The essence of generics is to parameterize types (the specific types of formal parameters are controlled by different types specified by generics without creating new types). In the use of generics, the data type of the operation is specified as a parameter, which can be used in classes, interfaces, and methods, which are called generic classes, generic interfaces, and generic methods, respectively.

Why use generics?

When generics are not used, parameters can be "arbitrary" through Object, but the drawback is that explicit casting is required, which requires developers to know the actual type.

There will be errors when casting, for example, Object converts the actual type to String and forcibly converts it to Integer. The compile time will not prompt an error, but an exception will be thrown at run time, which is an obvious security risk.

By introducing the generic mechanism, Java can check the above hidden dangers in advance to the compilation time, so that developers can not only know the actual types clearly, but also prompt errors through the check at the compilation time, so as to improve the security and robustness of the code.

Comparison before and after using generics

Take a classic example to demonstrate the problems if generics are not used.

List list = new ArrayList (); list.add (1); list.add ("zhuan2quan"); list.add ("Program New Horizon"); for (int I = 0; I

< list.size(); i++) { String value = (String) list.get(i); System.out.println("value=">

The above code does not report any errors at the compiler, but throws the following exception when executed:

Java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

So, can you solve this problem at the compiler instead of throwing an exception at run time? Generics emerge as the times require. After the above code is written in generics, it becomes as follows:

List list = new ArrayList (); list.add (1); list.add ("zhuan2quan"); list.add ("Program New Horizon"); for (String value: list) {System.out.println ("value=" + value);}

As you can see, the code becomes cleaner and simpler, and the line of list.add (1) prompts the error message directly in IDE:

Required type: StringProvided: int

The error message is that generics constrain the data added to List and can only be of String type.

Wildcards in generics

It is common to see T, E, K, V wildcards when using generics. What do they mean?

In essence, they are all wildcards, and there is no difference, so any letter between Amurz will do. However, there are some unwritten agreements among developers:

T (type) represents a specific java type

KV (key value) stands for Key Value in the java key value, respectively.

E (element) stands for Element

Why Java generics are pseudo generics

For backward compatibility, generics in Java are just syntactic sugar, not true generics like C++.

Again in the above example, adding an int type directly to a List whose generic type is String prompts an error:

List list = new ArrayList (); list.add (1)

For the above code, we use reflection to call the add method indirectly:

@ Testpublic void test3 () throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {List list = new ArrayList (); list.add (1); Method add = list.getClass (). GetMethod ("add", Object.class); add.invoke (list, "Program New Horizon"); System.out.println (list); System.out.println (list.get (1));}

After executing the above code, we find that the program does not throw an exception and prints in and out normally:

[1, New Vision of Program] New Vision of Program

The List, which could only be loaded into Integer, successfully loaded a value of type String. Thus it can be seen that the so-called generics are indeed pseudo generics.

At the same time, we can prove it by bytecode. Take the example code that uses generics above and look at the bytecode through the javap-c command:

Code: 0: new # 2 / / class java/util/ArrayList 3: dup 4: invokespecial # 3 / / Method java/util/ArrayList. "": () V 7: astore_1 8: aload_1 9: ldc # 6 / / String zhuan2quan 11: invokeinterface # 5 2 / / InterfaceMethod java/util/List.add: (Ljava/lang/Object ) Z 16: pop 17: aload_1 18: ldc # 7 / / New Horizon of String Program 20: invokeinterface # 5, 2 / / InterfaceMethod java/util/List.add: (Ljava/lang/Object;) Z 25: pop 26: aload_1 27: invokeinterface # 18, 1 / / InterfaceMethod java/util/List.iterator: () Ljava/util/Iterator 32: astore_2 33: aload_2 34: invokeinterface # 19, 1 / / InterfaceMethod java/util/Iterator.hasNext: () Z 39: ifeq 80

As you can see from the bytecode, the List.add method is essentially an Object. Once again, Java's generics are valid only at compile time and are erased at run time, which means that all generic parameter types are cleared after compilation. This is what we often call type erasure.

Therefore, it can also be said that generic types are logically regarded as many different types, but in fact they are all the same basic types.

Definition and use of generics

There are three types of generics: generic classes, generic interfaces, and generic methods.

Before we learn about these three types of generic usage scenarios, we need to make it clear that generic declarations are usually defined with uppercase letters, such as. It's just that different types, different locations of declarations, and different ways of using them.

Generic class

The syntax form of a generic class:

Class name {/ *... * /}

The declaration of a generic class is similar to that of a non-generic class, except that the type parameter declaration section is added after the class name. The part of the type parameter separated by angle brackets () follows the class name. It specifies type parameters (also known as type variables) T1, T2, … And Tn. The class name in a generic type is generally referred to as a prototype, and the specified parameter is called a type parameter.

Examples of use:

/ / T is arbitrarily identified, such as T, E, K, V, etc., to represent the member variables of the generalization of public class Foo {/ / generalization. The type of T is specified externally, and the type of private T info; / / constructor type is public Foo (T info) {this.info = info. } / / when public T getInfo () {return info;} public static void main (String [] args) {/ / instantiates a generic class externally, you must specify the specific type of T, in this case String. / / the argument type passed in must be the same as the type parameter type of the generic type, which is String in this case. Foo foo = new Foo ("New Vision of the Program"); System.out.println (foo.getInfo ());}}

Of course, in the above example, when using generic classes, you can also not specify the actual type, which is syntactically supported, so this is not recommended at this time, just like undefined generics.

Foo foo11 = new Foo (1)

For example, the above writing is also feasible, but the time zone defines the meaning of generics.

Generic interface

The declaration of the generic interface is the same as that of the generic class, and the generic interface syntax forms:

Public interface Context {T getContext ();}

There are two ways to implement a generic interface: subclasses explicitly declare generic types and subclasses do not explicitly declare generic types.

Let's start with an example of a subclass that explicitly declares a generic type:

/ / if the argument type has been passed in when implementing the generic interface, all places where the generic type is used should be replaced with the passed argument type public class TomcatContext implements Context {@ Override public String getContext () {return "Tomcat";}}

The subclass does not explicitly declare generic types:

/ / when no generic argument is passed in, it is the same as the definition of the generic class. When declaring the class, you need to add the declaration of the generic type to the class public class SpringContext implements Context {@ Override public T getContext () {return null;}}.

Of course, there is also a situation where we use classes defined as generics as normal classes as mentioned earlier.

In the above example, the generic parameters are all one, but you can also specify two or more:

Public interface GenericInterfaceSeveralTypes

< T, R >

{R performAction (final T action);}

Multiple generic parameters can be separated by commas (,).

Generic method

A generic class indicates the specific type of the generic type when instantiating the class; a generic method indicates the specific type of the generic type when calling the method. Generic methods can be normal methods, static methods, abstract methods, final-decorated methods, and constructors.

The syntax form of the generic method is as follows:

Public T func (T obj) {}

Inside the angle brackets is the list of type parameters, before the method returns the value T or the void keyword. The T defined in angle brackets can be used anywhere in a method, such as parameters, methods, and return values.

Protected abstract R performAction (final T action); static R performActionOn (final Collection

< T >

Action) {final R result =...; / / Implementation here return result;}

As you can see in the above example, a generic method can also define multiple generic types.

Take another look at the sample code:

Declare the generic type of this method between public class GenericsMethodDemo1 {/ / 1, public, and the return value. / / 2. Only declared methods are generic methods, and member methods in generic classes that use generics are not generic methods. / / 3, indicates that the method will use the generic type T, and only then can you use the generic type T in the method. / / 4, T can be any logo, such as T, E, K, V, etc. Public static T printClass (T obj) {System.out.println (obj); return obj;} public static void main (String [] args) {printClass ("abc"); printClass (123);}}

It is important to note that generic methods have nothing to do with whether the class is generic. In addition, static methods cannot access generics defined on the class; if the reference data type of static method operations is uncertain, generics must be defined on methods.

In the above example, if GenericsMethodDemo1 is defined as GenericsMethodDemo1, the printClass method cannot be used directly to the T on the class, and can only access the self-defined T as in the above code.

The difference between generic methods and ordinary methods

Next, let's compare the difference between generic and non-generic methods:

/ / method 1 public T getKey () {return key;} / / method 2 public T showKeyName (T t) {return t;}

Method one uses the generic declaration T, but it uses variables defined in the generic class, so this method is not a generic method. For example, in method 2, T is declared by two angle brackets, which is the real generic method.

For method 2, there is also a case where T is also declared in the class, so the T of the method parameter only refers to the T of the method, not the T of the class.

Generic methods and variable parameters @ SafeVarargspublic final void print (T... Args) {for (T t: args) {System.out.println ("t =" + t);}} public static void main (String [] args) {GenericDemo2 demo2 = new GenericDemo2 (); demo2.print ("abc", 123);}

The print method prints out the results in the variable parameter args, and the variable parameter can pass different specific types.

Print the results:

T=abct=123

A summary of generic methods is: if you can use generic methods as much as possible, you can bring generics to the most needed range. If you use a generic class, the entire class is generalized.

Generic wildcard character

Type wildcards are generally used? Instead of specific type arguments (in this case, type arguments, not type arguments). When you do not need to use the specific functions of the type when manipulating the type, you can use only the functions in the Object class. Wildcards to indicate unknown types. For example, List is logically the parent class of all List such as List, List, and so on.

/ * in the method that uses List as a formal parameter, you cannot pass in an instance of List, * that is to say, you cannot treat List as a subclass of List. * / public static void getNumberData (List data) {System.out.println ("data:" + data.get (0));} / * in the method that uses List as the formal parameter, you cannot use the instance of List to pass in; * / public static void getStringData (List data) {System.out.println ("data:" + data.get (0));} / * * use type wildcards to represent reference types that are both List and List and List. * Type wildcards are generally used? Instead of specific type arguments, note that here are type arguments; * it is a practical type like Number, String and Integer. As the parent of all types. * / public static void getData (List data) {System.out.println ("data:" + data.get (0);}

Of the above three methods, getNumberData can only pass parameters of type List, and getStringData can only pass parameters of type List. If they all use only the functionality of the Object class, they can be declared in the form of a getData method, and various types are supported at the same time.

These types of wildcards are also known as unbounded wildcards, and there are two application scenarios:

Methods that can be implemented using the functionality provided in the Object class.

Use methods in generic classes that do not depend on type parameters.

Is it used in getData? As a wildcard, but in some scenarios, you need to restrict the upper and lower boundaries of generic type arguments. For example, type arguments can only be passed in a certain type of parent class or a certain type of subclass.

Examples of upper-bound wildcards are as follows:

The upper limit of a type wildcard is defined by a form such as List, which means that the wildcard generic value accepts Number and its underlying subclass types. * / public static void getUperNumber (List

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report