Master the Java generic type (1)

xiaoxiao2021-03-06  73

Data type conversion and errors are for understanding generic types, what we want to turn your attention to the most easily caused errors in Java languages ​​- need to constantly turn the expression down type conversion (Downcast) as its static type More specific data types (see "The Double Descent Bug Pattern" in the reference to find some aspects of the troubles that may encounter when performing data type conversion.

Each down type conversion in the program is potential danger for ClassCastException, which should try to avoid them. But in the Java language they are usually unavoidable, even in the program of excellent design.

The most common reason for the down type conversion in the Java language is that the class is often used in a dedicated manner, which limits the possible runtime type of parameters returned by the method. For example, it is assumed to add an element to the HashTable and retrieve elements from it. Then, in a given program, the element type used as a key and the value stored in the hash table will not be any object. Typically, all keys are an instance of a particular type. Similarly, the stored value will work together to more specific public types than Object.

However, in the currently current Java language versions, it is impossible to declare a specific key and element of the hash table as a more specific type than Object. The type characteristic that performs insertion and retrieval operation on the hash table tells us that only one object can only be inserted and deleted. For example, the instructions for PUT and GET operations are as follows:

Listing 1. Insert / retrieval type Description Indicates that can only be any object

Class Hashtable {

Object Put (Object Key, Object Value) {...}

Object Get (Object Key) {...}

...

}

Therefore, when we retrieve elements from class HashTable instances, such as, even if we know only String in HashTable, the type system only knows that the value retrieved is the object type. This is also the case before any String operation is performed on the search value, and it is necessary to add it to String, even if the retrieved element is added to the same code block!

Listing 2. Mandatory converted to String

Import java.util.hashtable;

Class test {

Public static void main (String [] args) {

Hashtable h = new hashtable ();

H.PUT (New Integer (0), "Value");

String s = (string) h.get (new integer (0));

System.out.println (s);

}

}

Note that the data type conversion required in the third line of the main part of the MAIN method. Because the Java type system is quite weak, the code will vulnerability due to the conversion of data type above. These data type conversions not only make Java code more dragging length, but they also reduce the value of static type checks (because each data type conversion is a selection to ignore the puppet inspection of the static type check). How should we expand this type of system so that we don't have to avoid it?

Use generic type to solve problems! To eliminate the data type conversion as described above, there is a universal method that uses generic types to increase the Java type system. The generic type can be regarded as the type "function"; they can be parametric by type variables, which can be instantiated with various types of parameters according to the context.

For example, in different ways to define class HashTable, we can define generic class HashTable , where KEY and VALUE are type parameters. In addition to the series of type parameters declared after the name, the syntax of such generic classes is defined in Tiger and the syntax for defining a common class is very similar. For example, you can define your own generic HashTable class as follows: List 3. Define generic HashTable classes

Class HashTable {...}

These types of parameters can then be referenced, just like we reference a normal type in the class definition body, as shown below:

Listing 4. Quote type parameters like reference to normal types

Class HashTable {

...

Value Put (Key K, Value V) {...}

Value Get (Key K) {...}

}

The scope of the type parameter is the main part of the corresponding class (except for static members) (in the next article, we will discuss such a "monster" in the Tiger implementation, that is, this limit must be performed on static members. .Please note!).

When you create a new HashTable instance, you must pass the type parameters to specify the type of Key and Value. The way the type parameters depends on how we plan to use HashTable. In the above example, we really want to do it is to create a HashTable instance, which only maps the Integer to String. You can use the new HashTable class to do this:

Listing 5. Creating an instance of mapping an Integer to string

Import java.util.hashtable;

Class test {

Public static void main (String [] args) {

Hashtable H = new hashtable ();

H.PUT (New Integer (0), "Value");

...

}

}

The data type is no longer needed. Please note the syntax used to instantiate the generic class HashTable. As the type of generic type parameters are enclosed with a sharp bracket, the parameters of the generic type application are also enclosed with a sharp bracket.

Listing 6. Remove unnecessary data type conversion

...

String s = h.get ("key");

System.out.println (s);

Of course, if programmers are only necessary to redefine all standard utility classes (such as HashTable and List) if they can use generic types, they may be a vast project. Fortunately, Tiger provides users with a generic version of all Java collection classes, so we don't have to do it yourself to redefine them. In addition, these can seamless work with old code and new generic code (next month, we will explain how to do this).

Tiger's basic type limits one of the limits of type variables in Tiger is that they must be instantiated with reference types - the basic type does not work. Therefore, in this example, it is unable to complete the HashTable that is mapped from INT to String.

This is unfortunately, because this means that as long as you want to use the basic type as a generic parameter, you must assemble them as an object. On the other hand, the current situation is worse; you cannot pass the int as a button to HashTable, because all keys must be Object type.

What we really want to see is that the basic type can be automatically packaged and unboxing, similar to the operations performed by C # (or better than the latter). Unfortunately, Tiger does not intend to include basic types of automatic packaging (but people can always look forward to this feature in Java 1.6!). Submitted generics Sometimes we want to limit the type of generic class that may occur. In this example, the type parameters of class HashTable can be instantiated with any type parameters we want, but for some other classes, we may want to limit possible type parameter sets as subtypes within a given type. .

For example, we might want to define generic ScrollPane classes, which references ordinary PANE with scrollbar function. The runtime type of PANE is usually the subtype of class PANE, but the static type is just PANE.

Sometimes we want to retrieve the contained PANe with getter, but I hope that the return type of Getter may be specific. We might want to add type parameters MyPane to ScrollPane, which can be instantiated with any subclasses of PANE. You can then use this form of clause: Extends Bound to illustrate the declaration of MyPane to set the range of MyPane:

Listing 7. To illustrate the MYPANE declaration with an Extends clause

Class scrollpane {...}

Of course, we can completely do not use explicit ranges, as long as it is ensured that the type parameters are not used in an inappropriate type.

Why do you want to find a range on the type parameters? There are two reasons here. First, the scope enables us to add static type check. With a static type check, you can guarantee that each instantiation of generic types is in line with the range set.

Second, because we know that each instantiation of type parameters is subclasses within this range, it can be assured that the type parameter instance is in this range. If there is no explicit range for parameters, then the range is Object, which means that we cannot call a range instance any method that has not appeared in Object.

The polymorphism method is used to parameterize the method with type parameters in addition to the type parameters. It is often also useful to use the type parameters. In the generic Java programming language, the method for parameterizing the type is called a polymorphic method.

The reason why the polymorphism method is useful, because sometimes, in some operations we want, the type correlation between parameters and return values ​​is originally, but this generic nature does not depend on any type of type. Information, and is different for each method call.

For example, assume that the Factory method is added to the list class. This static method takes only one parameter and will be the only element of the List (until other elements). Because we want List to become generic types of elements included, it is desirable to have a static Factory method with an instance of the type variable T and returns an instance of List .

But we do hoping that the type variable T can declare on the method level because it changes with each individual method to call (and, as I will discuss in the next article, Tiger design "monster" "The stated static member is not within the category of the class type parameters). Tiger lets we declare type parameters at a separate method level by prefix the type parameters as a method declared. For example, the prefix can be added to the Factory method Make as follows:

Listing 8. Add type parameters as a prefix to method declaration class utilities {

Public Static List Make (t first) {

Return New List (first);

}

}

In addition to the flexibility added in the polymorphic method, TiGer has also increased an advantage. Tiger uses the type inference mechanism to automatically infer the type of polymorphism based on parameter types. This greatly reduces the cumbersome and complexity of method calls. For example, if you want to call your Make method to construct a new instance containing new integer (0), then you only need to write:

Listing 9. Mandatory Make Construction New Instance

Utilities.make (Integer (0))

The instantiation of the type parameters will then be inferred from the method parameters.

The end language is as we see, adding generic types in the Java language will definitely greatly enhance our ability to use the static type system. Learning how to use generic types is quite simple, but it also needs to avoid some defects. In the next article, we will discuss how to fully use the specific performance of generic types that will appear in Tiger, as well as some defects. We will also study the extension of generic Java type tools, and we look forward to this tool in the Java platform that is still in the design phase.

转载请注明原文地址:https://www.9cbs.com/read-87420.html

New Post(0)