Java generics--go

Source: Internet
Author: User
Tags class definition map class naming convention

Generics (Generic type or generics) are an extension of the Java language type system to support the creation of classes that can be parameterized by type. You can think of a type parameter as a placeholder for the type that you specify when you use a parameterized type, as if the form parameter of the method is a placeholder for the value passed at run time.
You can see the motivations for generics in the collection Framework (Collection framework). For example, the map class allows you to add an object of any class to a map, even if the most common scenario is to save an object of a particular type (such as a string) in a given map (map).
Because Map.get () is defined to return an object, it is generally necessary to cast the result of Map.get () to the desired type, as shown in the following code:



Map m = new HashMap ();

M.put ("Key", "Blarg");

string s = (string) m.get ("key");



For the program to compile, you must cast the result of the Get () to string, and you want the result to be really a string. But it is possible that someone has saved something that is not a string in the map, so the above code will throw classcastexception.
Ideally, you might come to the view that M is a map that maps a string key to a string value. This allows you to eliminate coercion of type conversions in your code and to obtain an additional type-checking layer that prevents someone from saving the key or value of the wrong type in the collection. This is the work that generics do.
Benefits of Generics
The introduction of generics in the Java language is a large feature enhancement. Not only has the language, type system, and compiler changed significantly to support generics, but class libraries have also been overhauled, so many important classes, such as the collection framework, have become generics. This brings a number of benefits:
· Type safety. The primary goal of generics is to improve the type-safety of Java programs. By knowing the type limits of variables defined using generics, the compiler can validate the type hypothesis at a much higher level. Without generics, these assumptions exist only in the programmer's mind (or, if you're lucky, in code comments).
A popular technique in Java programs is to define a collection in which its elements or keys are public types, such as "string List" or "string-to-string mapping". By capturing this additional type information in a variable declaration, generics allow the compiler to enforce these additional type constraints. Type errors can now be captured at compile time, rather than being shown as classcastexception at run time. Moving type checking from runtime to compile can help you find errors more easily and improve the reliability of your program.
· Eliminates forced type conversions. A side benefit of generics is the elimination of many coercion type conversions in the source code. This makes the code more readable and reduces the chance of error.
Although reducing coercion type conversions can reduce the amount of verbose code that uses generic classes, declaring generic variables can lead to a corresponding wordy. Compare the following two code examples.
The code does not use generics:



List li = new ArrayList ();

Li.put (New Integer (3));

Integer i = (integer) li.get (0);



The code uses generics:



list<integer> li = new arraylist<integer> ();

Li.put (New Integer (3));

Integer i = li.get (0);



Using a generic variable once in a simple program does not reduce the amount of wordy. However, for large programs that use generic variables more than once, you can accumulate them to reduce the amount of wordy.
· Potential performance gains. Generics are possible for larger optimizations. In the initial implementation of generics, the compiler enforces type conversions (without generics, programmers specify these coercion type conversions) into the generated bytecode. But the fact that more type information is available for compilers is possible for future versions of JVM optimizations.
Because of the way generics are implemented, generics are supported (almost) without the need for JVM or class file changes. All work is done in the compiler, and the compiler generates code that is similar to what is written when there is no generics (and coercion of type conversions), just to be more secure type.
Examples of generic usage
Many of the best examples of generics come from the collection framework, because generics let you specify type constraints on the elements that are saved in the collection. Consider this example of using the map class, which involves a certain degree of optimization, that is, the result returned by Map.get () will indeed be a string:



Map m = new HashMap ();

M.put ("Key", "Blarg");

string s = (string) m.get ("key");



If someone has placed something else in the map that is not a string, the code above will throw classcastexception. Generics allow you to express a type constraint where M is a map that maps a string key to a string value. This eliminates the coercion of type conversions in your code, while obtaining an additional type-checking layer that prevents someone from saving a key or value of the wrong type in the collection.
The following code example shows part of the definition of the map interface in the collection framework in JDK 5.0:



Public interface Map<k, v> {

public void put (K key, V value);

Public V get (K key);

}



Note the two additional objects of the interface:

* Type parameters K and V at the class level specification, represents a placeholder for the type specified when declaring a variable of type Map.
* The K and V are used in the method signatures of Get (), put () and other methods.

To gain the benefits of using generics, you must provide specific values for K and V when you define or instantiate a variable of type map. Do this in a relatively straightforward way:



Map<string, string> m = new hashmap<string, string> ();

M.put ("Key", "Blarg");

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



