Generics and Wildcard expression_1
Generics_Part 1
Generics was introduced from JDK 1.5 and since then been serving as a major feature in using Java language.
Generics is a function that does compile-time type checks for method or collection classes that deals with various types of objects; hence classes like HashSet, ArrayList, and HashMap make very good uses of generics.
1. Basics
Generics does…
enhances type stability : it prevents objects from being saved in unintended types, and reduces errors when an object is taken out in a different type than its original type.
simplifies the code : it lets you omit writing codes for type checking and casting.
package Generics;
public class Person<T> {
T language;
void setLanguage(T language){
this.language = language;
}
T getLanguage(){
return this.language;
}
}
- One thing to note is that ‘T’ can be substituted to basically any alphabet. Normally in case of arrayList, E (elements) is used; and for Map, K(key) and V(value) are often used.
Person<String> person = new Person<>();
person.setLanguage("Java");
person.setLanguage(new Object()); //<---error!
- The once-mysterious type T is not fixed to be a String. Once defined such, it has same as writing the whole class with String substituting T. Hence the error from the third line above.
Person<String> person = new Person<String>();
person.setLanguage("Java");
person.setLanguage(new Object()); //<---error!
Person<Integer> person2 = new Person<Integer>();
person2.setLanguage("Python"); //<---error!
person2.setLanguage(0);
- It is possible to make several Person objects, much like it is possible to call a same function multiple times with varying arguments.
- It will follow quite automatically that static members can’t have a generics type, because they should be used in a same way regardless of object types.
What is okay and not
public class Person<M> {
M language;
M[] languageArr; //OK
M toArray(){
M[] tmpArr = new M[languageArr.length]; //Error!
}
}
- Declaring an array of generics type is okay, while instantiating a new one is not.
- This is because new operator has to know exactly what type the T is during the compile time. Likewise, instanceof cannot be used because compiler has no way of knowing what T will be.
2. Using Generics
public static void main(String[] args) {
Person<JavaDeveloper> javaPerson = new Person<>(); // specific type of T can be ommited from JDK 1.7
Person<JavaDeveloper> javaScriptPerson = new Person<JavaScriptDeveloper>(); //error
Person<JavaDeveloper> groupOfJavaPersons = new Person<>();
groupOfJavaPersons.add(new Java());
groupOfJavaPersons.add(new JavaScript()); //error!
}
public class Programmer{}
public class JavaDeveloper extends Programmer{}
public class JavaScriptDeveloper extends Programmer{}
- This is quite self-explanatory. Once declared with specific types, the created objects won’t tolerate other types to butt in.
3. Limited Generics Class
- As mentioned in beginning, generics was created to lessen the burden for type-checking and casting. So far there doesn’t seem to be much virtue in it. how about limiting the type T to only take certain types of objects?
public class Person<T extends Programmer>
- This forces T to be descendents of Programmer. Hence, the below is possible.
Person<Programmer> programmerBatch = new Person<>(); programmerBatch.add(new JavaDeveloper()); programmerBatch.add(new JavaScriptDeveloper()); -
Basically if you omit and just write <T>, it is same as <T extends Object>
- When it comes to implementing an interface, make sure to use extends, rather than the usual implements.
interface codable()
class programmerBatch<T extends codable>
4. Wildcard Expressions
-
Once I bumped into this link in stackoverflow https://stackoverflow.com/questions/7573269/what-is-the-difference-between-and-t-in-class-and-method-signatures
-
After reading the adopted answer, I could still not get 100% of what the difference was. Now let’s investigate.
public class Outsourcing {
static webPage makeWebPage(Person<Programmer> box){
String temp = "Coded by ";
for(Programmer p : box.getList()) temp += p + " ";
return new webPage(temp);
}
}
Above class has the following problems.
- (1) Since it is a static method, a specific type (programmer) has to be written
- (2) Because of (1), if you want to substitute programmer to JavaDeveloper or JavaScriptDeveloper, you have to make separte methods like
static webPage makeWebPage(Person<JavaDeveloper> box){
String temp = "Coded by ";
for(Programmer p : box.getList()) temp += p + " ";
return new webPage(temp);
}
static webPage makeWebPage(Person<JavaScriptDeveloper> box){
String temp = "Coded by ";
for(Programmer p : box.getList()) temp += p + " ";
return new webPage(temp);
}
- (3) However, this is NOT possible, because having different generic types does not allow overloading.
- (4) This can be handled with ?(wildcard)!
<? extends T> : upper limit. T and its descendents <? super T> : lower limit. T and its ancestors <?> : no limit. same as <? extends Object>
- Converting the problematic makeWebPage function,
static webPage makeWebPage(Person<? extends Programmer> box){
...
}
-
Now this makeWebPage can accomodate JavaDevelopers and JavaScriptDevelopers at once! (and any of Programmer’s descendets)
-
Going back to the link, I can conclude that Generic type T is a compile-time decided consistent type for class, whereas wildcard is an expression limiting the range of types. Those two are not of same nature, the former being a grammar and the latter a little like a hack.
5. Generic Method
static <T> void sort(List<T> list, Comparator<? super T> c)
- The T in method and T in class are ‘totally different’ things. They may or may not be the same, and utterly unrelated.
static webPage makeWebPage(Person<? extends Programmer> box){
...
} //can be changed into ...
static Person<? extends Programmer> webPage makeWebPage(Person<T> box){
...
}
- Below is some tricky example
public static <T extends Comparable<? super T>> void sort(List <T> list) - Okay. parameter ‘list’ is of type T that is a decendents of Comparable<? super T> for one.
- The comparable interface compares T or its ancestors.
- If the list is given as JavaDevelopers, the comparable compares JavaDevelopers, Programmers and Persons and Objects