Generics in Java

Source: Internet
Author: User

Let's take a look at the following 2 pieces of code, and then draw our generics further.

   Public Static void Main (string[] args) {        new  ArrayList ();        List.add ("123");        List.add (456);         = list.iterator ();          while (It.hasnext ()) {            //  Error:integer cannot is cast to string            string next = (String) ();          }    }

The above code, there will be conversion anomalies, but the compilation is no problem, in the output conversion when there is an exception, there is an impulse to the collection of the type of one? The following is a very normal method of summing, however we can only find the sum of the parameters of type Integer.

 Public integer Add (integer a,integer b) {    return a + b;}

For a collection, if we can specify the type of data in the collection at compile time, so that there is no error in the type conversion, again, in the following summation method, we can only find the sum of the parameters of type Integer, can we do the general sum? With generics, you can do it.

The concept of generics is "data type parameterization" because we are not sure what types can be specified in the collection, is it an Integer or a String? What are the data types of the arguments in the summation method, Float or Double? Then we can use generics to parameterize this data type.

Generics are applied with generic interfaces, generic classes, and generic methods. The following defines a generic class and demonstrates how to use it.

 Public classBox <T> {    //T is a shorthand for type, representing any type, and note the class, not the base data type. //It can also be replaced by other words, which is just a representation. T T;  PublicT Gett () {returnT; }     Public voidsett (t t) { This. T =T; }    //in the following application, we can replace T with any type we want     Public Static voidMain (string[] args) {Box<Integer> IBox =NewBox<integer>(); Box<Double> dbox =NewBox<double>(); //The JDK1.7 and above versions can be written using "type inference". Box<string> Stringbox =NewBox<>(); }}

The definition of a generic method requires only adding < T > to the Declaration of the method, or adding a set of generic <k,v>.

 Public classUtil { Public Static<k, v>BooleanCompare (Pair<k, v> p1, pair<k, v>p2) {        returnP1.getkey (). Equals (P2.getkey ()) &&p1.getvalue (). Equals (P2.getvalue ()); }} Public classPair<k, v> {    PrivateK Key; PrivateV value;  PublicPair (K key, V value) { This. Key =key;  This. Value =value; }     Public voidSetkey (K key) { This. Key =key;}  Public voidSetValue (V value) { This. Value =value;}  PublicK GetKey () {returnkey;}  PublicV GetValue () {returnvalue;}}

We can call a generic method like this.

New Pair<> (1, "Apple"); PairNew pair<> (2, "pear"); Boolean same = Util.<integer, String>compare (P1, p2);

The above is simply the application, then we will encounter what situation, the following look at the question about wildcards, in order to demonstrate the effect, I wrote a practical use of the method.


 Public Static void printsize (list<object> List) {        System.out.println (list.size ());    }      Public Static void Main (string[] args) {        Listnew arraylist<>();        ListNew arraylist<>();         // error    }

As we know above, using generics in a collection makes the program more secure and readable, so the Java specification recommends that we use generics, so let's take a look at the above scenario, how do I represent receiving all the List collections with generics. It is not possible to use list<object> above. Why not? How do we receive the parameters?

First to explain why not, first look at the simple difference.

New Integer (1); ArrayListNew//  error

Obj can be assigned successfully because polymorphism (which is the principle of the Richter substitution), the parent's reference points to the entity of the subclass, and the following error, the intuitive reason,arraylist<object> is not arraylist<integer> The parent class. Well, no, it's not, why not, it's because the normal generics in Java are immutable, and of course we can make them change. (invariant, covariant and contravariant concepts can be self-Baidu)


So I just want the method to receive all the collections with generics. Now that the wildcard appears, we can use list<?> to represent all of the generic lists, which means you can use list<?> to point to all of the list with generics.

 Public Static void printsize (list<?> List) {        System.out.println (list.size ());    }      Public Static void Main (string[] args) {        Listnew arraylist<>();        ListNew arraylist<>();        PrintSize (list1);        PrintSize (LIST2);    }

Well, again, in Java we can use the parent class's reference to the object of the subclass, whereas in generics,list<object> and list<integer> do not form an inheritance because generics are immutable. And yet we want to represent all the collections with generics, and that's when it happens? A wildcard character. We can use list<?> to refer to other lists with generics.

The actual effect is this.

New // Error New Arraylist<integer> ();

Well, now that the upgrade is required, I hope my List collection does not point to anything, let's take a look at some of the restrictions on how to represent the modifier.

//General ModifiersList<?> List1 =NewArraylist<integer>();//< extends t> can be used to represent subclasses of T and Tlist<?extendsNumber> List2 =NewArraylist<number>(); List<?extendsNumber> List3 =NewArraylist<integer>(); List<?extendsNumber> List4 =NewArraylist<string> ();//Error//< Super t> can be used to represent the parent class of T and Tlist<?SuperNumber> LIST5 =NewArraylist<number>(); List<?SuperNumber> List6 =NewArraylist<object>(); List<?SuperNumber> list7 =NewArraylist<integer> ();//Error

for the above <? Extends number> and <? How does super number> choose? First, the conclusion: "Producer extends,consumer Super" abbreviation PECS principle.

"Producer Extends" – If you need a read-only List, use it to produce T, then use <? Extends T >.

"Consumer Super" – If you need a write-only List, use it to consume T, then use <? Super T >.

If you need to read and write at the same time, then we can't use wildcards.

extends New Arraylist<number>(); Listextendsnew arraylist<integer>(); Listextendsnew arraylist<double>(); // no matter what the specific instantiation is, we get the element after the parent class number // so is produce, can get get a lot of T Number number = List.get (0); List.add (new//  error

Since all three of these instantiation methods are allowed, if I want to get an instance from list now, the instance that the list points to may be a collection of Animal, Dog, or Cat instances. So the returned value is uniform to its parent class. There is a problem with the add value, I am not sure which element is added, except NULL, so it will be an error.

The same idea again to see <? Super T > operation.

list<?Superinteger> list =NewArraylist<integer>(); List<?Superinteger> list =NewArraylist<number>(); List<?Superinteger> list =NewArraylist<object>();//different instantiation, the value returned after we get element is indeterminate//or Integer, number, Object ...List.get (0); //When adding data, you can determine what is added .//so super corresponds to write-only cases where consume TList.add (NewInteger (1));

About generics also illustrates that generics are a technique that is applied at compile time and that there is no generics during runtime. The reason for this is the generic type erasure. Why do you say that, we can look at an example

 Public Static voidMain (string[] args) {List<Integer> list =NewArraylist<integer>(); List.add (55W); List.add ("123");//Compile Error    }    -------------------------------------------------- Public Static voidMain (string[] args) {List<String> L1 =NewArraylist<string>(); List<Integer> L2 =NewArraylist<integer>();        System.out.println (L1.getclass ());      System.out.println (L1.getclass (). Equals (L2.getclass ())); }     //class Java.util.ArrayList//true

The reason for this is that the concept of generics in Java is intended to cause it to only act on the code compilation stage, and when the generic results are correctly inspected during compilation, the relevant information of generics is erased, that is, the class file after the successful compilation does not contain any generic information. Generic information is not entered into the run-time phase.

After the type erasure, if there is a corresponding type variable in the code, following the "reserved upper bound" rule, the corresponding T will be replaced with the specific class.

<? >----> Object

<? Extends T >----> t

<? Super T >-----> Object

As a point of note, creating a generic array directly in Java is not allowed.

list<integer>[] Lists =NewArraylist<integer> ();//ErrorSee the demo code below//Not really allowed.list<string>[] LSA =Newlist<string>[10];//1Object o =lsa;object[] OA=(object[]) o; List<Integer> Li =NewArraylist<integer>(); Li.add (NewInteger (3));//unsound, but passes run time store checkOA[1] =Li;//run-time error:classcastexception.String s = lsa[1].get (0);

If the existence of a generic array is allowed (1th code compiles through), then the code in the 2nd place will report ClassCastException, because Lsa[1] is list<integer>. Java designers, in line with the principle of first guarantee type safety (type-safety), do not allow the existence of generic arrays, allowing the compile time to check for such errors.

Solution Solutions

New list<?>[10];                // 1 Object o == (object[]) o; ListNew arraylist<integer>(); Li.add (new Integer (3)); // Correct. OA[1] = li; // Run time error, but cast is explicit. string s = (string) lsa[1].get (0);              // 2

In the 1th place, with? Replaces the determined parameter type. Based on the definition of the wildcard character and the retention upper bound principle of Java type Erasure, the 2 lsa[1].get (0) will be Object, so the programmer needs to do an explicit type conversion.

There is also a reflection of the way to achieve, using Java.util.reflect.Array, you can not use wildcard characters, and achieve the effect of the generic array.

List<string>[] LSA = (list<string>[]) array.newinstance (ArrayList.  Class, 4);     // 1 Object o == (object[]) o; ListNew arraylist<integer>(); Li.add (new Integer (3)); // Correct. OA[1] = li; // Run time error, but cast is explicit. String s = lsa[1].get (0);                                  2

As you can see, a generic array is generated using array.newinstance (), no wildcard characters are used, and there is no explicit type conversion at 2nd, but there is still an explicit type conversion at the 1th place.

So in order to use a generic array, the programmer must perform a display of type conversions, that is, the problem of type checking is given to the programmer from the compiler. However, generics are designed to help us check the data types. You say contradiction is not contradictory!





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: and provide relevant evidence. A staff member will contact you within 5 working days.

Tags Index: