Java Generics Summary

Source: Internet
Author: User
Tags addall

I. Why do we need generics?

First, let's look at the following short code:

 PackageCorejava.day_5;ImportJava.util.ArrayList;ImportJava.util.List;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest {     Public Static void Main(string[] args) {List List =NewArrayList (); List.add ("Justdoit"); List.add ("Core"); List.add ( -); for(inti =0; I < list.size (); i++) {String name = (string) list.get (i);//1System.out.println ("Name:"+ name); }    }}

We define a collection of list types, first adding a value of two string types to it, and then adding an integer type. This is entirely permissible because the default type of the list at this time is type object. In the subsequent loop, it is easy to get an error similar to//1 in that it has been added to the list with an integer value or other encoding reason. Because the compile phase is normal, a "java.lang.ClassCastException" exception occurs at run time. Therefore, this kind of error encoding process is not easy to find.

In the coding process as above, we found that there are two main problems:

1. When we put an object into the collection, the collection does not remember the type of the object, and when the object is removed from the collection again, the compilation type of the object is changed to the object type, but its run-time type is still its own type.

2. As a result, it is necessary to//1 the collection element into the specific target type, and the "java.lang.ClassCastException" exception can easily occur.

So is there any way that the collection can remember the types of elements within the collection and be able to achieve the "java.lang.ClassCastException" exception when the runtime does not have a problem at compile time? The answer is to use generics.

Two. What is a generic type?

Generic, which is the parameterized type. When referring to a parameter, it is most familiar to define the method when the physical parameter is called and then pass the argument when calling this method. So how do parameterized types understand? As the name implies, the type is parameterized by the original specific type, similar to the variable parameter in the method, when the type is also defined as a Parameter form (which can be called a type parameter), and then the specific type (type argument) is passed in when using/calling.

This is a bit complicated, so let's take a look at the example above that uses generic notation:

 PackageCorejava.day_5;ImportJava.util.ArrayList;ImportJava.util.List;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_2 {     Public Static void Main(string[] args) {/* List List = new ArrayList ();        List.add ("Justdoit");        List.add ("core");        List.add (100); */list<string> list =NewArraylist<string> (); List.add ("Qqyumidi"); List.add ("Corn");//list.add (100); 1 Hint compilation error         for(inti =0; I < list.size (); i++) {String name = List.get (i);//2System.out.println ("Name:"+ name); }    }}

After a generic notation, a compilation error occurs when you want to add an object of type integer at//1, through list< String>, which directly qualifies only elements of type String in the list collection, so there is no need to force type conversions at//2, because at this point , the collection remembers the type information of the element, and the compiler has been able to confirm that it is of type string.

In conjunction with the generic definition above, we know that in list< string>, String is a type argument, that is, the corresponding list interface must contain a type parameter. The return result of the Get () method is also directly the parameter type (that is, the corresponding incoming type argument). Here's a look at the specific definition of the list interface:

 Public  interface List<e> extends Collection<e> {     intSize ();BooleanIsEmpty ();BooleanContains (Object o);    Iterator<e> Iterator ();    Object[] ToArray (); <T> t[] ToArray (t[] a);BooleanAdd (e e);BooleanRemove (Object o);BooleanContainsall (collection<?> c);BooleanAddAll (collection<? extends e> c);BooleanAddAll (int Index, collection<? extends e> c);BooleanRemoveAll (collection<?> c);BooleanRetainall (collection<?> c);voidClear ();BooleanEquals (Object O);intHashcode (); E Get (int Index); E Set (int Index, E Element);voidAddint Index, E Element); E Remove (int Index);intIndexOf (Object o);intLastIndexOf (Object o);    Listiterator<e> Listiterator (); Listiterator<e> Listiterator (int Index); List<e> sublist (intFromIndex,intToindex);}

We can see that after the generic definition in the list interface, E in,< e> represents a type parameter and can receive specific type arguments, and in this interface definition, wherever e occurs, the same type arguments are accepted from outside.

Naturally, ArrayList as the implementation class for the list interface, which is defined in the following form:

 Public  class ArrayList<e> extends abstractlist<e> C8>implements List<E;, randomaccess, cloneable, Java . io. Serializable {     Public BooleanAdd (e e) {ensurecapacityinternal (size +1);//increments modcount!!elementdata[size++] = e;return true; } PublicE Get (int Index) {Rangecheck (Index); Checkforcomodification ();returnArrayList. This. Elementdata (offset +Index); }//... Omit the other specific definition process}

Thus, we can see from the source code The reason why//1 is added to the integer type Object compile error, and the type of Get () at//2 is directly the type of string.

Three. Custom generic interfaces, generic classes, and generic methods

From the above, we have already understood the specific operation process of generics. Also know that interfaces, classes, and methods can also be defined using generics and used accordingly. Yes, it can be divided into generic interfaces, generic classes, and generic methods when used in concrete form.

Custom generic interfaces, generic classes, and generic methods are similar to the list and ArrayList in the Java source code above. Below, let's look at one of the simplest generic class and method definitions:

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_3 {     Public Static void Main(string[] args) {box<string> name =NewBox<string> ("Core"); System.out.println ("Name:"+ Name.getdata ()); }}class box<t> {PrivateT data; Public Box() {    } Public Box(T data) { This. data = data; } PublicTGetData() {returnData }}

In the definition of generic interfaces, generic classes, and generic methods, our common parameters, such as T, E, K, V, and so on, are commonly used to denote a generic parameter, because of the type arguments that are passed in when receiving from external use. So for different incoming type arguments, is the type of the corresponding object instance generated the same?

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_4 {     Public Static void Main(string[] args) {box<string> name =NewBox<string> ("Core"); Box<integer> age =NewBox<integer> (712); System.out.println ("Name class:"+ Name.getclass ());//CoreJava.day_5.BoxSystem.out.println ("Age class:"+ Age.getclass ());//CoreJava.day_5.BoxSystem.out.println (name.getclass () = = Age.getclass ());//True}}

As a result, we find that when using a generic class, although different generic arguments are passed in, but there is no real sense of generating different types, the generic classes passing in different generic arguments have only one in memory, that is, the original basic type (box in this case), of course, Logically, we can understand a number of different generic types.

The reason for this is that the concept of generics in Java is intended to be a function of the code compilation phase, during the compilation process, for the correct validation of generic results, the generic information will be erased, that is, the successful compilation of the class file does not contain any generic information. Generic information is not entered into the run-time phase.

This is summed up in a sentence: a generic type is logically viewed as multiple different types, and is actually the same basic type.

Four. Type wildcard characters

Then the above conclusion, we know that box and box are actually box types, and now need to continue to explore a problem, so logically, like box and box can be considered as a parent-child relationship of the generic type?

To figure this out, let's look at the following example:

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_6 {     Public Static void Main(string[] args) {box<number> name =NewBox<number> ( About); Box<integer> age =NewBox<integer> (712); GetData (name);//the method GetData (box<number>) in the type Generictest is        //not applicable for the arguments (box<integer>)GetData (age);//1} Public Static void GetData(box<number> data) {System.out.println ("Data:"+ Data.getdata ()); }}

We found that there was an error message in the code//1: The Method GetData (box< number>) in the T ype Generictest was not applicable for the arguments (box< integer>). Obviously, by prompting the message, we know that box is logically not considered a box< integer> parent class. So, what is the reason?

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_5 {     Public Static void Main(string[] args) {Box<integer> A =NewBox<integer> (712); Box<number> B = A;//1Box<float> f =NewBox<float> (3.14f); B.setdata (f);//2} Public Static void GetData(box<number> data) {System.out.println ("Data:"+ Data.getdata ()); }}class box<t> {PrivateT data; Public Box() {    } Public Box(T data)    {setData (data); } PublicTGetData() {returnData } Public void SetData(T data) { This. data = data; }}

In this case, it is clear that the//1 and//2 are definitely wrong. Here we can use the contradiction to illustrate.

Assuming that box< number> can logically be regarded as the parent of box< integer>, then there will be no error in//1 and//2, so the question is, what type is it when the data is fetched by the GetData () method? An Integer? Float? or number? And because the order is not controllable in the programming process, it is necessary to make the type judgment, and to make the forced type conversion. Obviously, this contradicts the concept of generics, so logically box< number> cannot be regarded as the parent class of box< integer>.

Well, let's go back and look at the first example in "type wildcard", we know the underlying reason for its specific error message. So how to solve it? The headquarters can define a new function again. This is obviously a violation of the polymorphic concept in Java, so we need a reference type that can be logically used to represent the parent class of box< integer> and box< number>, and thus the type wildcard comes into being.

Type wildcard characters are generally used? Instead of a concrete type argument. Note that here is the type argument, not the type parameter! and box

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_7 {     Public Static void Main(string[] args) {box<string> name =NewBox<string> ("Core"); Box<integer> age =NewBox<integer> (712); box<number> number =NewBox<number> (314);        GetData (name);        GetData (age);    GetData (number); } Public Static void GetData(box<?> data) {System.out.println ("Data:"+ Data.getdata ()); }}

Sometimes we may also hear the type wildcard upper bound and the type wildcard lower bound . What is the specific one?

In the example above, if you need to define a method that functions like GetData (), there are further restrictions on type arguments: only the number class and its subclasses. At this point, you need to use the maximum type wildcard character.

 PackageCorejava.day_5;/** * @author li Zhi * @date 2016/12/15 * * Public  class generictest_8 {     Public Static void Main(string[] args) {box<string> name =NewBox<string> ("Core"); Box<integer> age =NewBox<integer> (712); box<number> number =NewBox<number> (314);        GetData (name);        GetData (age); GetData (number);//getuppernumberdata (name);//1Getuppernumberdata (age);//2Getuppernumberdata (number);//3} Public Static void GetData(box<?> data) {System.out.println ("Data:"+ Data.getdata ()); } Public Static void Getuppernumberdata(box<? extends number> data) {System.out.println ("Data:"+ Data.getdata ()); }}

At this point, it is clear that the call at Code//1 will appear with an error, and//2//3 is called normally.

type wildcard upper bound by shape as box<? extends number> form definition, corresponding to the type wildcard lower limit is box<? Super number> form, which means the same as the type wildcard upper limit is exactly the opposite , There is not much elaboration here.

Five. Outside the speech

The examples in this article are intended to illustrate some of the ideas in generics and are simply cited, and do not necessarily have practical usability. In addition, a reference to generics, I believe that the most used is in the collection, in fact, in the actual programming process, you can use generics to simplify development, and can be good to ensure the quality of the code. It is also important to note that there is no so-called generic array in Java.

For generics, the main thing is to understand the thought and the purpose behind it.

Java Generics Summary

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.