Technorati Tag: java, generic, generic
Java generic applications are one of the core foundations of java and are introduced from java 5. If you have used java Collection before, you have already been familiar with generics. Using Generics in java collections is a simple task. generics have many unexpected effects. Before learning more about generics, let's first take a look at some basic concepts and principles of generics.
I. Introduction of java generics
Java generic applications can improve code reusability. At the same time, generic applications provide type checks to reduce data type conversion and ensure type security. Next, let's take a look at how generics ensure type security:
List list = new ArrayList (); list. add ("abc"); list. add (new Integer (1); // You can compile for (Object object: list) {System. out. println (String) object); // throws a ClassCastException}
The above code will throw ClassCastException at runtime because it tries to convert an Integer to a String. Next, let's take a look at the usage of Collection from Java 5:
List <String> list = new ArrayList <> (); list. add ("abc"); // list. add (new Integer (1); // compilation error for (String string: list) {System. out. println (string); // no forced type conversion required}
Note that the String type parameter is added to the List creation. Therefore, you can only add a String type object to the list. Adding other objects will throw a compilation exception. You can also note that, the foreach loop removes the ClassCastException exception during running without adding any forced type conversion.
Ii. generic classes and interfaces
To learn generics, you must naturally know how to use generics to define your own classes and interfaces. At the same time, in order to deepen understanding of the role of generics, we first introduce an original class:
Public class Gen {private Object obj; public Object getObj () {return obj;} public void setObj (Object obj) {this. obj = obj;} public static void main (String [] args) {Gen gen = new Gen (); gen. setObj ("abc"); String str = (String) gen. getObj (); // type conversion, which may cause ClassCastException }}
The definition of the original class is easy to cause ClassCastException, which is similar to the first point. Now let's take a look at the generic class to redefine Gen-use <> specify the generic parameters, as shown below:
Public class Gen <T> {T obj; public T getObj () {return obj;} public void setObj (T obj) {this. obj = obj;} public static void main (String [] args) {Gen <String> gen = new Gen <> (); gen. setObj ("abc"); // gen. setObj (10); // The String str = gen cannot be compiled. getObj (); // No need for type conversion // --------------------------- Gen gen2 = new Gen (); // raw type Original type gen2.setObj ("abc"); gen2.setObj (10 ); // It can be compiled and automatically packed to convert 10 to Integer object Integer num = (Integer) gen2.getObj (); // forced type conversion is used }}
You will find that in the main) method, the generic type Gen <String> is used, so you no longer need to force type conversion, and then the ClassCastException at runtime is removed. For the sake of difference, a gen2 without the generic type is also defined here. At this time, the compiler will pop up a warning "Gen is a raw type, references to generic type Gen <T> shocould be parameterized ". If the generic type is not provided, the Object will be replaced by default. Therefore, the String and Integer types can be set for gen2. However, we should try to avoid this situation, so we need to use forced type conversion, and the ClassCastException exception at runtime.
Tips: @ SuppressWarnings ("rawtypes") can be used to suppress the compiler's pop-up warning.
Interface generic applications are similar to class generic applications, as shown below:
public interface List <E> { void add(E x); Iterator<E> iterator();}public interface Iterator<E> { E next(); boolean hasNext();}
Similarly, this can be applied to custom interfaces and classes. In addition, you can use multiple generic parameters to define interfaces and classes, such as Map <K, V>. At the same time, the generic type can also be used as a parameter, new HashMap <String, List <String> ().
Iii. Generic naming rules
To better understand generics, we also need to understand the naming rules of java generics. To distinguish it from java keywords, java generic parameters are defined using only one uppercase letter. The meanings of common generic parameters are as follows:
- E-Element, which is often used in java Collection, such as List <E>, Iterator <E>, Set <E>
- K, V-Key, Value, representing the Key-Value pair of Map
- N-Number, Number
- T-Type, Type, such as String and Integer
- S, U, V etc.-2nd, 3rd, 4th type, same as T usage
Iv. generic methods and constructor
Sometimes we do not want the entire class to be generic. In this case, we can only apply generics to a method. Because constructor is a special method, you can also apply generics to constructor. Demo GenMethod demonstrates how to apply generics to methods and call generic methods,
public class GenMethod {public static <T> void fromArrayToCollection(T[] a,Collection<T> c){for (T t : a) { c.add(t);}}public static void main(String[] args) {Object[] oa = new Object[100];Collection<Object> co = new ArrayList<>();GenMethod.<Object>fromArrayToCollection(oa, co);}}
There are not many GenMethod codes, but there are a lot of notes. First, the generic parameters used to define the method must be added after the modifier. As shown in the preceding figure, public static <T>. If multiple generic parameters exist, you can define them as follows: <K, v> or <T1, T2>. Second, it is not recommended to add other types to generic variables. The following code will cause compilation errors or implicit errors:
public static <T> void fromArrayToCollection(T[] a,Collection<T> c){for (T t : a) {c.add(t);c.add(new Object());}}
Third, let's take a look at the generic method call GenMethod. <Object> fromArrayToCollection (oa, co); a generic Object is declared before the method. However, since the compiler can infer this generic type, it can also be written as follows:
GenMethod. fromArrayToCollection (oa, co ).
To deepen understanding of the compiler to deduce generic types, let's look at the following inferences:
String [] sa = new String [100]; Collection <String> cs = new ArrayList <String> (); // T is inferred as StringfromArrayToCollection (sa, cs ); // T is inferred to be ObjectfromArrayToCollection (sa, co); Integer [] ia = new Integer [100]; Float [] fa = new Float [100]; number [] na = new Number [100]; Collection <Number> cn = new ArrayList <Number> (); // T is inferred as NumberfromArrayToCollection (ia, cn ); // T inferred as NumberfromArrayToCollection (fa, cn); // T inferred as NumberfromArrayToCollection (na, cn); // T inferred as ObjectfromArrayToCollection (na, co ); // compilation error. Number and String are not compatible with fromArrayToCollection (na, cs );
Iv. Limits of generic parameters
Sometimes, you want the generic type to be only a certain part of the type. For example, when operating data, you want to be a Number or its subclass type. The idea is to add a boundary for generic parameters. Its definition form is:
<T extends BoundingType>
This definition indicates that T should be the subtype of BoundingType ). T and BoundingType can be classes or interfaces. In addition, the Child type represented by "extends" here is not the same as inheritance.
Demo:
Public class Box <T> {private T t; public void set (T t) {this. t = t;} public T get () {return t;} public <U extends Number> void inspect (U u) {System. out. println ("T:" + t. getClass (). getName (); System. out. println ("U:" + u. getClass (). getName ();} public static void main (String [] args) {Box <String> integerBox = new Box <> (); integerBox. set ("abc"); // can be compiled, because T is specified as String type // integerBox. inspect ("abc"); // It cannot be compiled because U must be of the Number type or its subclass integerBox. inspect (new Integer (10 ));}}
Box <T> shows how to add a boundary for generic parameters. The problem also arises. Since the limit of generic parameters is limited, can we call the corresponding method of Number in BoundingType ?? The answer is yes, as shown below:
public class NumberTest<T extends Integer> {private T num;public NumberTest(T num) { this.num = num;}public boolean isOdd(){return num.intValue()%2 == 1;}//....}
Next, we will introduce the following question: how to add multiple restriction ranges for generic parameters? The format of Multiple restriction ranges is as follows:
<T extends A & B & C>
A generic parameter can have multiple limits separated. There is one more class in the limit range. If a class is used as a limitation, it must be the first one in the limitation List. Example:
Class A { /* ... */ }interface B { /* ... */ }interface C { /* ... */ }class D <T extends A & B & C> { /* ... */ }
If BoundingType is not placed first, a compilation exception occurs:
Class D <T extends B & A & C> {/*... */} // cannot be compiled
V. Synthesis of generic methods and generic parameter boundaries
If the generic method is a useful tool, then the boundary of the Generic parameters should be the soul of the tool, and some "code of conduct" should be added to the tool ". As follows: design a method to count the number of elements in an array larger than the specified one,
Public static <T> int countGreater (T [] array, T elem) {int count = 0; for (T t: array) {if (t> elem) {// compilation error + + count ;}} return count ;}
The above method cannot be compiled. Why ?? Because the operator ">" can only be used in basic data types such as byte, char, short, int, float, long, double, boolean ), but it cannot be used to compare the size between class objects unless the Comparable interface is implemented ). To solve this problem, you need to add a <T> Comparable <T>:
public interface Comparable<T> { public int compareTo(T o);}
The changed code is as follows:
Public static <T extends Comparable <T> int countGreater (T [] array, T elem) {int count = 0; for (T t: array) {if (T. compareTo (elem)> 0) {// No compilation error + + count ;}} return count ;}
In addition to the above method, you can also select to add the boundary Comparator <T, T>. However, this boundary only requires two parameters. The definition and use of Comparator have been discussed before, click here for details.
6. Generic, inheritance, and subtypes
If the two classes are compatible with each other and inherited), you can assign a class Object to another class Object. For example, you can assign a String Object to an Object, string is a subclass of an Object,
String someString = new String();Object someObject = new Object();someObject = someString;
If you are familiar with object-oriented technology, you will know that this is a "is-a" relationship. String is an Object, so the above value assignment is acceptable. Similarly, Integer and Double are a type of Number objects. The following values can also be assigned:
public void someMethod(Number n) { /* ... */ }someMethod(new Integer(10)); // OKsomeMethod(new Double(10.1); // OK
This "is-a" relationship also uses generics. If you set the Number of the wildcard parameter, you only need to input a data object in the subsequent call, as shown below:
Box<Number> box = new Box<>();box.add(new Integer(1)); box.add(new Double(1.0));
Now, consider the following method:
public void someMethod(Box<Number> n) { /*.....*/}
What types of parameters can this method accept ?? Obviously, this method accepts the Box <Number> type parameter ?? Can I accept Box <Integer> or Box <Double> parameters ?? The answer is:
NoBecause both Box <Integer> and Box <Double> are not subclasses of Box <Number>. In generic programming, This is a confusing concept, but it must be understood. For example: 650) this. width = 650; "style =" background-image: none; border-right-0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px "title =" generics-subtypeRelationship "border =" 0 "alt =" generics-subtypeRelationship "src =" http://www.bkjia.com/uploads/allimg/131228/1443412155-0.gif "width =" 360 "height =" 241 "/> from the graph as you can see, even if Integer is Num But Box <Integer> is not a subclass of Box <Number>. The common parent class of Box <Integer> and Box <Number> is Object. In other words, no matter whether Class A and Class B are associated, MyClass <A> and MyClass <B> are not associated. The common parent class of MyClass is Object. Does it mean that there is no subclass for the generic type ?? This remains to be solved and will be known after reading this article. VII. generic classes and subtypes
In this section, we will first review the meaning of the generic method "extends". The generic "extends" is not the same as the inherited "extends, generic "extends" can be followed by a Class such as T extends Number), or an interface such as T extends List <T> ). Generic "extends" indicates the child type, rather than the child type. You may equivalent it to the union of "extends inheritance" and "implement.
In generics, there are also child types, provided that the limitations of their generic parameters have not changed. You can think that the generic parameters have not changed, in fact, it is to judge the subtype of the generic type from the original class or interface. For image understanding, we have used the collection class as an example, for example: ArrayList <E> implement List <E>, while List <E> extends Collection <E>, then, ArrayList <String> is the child type of List <String>, while List <String> is Collection <String>. The relationship diagram is as follows:
650) this. width = 650; "style =" background-image: none; border-right-0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px "title =" generics-sampleHierarchy "border =" 0 "alt =" generics-sampleHierarchy "src =" http://www.bkjia.com/uploads/allimg/131228/144341CA-1.gif "width =" 195 "height =" 155 "/>
Let's take a deeper look. Now we assume we need to define our own List interface-PayLoadList. Its definition is as follows:
interface PayloadList<E,P> extends List<E> { void setPayload(int index, P val); //...}
As shown above, the following examples are all List <String> subtypes ,:
PayloadList<String,String>PayloadList<String,Integer>PayloadList<String,Exception>
650) this.width=650;" style="background-image: none; border-right- 0px; padding-left: 0px; padding-right: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="generics-payloadListHierarchy" border="0" alt="generics-payloadListHierarchy" src="http://www.bkjia.com/uploads/allimg/131228/1443413G7-2.gif" width="464" height="117" />