I. The concept of generics (why generics are needed)?
First, let's look at the following short code:
1 public class Generictest {2 3 public static void Main (string[] args) {4 list list = new ArrayList (); 5
list.add ("Qqyumidi"); 6 list.add ("corn"); 7 List.add (+); 8 9 for (int i = 0; i < list.size (); i++) {ten String name = ( String) List.get (i); 111 System.out.println ("Name:" + name); }13 }14}
Defines a collection of list types, with a value of two string types added to it, followed by 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.
Looks a bit complicated, first we look at the above example using generic notation.
1 public class Generictest {2 3 public static void Main (string[] args) {4/ * 5 List list = new ArrayList (); 6 List.add ("Qqyumidi"), 7 list.add ("corn"), 8 List.add (+), 9 */10 one list<string> list = New Arraylist<string> (), list.add ("Qqyumidi"), list.add ("corn"), //list.add (+) ; 1 hint compilation error for (int i = 0; i < list.size (); i++) {n String name = List.get (i);//218 System . Out.println ("Name:" + name); }20 }21}
After using the generic notation, a compilation error occurs when you want to add an object of type integer at//1, by List<string>, directly qualifying 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:
1 public Interface list<e> extends collection<e> {2 3 int size (); 4 5 Boolean IsEmpty (); 6 7 Boolean contains (Object O); 8 9 iterator<e> Iterator (); object[] ToArray (); <T> t[] ToArray (t[] a); Boolea n Add (e e);. Boolean remove (Object o); Containsall (Collection<?> C), Boolean Addal L (collection< extends e> c); boolean addall (int index, COLLECTION<? extends e> c); RemoveAll (collection<?> c); A Boolean retainall (collection<?> c) and a void clear (); Boole An Equals (Object o); int hashcode (); e get (int index), and set (int index, e element); ID Add (int index, e element), e remove (int index), indexOf int (Object o), lastIndexOf Int (objec t o); listiterator<e> listiterator (); listiterator<e> listiterator (int index); 50 51list<e> sublist (int fromIndex, int toindex); 52}
As we can see, after the generic definition in the list interface, the E in,<e> represents the type parameter and can receive the specific type argument, and in this interface definition, where E is present, the same type argument that is accepted from the external.
Naturally, ArrayList as the implementation class for the list interface, which is defined in the following form:
1 public class Arraylist<e> extends abstractlist<e> 2 implements List<e>, Randomaccess, Cloneable, java.io.Serializable {3 4 public boolean add (E e) {5 ensurecapacityinternal (size + 1); Increments modcount!! 6 elementdata[size++] = e; 7 return true; 8 } 9 public e get (int index) { Rangecheck ( Index), checkforcomodification (), return ArrayList.this.elementData (offset + index), }15 /... Omit other specific definition procedures 17 18}
From the source code point of view, we understand why an integer type Object compilation error has been added to the//1, and the type of Get () at//2 is directly the string type.
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:
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<string> name = new Box<string> ("corn"); 6 System.out.println ("Name:" + name.getdata ()); 7 } 8 9}10 class Box<t> { data;14 public Box () { }18 Box (T data) { This.data = data;21 }22-Public T GetData () { return data;25}26 27}
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?
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<string> name = new Box<string> ("corn"); 6 box<integer> age = new box<integer> (712); 7 8 System.out.println ("name class:" + Name.getclass ()); Com.qqyumidi.Box 9 System.out.println ("Age class:" + Age.getclass ()); com.qqyumidi.Box10 System.out.println (name.getclass () = = Age.getclass ()); True11 }13 14}
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<number> and box<integer> are actually Box types, and now we need to continue to explore a problem, then logically, similar to box<number> and box< Can integer> be considered a generic type with a parent-child relationship?
To figure this out, let's look at the following example:
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<number> name = new Box<number> (99); 6 box<integer> age = new box<integer> (712); 7 8 getData (name); 9 //the method GetData (box<number>) in the type generictest is one //not applicable for the arguments (box<integer>) 12
getdata (age); 113 }15 public static void GetData (box<number> data) { System.out.println ("Data: "+ data.getdata ()); }19 20}
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 information, we know that box<number> is logically not considered a box<integer> parent class. So what is the reason?
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<integer> a = new B Ox<integer> (712); 6 box<number> B = A; 1 7 box<float> f = new box<float> (3.14f); 8 b.setdata (f); 2 9 }11 public static void GetData (box<number> data) { System.out.println ("Data:" + DATA.G Etdata ()) }15}17 class Box<t> { private T data;21 public Box () { }25 26
public Box (t data) { setData (data),}29-Public T getData () { return data;32 }33 Public void SetData (T data) { This.data = data;36 }37 38}
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 Box<integer> 's parent class.
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 both box<integer> and Box<number> 's parent class, and thus the type wildcard comes into being.
type wildcard characters are generally used instead of specific type arguments. Note that here is the type argument, not the type parameter! And box<?> is logically box<integer>, Box<number; The parent class for all box< concrete type arguments >. As a result, we can still define generic methods to accomplish such requirements.
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<string> name = new Box<string> ("corn"); 6 box<integer> age = new box<integer> (712); 7 box<number> number = new Box<number> (314) ; 8 9 getData (name), GetData (age), getData (number),}13, public static void GetData (box<?> data) { System.out.println ("Data:" + data.getdata ()); }17 18}
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.
1 public class Generictest {2 3 public static void Main (string[] args) {4 5 box<string> name = new Box<string> ("corn"); 6 box<integer> age = new box<integer> (712); 7 box<number> number = new Box<number> (314) ; 8 9 getData (name), GetData (age), GetData (number ), //getuppernumberdata (name ); Getuppernumberdata (age); 215 getuppernumberdata (number);// }17 public static void GetData (box<?> data) { SYSTEM.OUT.PRINTLN ("Data:" + data.getdata ()), }21 public static void Getuppernumberdata (box< ? Extends number> data) { System.out.println ("Data:" + data.getdata ()); }25 26}
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 character upper bound by shape such as box<? extends number> form definition, corresponding to the type of wildcard character lower limit is box<? super number> form, which means the opposite of the type wildcard upper bound , not too 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.
Blog Original: http://www.cnblogs.com/lwbqqyumidi/p/3837629.html
Turn!! Java generic Concepts (generic classes, interfaces, methods)