473,602 Members | 2,774 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Advanced Generics: Wildcards

Nepomuk
3,112 Recognized Expert Specialist
The basics of Generics are explained in the article Generic Classes in Java by sreekandank. However, there is more to learn than explained in that article. Here I will talk about one specific feature of Java Generics called wildcards.
  1. Basic wildcards
    Generics can be very useful, but sometimes they can be limiting. For example, say you have a generic class Wildcard<T> which has an List<T> object. This so far is no problem.
    Expand|Select|Wrap|Line Numbers
    1. public class Wildcards<T> {
    2.  
    3.     private List<T> list;
    4.     public void setList(List<T> list) {
    5.         this.list = list;
    6.     }
    7. }
    However, say we want to now write a function which will compare the length of the internal list with another List which is of course also generic. This should happen within the Wildcard<T> class and it should not depend on this second List having the same generic Type as the first one.
    A first attempt could be to make the Wildcard class more generic: Wildcard<T1,T2>. Now we can write our function.
    Expand|Select|Wrap|Line Numbers
    1.  public class Wildcards<T1,T2> {
    2.  
    3.     private List<T1> list;
    4.     public void setList(List<T1> list) {
    5.         this.list = list;
    6.     }
    7.     public boolean hasMoreElementsThan(List<T2> otherList) {
    8.         return list.size() > otherList.size();
    9.     }
    10. }
    That should work. Let’s test it:
    Expand|Select|Wrap|Line Numbers
    1. public static void main(String[] args) {
    2.     // Create a new ArrayList of Strings and fill it with "Hello", "World" and "!"
    3.     ArrayList<String> list1 = new ArrayList<String>();
    4.     list1.add("Hello");
    5.     list1.add("World");
    6.     list1.add("!");
    7.     // Create a new Wildcard<String> object and set list1 as the internal list 
    8.     Wildcards<String,Integer> w1 = new Wildcards<String,Integer>();
    9.     w1.setList(list1);
    10.     // Create a new LinkedList of Integers and fill it with the Numbers 0 through 9
    11.     ArrayList<Integer> list2 = new ArrayList<Integer>();
    12.     for(int i=0; i<10; i++) {
    13.         list2.add(new Integer(i));
    14.     }
    15.     // Use the <i>hasMoreElementsThan</i> function
    16.     if(w1.hasMoreElementsThan(list2)) {
    17.         System.out.println("The internal list is bigger than the one it was compared to");
    18.     } else {
    19.         System.out.println("The internal list is not bigger than the one it was compared to");
    20.     }
    21. }
    Great, that should work. But are there any problems? Well, yes. Say we want to also compare the internal list to a third List. We would have to either create a new Wildcard instance for each type we want to compare our list to or make the list of types longer each time we want to add a new comparison. That’s not very efficient. Another idea might be to cast the second List to a more general type, such as LinkedList<Obje ct>. Trying that however will result in the following error message:
    Expand|Select|Wrap|Line Numbers
    1.  Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    2.     Cannot cast from LinkedList<Integer> to LinkedList<Object>
    Why so? Well, if that kind of cast were allowed, one could also do something like this:
    Expand|Select|Wrap|Line Numbers
    1. ((LinkedList<Object>) list2).add(42);
    I hope you see the problem.
    Anyway, this is why there is the concept of wildcards in Java; rather than adding a further generic type for comparison we tell the hasMoreElements Than function ”I don’t really care, what sort of list it is I’m comparing to.” And here’s how that works:
    Expand|Select|Wrap|Line Numbers
    1. public boolean hasMoreElementsThan(List<?> otherList) {
    2.     return list.size() > otherList.size();
    3. }
    The question mark means that we don’t care about the type. It is not the same as casting it to a List<Object>, because in this case we have no information whatsoever about what kind of Object may be in the List. We don’t have any information about the generic type through the call.

    Note: It is still possible to do stuff like
    Expand|Select|Wrap|Line Numbers
    1. if(otherList.get(0) instanceof String) { … }
  2. Upper-bound wildcards
    Though this can be useful, sometimes we want more control over what kinds of parameters can be handed to a function. Say for example, we want to create a further function in the Wildcards class that will check whether one of the numbers in a List of numbers is close to the size of our internal list. This could look something like this:
    Expand|Select|Wrap|Line Numbers
    1. public boolean closeToSize(List<Number> otherList) {
    2.     for(Number item : otherList) {
    3.         if(item.intValue() == list.size())
    4.             return true;
    5.     }
    6.     return false;
    7. }
    But wait – that only works if our List is actually a List<Number> but not if it’s a List<Integer> or a List<Double>. What to do?
    Luckily, there are methods of limiting wildcards. Upper-bound wildcards are one of the two methods that are offered to do that. Basically, we say ”allow any generic object that extends Number”. And writing this is luckily very easy:
    Expand|Select|Wrap|Line Numbers
    1.  public boolean closeToSize(List<? Extends Number> otherList) {
    2.     // Same as before
    3. }
    Note: The extends X syntax doesn’t just work for wildcards – if you want access to the generic type, you can also have something like
    Expand|Select|Wrap|Line Numbers
    1.  public <S extends Number> boolean closeToSize2(List<S> otherList) {
    2.     for(int i=0; i<otherList.size(); i++) {
    3.         S item = otherList.get(i);
    4.         if(item.intValue() == list.size())
    5.             return true;
    6.     }
    7.     return false;
    8. }
    This should only be used however if the type is actually needed.
  3. Lower-bound wildcards
    If there are upper-bound wildcards then intuition tells us that there are probably lower-bound ones too. And indeed, they exist! The reason they are needed is known as the PECS principle: Producer Expands, Consumer Super. But what does that mean?
    In the upper-bound example, the List produced items with which we could do things. Because of that, we needed some information on what kind of objects the contents may be. If however we want to create a new List and have this new List consume Objects (= add Objects to the List), we need to know what can be put into it. An example:
    Expand|Select|Wrap|Line Numbers
    1.  public void unite(List<? extends Form> listA, List<? extends Form> listB) {
    2.     for(Form item : listA) {
    3.         listB.add(item);
    4.     }
    5. }
    with
    Expand|Select|Wrap|Line Numbers
    1.  abstract class Form {
    2.     protected double area;
    3.  
    4.     public double getArea() {
    5.         return area;
    6.     }
    7. }
    8.  
    9. class Ellipse extends Form {
    10.     public Ellipse(int rx, int ry) {
    11.         super();
    12.         area = Math.PI * rx * ry;
    13.     }
    14. }
    15.  
    16. class Circle extends Ellipse {
    17.     public Circle(int r) {
    18.         super(r,r);
    19.     }
    20. }
    21.  
    22. class Rectangle extends Form {
    23.     public Rectangle(int x, int y) {
    24.         area = x * y;
    25.     }
    26. }
    27.  
    28. class Square extends Rectangle {
    29.     public Square(int x) {
    30.         super(x,x);
    31.     }
    32. }
    If we try to compile this, and call it with w1.unite(list4, list5) (the Lists being of the types ArrayList<Ellip se> and ArrayList<Circl e> respectively) the following RuntimeExceptio n is thrown:
    Expand|Select|Wrap|Line Numbers
    1.  Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    2.     The method add(capture#4-of ? extends Form) in the type List<capture#4-of ? extends Form> is not applicable for the arguments (Form)
    3.  
    The reason for this is that the program has no way of knowing, whether the two generic types are compatible. After all, from what it knows we may be trying to add Squares to a List of of Circles! For this reason, we can limit wildcards in the other direction too:
    Expand|Select|Wrap|Line Numbers
    1.  public void unite(List<? extends Circle> listA, List<? super Ellipse> listB) {
    2.     for(Circle item : listA) {
    3.         listB.add(item);
    4.     }
    5. }
    This means, that the items of listB can be anything that is in the inheritance chain of Ellipse; this is of course only Form (which is abstract) and Ellipse itself. But, as we’re not reading from listB but only writing to it and Circles can be interpreted as Ellipses, this will work.
So, this has been a detailed explanation of what Wildcards in the world of Java Generics are. The full code can be downloaded below. So now it's time for you to do something with this new knowledge!
Attached Files
File Type: zip Wildcards.java.zip (1.8 KB, 111 views)
May 16 '13 #1
3 4143
sankar2011
18 New Member
It's a nice article Nepomuk.
A very good one! :-)
Dec 9 '13 #2
Nepomuk
3,112 Recognized Expert Specialist
Glad you like it :-)
Dec 9 '13 #3
chaarmann
785 Recognized Expert Contributor
Very good explanation with even better examples. The examples are concise and point out the problem without having unnecessary code.
Dec 11 '13 #4