When using a generic version of map, you no longer need to cast the result of Map.get () to string, because the compiler knows that get () will return a string.
There is no reduction in keyboard entry in versions that use generics; in fact, more typing is needed than a version that uses forced type conversions. The use of generics simply brings additional type-safety. Because the compiler knows more about the types of keys and values you will put into a map, type checking moves from execution to compile time, which increases reliability and accelerates development.
Backwards compatible
One important goal of introducing generics in the Java language is to maintain backward compatibility. Although many of the classes in the standard class library of JDK 5.0, such as the collection framework, are already generic, existing code that uses collection classes such as HashMap and ArrayList will continue to work in JDK 5.0 unmodified. Of course, existing code that does not take advantage of generics will not win the type-safety benefits of generics.
Type parameter
When defining a generic class or declaring a variable of a generic class, use angle brackets to specify the form type parameter. The relationship between the formal type parameter and the actual type parameter is similar to the relationship between the formal method parameter and the actual method parameter, except that the type parameter represents the type, not the value.
The type parameters in a generic class can be used almost anywhere a class name can be used. For example, here is an excerpt of the definition of the Java.util.Map interface:



Public interface Map<k, v> {

public void put (K key, V value);

Public V get (K key);

}



The map interface is parameterized by two types, which are the key type K and the value type V. Methods that will accept or return object (without generics) now use K or V in their method signatures, indicating that additional type constraints are located under the map's specification.
When declaring or instantiating a generic object, you must specify the value of the type parameter:



map<string, string> map = new hashmap<string, string> ();



Note that in this example, you must specify two type parameters. One time is when you declare the type of a variable map, and the other is when you choose to parameterize the HashMap class so that one instance of the correct type can be instantiated.
When the compiler encounters a variable of type map<string, string>, it knows that K and V are now bound to string, so it knows that calling Map.get () on such a variable will get the String type.
In addition to exception types, enumerations, or anonymous inner classes, any class can have type parameters.
Named type parameters
The recommended naming convention is to use an uppercase single letter name as the type parameter. This differs from the C + + conventions (see Appendix A: Comparisons to C + + templates) and reflects the assumption that most generic classes will have a small number of type parameters. For common generic patterns, the recommended name is:

* k--key, such as the mapped key.
* v--values, such as the contents of list and Set, or the values in a Map.
* e--Exception class.
* t--generic type.

Generics are not covariant
A common source of confusion about generics is to assume that they are covariant like arrays. In fact, they are not co-variable. List<object> is not a parent type of list<string>.
If a expands B, then the array of a is also an array of B, and can be used completely where b[] is needed a[]:



integer[] Intarray = new INTEGER[10];

number[] Numberarray = Intarray;



The above code is valid because an integer is a number, and an integer array is an array of number. But not for generics. The following code is not valid:



list<integer> intlist = new arraylist<integer> ();

list<number> numberlist = intlist; Invalid



Initially, most Java programmers find this lack of covariance annoying, or even "bad", but there is a good reason for this broken. If you can assign list<integer> to List<number&gt, the following code violates the type-safety that generics should provide:



list<integer> intlist = new arraylist<integer> ();

list<number> numberlist = intlist; Invalid

Numberlist.add (New Float (3.1415));



Because Intlist and numberlist are both aliases, if allowed, the above code will let you put things that are not integers into the intlist. However, as the next screen will see, you have a more flexible way to define generics.
Package com.ibm.course.generics;
Import java.util.ArrayList;
Import java.util.List;
public class Genericsexample {
public static void Main (string[] args) {
integer[] integer = new integer[5];
number[] Number = integer;
System.out.println (number[0]);//null
Number[0] = new Float (7.65);
System.out.println (Number[0]);
System.out.println (Integer[0]);
list<integer> list = new arraylist<integer> ();
Type Mismatch:cannot convert from list<integer> to list<number>
list<number> listobj = list;
}
}
list<number> listobj = list; causes compilation error: Type Mismatch:cannot convert from list<integer> to list<number>
and System.out.println (Number[0]); System.out.println (integer[0]); causes a run-time exception:
Exception in thread "main" java.lang.ArrayStoreException:java.lang.Float
At Com.ibm.course.generics.GenericsExample.main (genericsexample.java:15)

Type wildcard character
Suppose you have this method:

void Printlist (List l) {

for (Object o:l)

System.out.println (o);

}



The above code is compiled on JDK 5.0, but if you try to invoke it with list<integer>, you get a warning. The warning occurs because you pass generics (list<integer>) to a method that only promises to treat it as a List (the so-called primitive type), which destroys type-safety using generics.
What if you try to write a method like this?



void Printlist (list<object> l) {

for (Object o:l)

System.out.println (o);

}



It still does not compile because a list<integer> is not a list<object> (as the previous screen generics are not learned in covariant). This is really annoying--now your generic version is no more useful than a normal non-generic version!
The solution is to use a type wildcard character:



void Printlist (list<?> l) {

for (Object o:l)

System.out.println (o);

}



