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. - 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. - public class Wildcards<T> {
-
-
private List<T> list;
-
public void setList(List<T> list) {
-
this.list = list;
-
}
-
}
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. - public class Wildcards<T1,T2> {
-
-
private List<T1> list;
-
public void setList(List<T1> list) {
-
this.list = list;
-
}
-
public boolean hasMoreElementsThan(List<T2> otherList) {
-
return list.size() > otherList.size();
-
}
-
}
That should work. Let’s test it: - public static void main(String[] args) {
-
// Create a new ArrayList of Strings and fill it with "Hello", "World" and "!"
-
ArrayList<String> list1 = new ArrayList<String>();
-
list1.add("Hello");
-
list1.add("World");
-
list1.add("!");
-
// Create a new Wildcard<String> object and set list1 as the internal list
-
Wildcards<String,Integer> w1 = new Wildcards<String,Integer>();
-
w1.setList(list1);
-
// Create a new LinkedList of Integers and fill it with the Numbers 0 through 9
-
ArrayList<Integer> list2 = new ArrayList<Integer>();
-
for(int i=0; i<10; i++) {
-
list2.add(new Integer(i));
-
}
-
// Use the <i>hasMoreElementsThan</i> function
-
if(w1.hasMoreElementsThan(list2)) {
-
System.out.println("The internal list is bigger than the one it was compared to");
-
} else {
-
System.out.println("The internal list is not bigger than the one it was compared to");
-
}
-
}
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: - Exception in thread "main" java.lang.Error: Unresolved compilation problem:
-
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: - ((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: - public boolean hasMoreElementsThan(List<?> otherList) {
-
return list.size() > otherList.size();
-
}
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 - if(otherList.get(0) instanceof String) { … }
- 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: - public boolean closeToSize(List<Number> otherList) {
-
for(Number item : otherList) {
-
if(item.intValue() == list.size())
-
return true;
-
}
-
return false;
-
}
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: - public boolean closeToSize(List<? Extends Number> otherList) {
-
// Same as before
-
}
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 - public <S extends Number> boolean closeToSize2(List<S> otherList) {
-
for(int i=0; i<otherList.size(); i++) {
-
S item = otherList.get(i);
-
if(item.intValue() == list.size())
-
return true;
-
}
-
return false;
-
}
This should only be used however if the type is actually needed. - 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: - public void unite(List<? extends Form> listA, List<? extends Form> listB) {
-
for(Form item : listA) {
-
listB.add(item);
-
}
-
}
with - abstract class Form {
-
protected double area;
-
-
public double getArea() {
-
return area;
-
}
-
}
-
-
class Ellipse extends Form {
-
public Ellipse(int rx, int ry) {
-
super();
-
area = Math.PI * rx * ry;
-
}
-
}
-
-
class Circle extends Ellipse {
-
public Circle(int r) {
-
super(r,r);
-
}
-
}
-
-
class Rectangle extends Form {
-
public Rectangle(int x, int y) {
-
area = x * y;
-
}
-
}
-
-
class Square extends Rectangle {
-
public Square(int x) {
-
super(x,x);
-
}
-
}
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: - Exception in thread "main" java.lang.Error: Unresolved compilation problem:
-
The method add(capture#4-of ? extends Form) in the type List<capture#4-of ? extends Form> is not applicable for the arguments (Form)
-
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: - public void unite(List<? extends Circle> listA, List<? super Ellipse> listB) {
-
for(Circle item : listA) {
-
listB.add(item);
-
}
-
}
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!
3 4143
It's a nice article Nepomuk.
A very good one! :-)
Nepomuk 3,112
Recognized Expert Specialist
Very good explanation with even better examples. The examples are concise and point out the problem without having unnecessary code.
Sign in to post your reply or Sign up for a free account.
Similar topics |
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 ]
|
by: Alvaro Puente |
last post by:
Hi all!
Do any of you know if wildcards are accepted when calling rename()
function?
Thanks/Alvaro
|
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
|
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>
{
}
|
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.
...
| |
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)
--------------------------
|
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...
|
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:
|
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...
|
by: -- |
last post by:
Imagine I have a class TypeX and a class TypeY that inherts TypeX.
public class typeX
{
....
}
public class typeY
: typeX
{
....
|
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...
| |
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,...
|
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...
|
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,...
|
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...
|
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...
|
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
| |
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
|
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...
| |