Sign in to post your reply or Sign up for a free account.

Similar topics

3
1512
by: Stephen Waits | last post by:
Specifically, I'd like something that goes into detail on expression and meta templates.. Thanks, Steve http://www.gotw.ca/resources/clcm.htm for info about ]
10
5106
by: Alvaro Puente | last post by:
Hi all! Do any of you know if wildcards are accepted when calling rename() function? Thanks/Alvaro
4
1632
by: noname | last post by:
I'm learning C# generics recenly. How do i do to write the similar Java function below in C#? void printCollection(Collection<? extends A> c) { for (Object e: c) { System.out.println(e); }} In printCollection, I have to limit the bound of the argument, when is a generic of Collection with some classes inherites from A. Does anyone know
7
4571
by: Jock | last post by:
Hi all, Could anybody suggest what should be the return type of the method Create in the Factory class? In Java I would have used the wildcards, but here in C# apparently there is no way do do it?!? public class B<T> { }
9
5967
by: sloan | last post by:
I'm not the sharpest knife in the drawer, but not a dummy either. I'm looking for a good book which goes over Generics in great detail. and to have as a reference book on my shelf. Personal Experience Only, Please. ...
19
4627
by: Alan Carpenter | last post by:
Access 8 on Win98 and WinXP I'm having trouble with wildcards in the .Filename property of the FileSearch Object giving different results on win98 and XP. I've been successfully using FileSearch in win98 to fill an array with filenames with no problems since about 1998. From the 97 Help: (The Filename Property of the FileSearch object) --------------------------
13
3809
by: rkausch | last post by:
Hello everyone, I'm writing because I'm frustrated with the implementation of C#'s generics, and need a workaround. I come from a Java background, and am currently writing a portion of an application that needs implementations in both Java and C#. I have the Java side done, and it works fantastic, and the C# side is nearly there. The problem I'm running into has to do with the differences in implementations of Generics between the two...
10
5021
by: =?Utf-8?B?S29ucmFkIFJ1ZG9scGg=?= | last post by:
Hello, I was wondering if C# 3.0 finally supported generic upcasting. Consider the following code which does work in C# 2: string xs = {"this", "is", "a", "test"}; object ys = xs; Now, analogously, I would expect the following to work as well:
5
36629
by: nidaar | last post by:
From a security point of view, is accepting wildcards like "%" in input parameters of stored procedures against any best practices? As an example, if a user defined function uses "Productname LIKE @ProductName" in WHERE clause of a select statement, and a stored procedure uses the user defined function while passing @ProductName input parameter to the user defined function, is there any security risks? Is there a better way to construct...
20
1833
by: -- | last post by:
Imagine I have a class TypeX and a class TypeY that inherts TypeX. public class typeX { .... } public class typeY : typeX { ....
0
7993
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
7920
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8401
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8054
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8268
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
6730
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
2418
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1510
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1254
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.