The question mark in the code above is a type wildcard character. It is read as a "question mark". List<?> is the parent type of any generic List, so you can completely add list<object>, list<integer>, or list<list<list<flutzpah> >> passed to Printlist ().
Package com.ibm.course.generics;
Import java.util.ArrayList;
Import java.util.List;
public class Genericexample {
public static void Main (string[] args) {
list<integer> Integer = new arraylist<integer> ();
Integer.add (new Integer (0));
Integer.add (New Integer (1));
list<string> str = new arraylist<string> ();
Str.add (New String ("Hello"));
Str.add (New String ("World"));
List<?> Li=integer;
LI=STR;
Printlist (integer);
Printlist (str);
}
public static void Printlist (list<?> l) {
for (Object o:l) {
System.out.println (o);
}
}
}
The above example program does not have a warning or compile error.
The role of a type wildcard
The type wildcard is introduced in the previous screen type wildcard, which allows you to declare variables of type list<?>. What can you do with such a list? It is convenient to retrieve elements from, but cannot add elements (you can add null). The reason is not that the compiler knows which methods modify the list which methods do not modify the list, but rather (most) change the method to require more type information than the non-changing method. The following code works very well:



list<integer> li = new arraylist<integer> ();

Li.add (New Integer (42));

list<?> lu = li;

System.out.println (lu.get (0));



Why does the code work? For Lu, the compiler does not know the value of the list's type parameter at all. But the compiler is smarter, and it can do some type of reasoning. In this case, it infers that the unknown type parameter must extend the object. (This particular inference is not much of a leap, but the compiler can make some very admirable type inference, as you'll see later (in the bottom-level details section). So it lets you call List.get () and infer that the return type is object.
On the other hand, the following code does not work:



list<integer> li = new arraylist<integer> ();

Li.add (New Integer (42));

list<?> lu = li;

Lu.add (New Integer (43)); Error



In this case, for LU, the compiler cannot make sufficiently rigorous inferences about the type parameters of the list to determine that passing an integer to List.add () is type-safe. So the compiler will not allow you to do so.
In case you still think the compiler knows which methods change the contents of the list and what does not change the contents of the list, be aware that the following code will work because it does not depend on any information that the compiler must know about the type parameters of the LU:



list<integer> li = new arraylist<integer> ();

Li.add (New Integer (42));

list<?> lu = li;

Lu.clear ();

Generic methods
(In the Type parameters section) you have seen that you can generics a class by adding a formal type parameter list to the definition of the class. Methods can also be generalized, regardless of whether the class they are defined in is generic.
A generic class enforces type constraints among multiple method signatures. In list<v>, the type parameter V appears in the signatures of methods such as Get (), add (), contains (), and so on. When creating a variable of type map<k, v>, you declare a type constraint between the methods. The value you pass to add () will be the same as the type of the value returned by Get ().
Similarly, it is common to declare a generic method because you want to declare a type constraint between multiple parameters of the method. For example, the IfThenElse () method in the following code, depending on the Boolean value of its first argument, returns the second or third parameter:



Public <T> T IfThenElse (Boolean B, t first, T second) {

Return b? First:second;

}



Note that you can call IfThenElse () without having to explicitly tell the compiler what value you want t. The compiler does not have to explicitly be told what value T will have; it knows only that these values must be the same. The compiler allows you to invoke the following code because the compiler can use type inference to infer that a string that replaces T satisfies all type constraints:



String s = ifthenelse (b, "A", "B");



Similarly, you can call:



Integer i = IfThenElse (b, new Integer (1), new Integer (2));



However, the compiler does not allow the following code, because no type will satisfy the required type constraint:



String s = ifthenelse (b, "PI", New Float (3.14));



Why do you choose to use a generic method instead of adding type T to the class definition? (at least) there are two things that you should do:

* Class type parameters cannot be used in this case when the generic method is static.
* When a type constraint on T is really local to a method, this means that no constraint of the same type T is used in another method signature of the same class. By making the type parameters of a generic method local to the method, you can simplify the signature of the enclosing type.

Restricted types
In the example of a previous-screen generic method, the type parameter V is an unconstrained or unrestricted type. Sometimes you need to specify additional constraints on the type parameter when the type parameter is not fully specified.
Consider the example matrix class, which uses the type parameter V, which is limited by the number class:



public class Matrix<v extends Number> {...}



The compiler allows you to create a variable of type matrix<integer> or matrix<float>, but an error occurs if you try to define a variable of type matrix<string>. The type parameter v is judged to be limited by number. When there is no type restriction, assume that the type parameter is restricted by object. This is why the example in the previous screen generic method allows List.get () to return an object when the list<?> is raised, even if the compiler does not know the type of the type parameter v.

Java generics--go

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.