Master the Java generic type (2)

xiaoxiao2021-03-06  73

The limit of generic types allows us to first check the use restrictions of Tiger and JSR-14 general types:

Closed type parameters should not be referenced in static members. The generic type parameters cannot be instantiated with basic types. The "exposed" type parameters cannot be used in data type conversion or instanceof operations. The "exposed" type parameters cannot be used in New operations. You cannot use the "exposed" type parameter in the class definition of the type definition.

Why have these restrictions? This is due to Tiger and JSR-14 for mechanisms used in the JVM. Since the JVM does not support generic types, these compilers "play a trick", which seems to have support for generic types - they use generic type information to check all code, but "erase" all the pan Type and generate a class file containing only normal types.

For example, the generic type of List is removed only LIST. "Decode" type parameters - Alone instead of the type parameters in a type (such as type parameters in class List ) - is simply erased into their upper bounds (on T, The boundary is Object).

The function of this technology is extremely powerful; we can enhance the accuracy of almost all generic types, but keep it compatible with JVM. In fact, we can even alternately use non-floating old classes (such as List) and their corresponding generic classes (List ); both look like running.

Unfortunately, as indicated by the above restrictions, this feature is available. Erase in this way is introduced into the type system, which limits the security of our generic type.

To help each restriction, we will see examples of these restrictions. In this article, we will discuss the top three restrictions. The problem related to the latter limitations is too complicated, and thus a more in-depth study is required, and the next article is discussed.

Closed type parameters in static members are completely prohibited from reference to closed type parameters in static methods and static internal classes. Therefore, for example, the following code is illegal in Tiger:

Listing 1. Unfair reference closure type parameters in static context

Class C {

Static void m () {

T t;

}

Static class d {

C T;

}

}

When compiling this code, two errors are generated:

The error illegally reference T by the illegal reference T in the static method m illegally reference TE to the error

When defining a static field, the situation becomes more complicated. In JSR-14 and TiGer, share static fields in this class in all instances of generic classes. Now, in JSR-14 compilers 1.0 and 1.2, if you reference type parameters in a static field declaration, the compiler will not report error, but it should do this. Fields are shared This fact is easy to cause strange errors at runtime, such as ClassCastException in code that does not contain data type conversion.

For example, the following procedure will be compiled with both versions of JSR-14 without any warning:

Listing 2. References for the closed type parameters in the static field

Class C {

Static T MEMBER;

C (t t) {member = t;

T getmember () {returnember;}

Public static void main (String [] args) {

C C = New C ("Test");

System.out.println (C.getMember (). TOSTRING ()); New c (New Integer (1));

System.out.println (C.getMember (). TOSTRING ());

}

}

Note that each time the instance of the class C is allocated, the static field MEMBER is reset. Moreover, it is set to the type of object depends on the type of the instance of C! In the supplied main method, the first example c is a C type. The second is C type. Whenever the MEMBER is accessed from C, it is always assumed that the type of MEMBER is String. However, after the second instance of type C is allocated, the type of MEMBER is Integer.

The results of the MAIN method running C will be surprised - it will send a ClassCastException! The source code does not contain any data type conversion, how can this? It turns out that the compiler does insert the data type conversion into the code during the compile stage, which is to solve the type of accuracy of the type of expression to reduce certain expressions. These data type conversions are expected to be successful, but they are not successful in this case.

This special "function" of JSR-14 1.0 and 1.2 should be considered an error. It destroys the soundness of the type system, or it can be said that it destroys the "basic contract" that type system should be reached with programmers. As is done by static methods and classes, it will be much better as the programmer will definite type in the static field.

Please note that the problem that is allowed to have potential "explosive" code is not the programmer intentionally override the type system in its own code. The problem is that the programmer may not intend to write such code (for example, due to the "copy and paste" operation, incorrectly include a static modifier in the field declaration).

Type Checker can help programmers recover from these types of errors, but for static fields, type systems will actually make programmers more confused. How should we diagnose such errors when the unique error displayed in the code that is converted in the data type conversion is ClassCastexception? For programmers who do not know the implementation of Tiger's general type, it is even better to assume a reasonable operation of the type system. Because in this case, the type system is not reasonably running.

Fortunately, the latest version of JSR-14 (1.3) announced that the type parameters used in the static field are illegal. Therefore, we have reason to look forward to using type parameters in Tiger's static fields.

The generic type parameters and basic types are different from our discussion, this limitation does not have the same potential defect, but it will make your code very lengthy. For example, in a generic version of java.util.hashtable, there are two types of parameters: for the KEY type and for the value of the Value. So if we want a HashTable that maps String to String, we can specify a new instance with expressions new hashtable (). However, if we want a HashTable that maps String to int, we can only create an instance of HashTable , and package all INT values ​​in Integer.

Similarly, Tiger is of course also obtained by the implementation of the achievements used in this regard. Since the type parameter is erased for their boundaries, the boundary cannot be a basic type, so once the type is erased, the instantiation of the basic type will be completely meaningless. Data Type Conversion or "Explicit" parameters in InstanceOf is recalled that for the "exposed" type parameters, we refer to the type parameters that appear separately on the vocabulary, not a larger type of grammar component. For example, C is not a "exposed" type parameter, but in the C body) T is.

If the "exposed" type parameters are converted or instanceof operations in the code, the compiler will issue a warning name "unchecked". For example, the following code will generate a warning: Warning: unchecked Cast to Type T:

Listing 3. Wild code with unchecked operation

Import java.util.hashtable;

INTERFACE registry {

Public Void Register (Object O);

}

Class C Implements registry {

INT counter = 0;

Hashtable values;

Public c () {

Values ​​= new hashtable ();

}

Public void register (Object O) {

VALUES.PUT (New Integer (T) O);

Counter ;

}

}

You should treat these warnings seriously because they explain that your code is very strange at runtime. In fact, they will make the diagnostic code become extremely difficult. In the previous code, we believe that if the Register ("Test") is called for instance c , ClassCastException will be issued. But this is not the case; the calculation will continue, as if the data type conversion is successful, then make an error in further calculation, or worse: Calculation with the destroyed data, but no error signals will be applied. Similarly, INSTANCED "" unchecked "warnings will be generated at compile time when compiling, and check will not be run as scheduled.

Double-edged sword, what happened here? Because Tiger relies on type erase, the data type conversion and the exposed type parameters in the InstanceOf test are "erased" for their upper bound (in the previous example, that will be type Object). Therefore, the data type conversion of the type parameters will become converted to the upper bound of the parameter.

Similarly, InstanceOf will check if the operand is instanceof. That's not what we intend to do. If so, we can fully convert to the boundaries. Therefore, it is usually avoided to use data type conversion and instanceOf checking of type parameters.

However, sometimes in order to compile the code, you must rely on data type conversion to the type parameters. If this is the case, just remember, in that section of the code, the type check is not insurance - you will rely on yourself.

Although generic types are a strong weapon for making robust code, we have demonstrated that they will make code no longer robust and difficult to diagnose and correct. Next time, we will introduce the two limitations of Tiger's general types and discuss some of the issues that must appear when they include them in generic Java type systems.

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

New Post(0)