So I've been reading through the Generics tutorial offered by Oracle here: http://docs.oracle.com/javase/tutorial/java/generics/
And I've tried running my own example to make sure I understand how to use Generics. I have the following code:
import java.util.*;
public class Generics {
class NaturalNumber {
private int i;
public NaturalNumber(int i) { this.i = i; }
}
class EvenNumber extends NaturalNumber {
public EvenNumber(int i) {
super(i);
}
}
public static void main(String[] args) {
Collection<? extends NaturalNumber> c = new ArrayList<>();
c.add(new EvenNumber(2)); //this line produces a compile time error
}
}
My goal is to be able to add any object which is a subtype of NaturalNumber to the Collection c. I'm not sure why this doesn't work and reading through Oracle's tutorial hasn't enlightened me either.
When you have ? extends NaturalNumber, the parameter could be some other subclass of NaturalNumber that is in no way related to EvenNumber. For instance,
Collection<? extends NaturalNumber> c = new ArrayList<OtherNaturalNumber>();
is valid if OtherNaturalNumber extends NaturalNumber.
Consequently, you are not able to add an EvenNumber instance to the list. You can just use this declaration:
Collection<NaturalNumber> c = new ArrayList<>();
which will allow you to add any NaturalNumber instance (including an EvenNumber).
On another note, you probably meant to make those nested classes static (or don't nest them at all).
First Collection<? extends NaturalNumber> should just be Collection<NaturalNumber>. Instances of EvenNumber (or any NaturalNumber or a subtype of NaturalNumber) can be put into the collection this way.
Essentially Collection<? extends NaturalNumber> says that the type of the type parameter to Collection extends NaturalNumber. So say that class OddNumber extends NaturalNumber, then the type of Collection's type parameter could be OddNumber which EvenNumber cannot be safely cast to.
However there is another compiler error. To be used in the static context or main(String[]) each of the inner classes NaturalNumber and EvenNumber need to have the modifier static placed on each class declaration.
Your problem is that you've told the compiler that the Collection's element type can be any type that extends NaturalNumber, but then you tried to insert an object into it. As far as the compiler knows, c is a Collection<OddNumber>, and you just added an EvenNumber!
Related
Could anyone please help me understand how does Java's generics work? I understand the concept of it. But for this specific example of the code I don't clearly understand the compiler's error messages.
Example code:
Test class
// Test code
public class A < ListType extends Comparable < ListType >> {
// To make the instance variable y
public int y;
// To make the instance variable s
public String s;
//Constructor Method
public A(int requiredY, String requiredS) {
y = requiredY;
s = requiredS;
}
more code here...
}
Then in a different class I wrote
List <A> a = new ArrayList<A>();
more code here...
Collections.sort(a)
The error message I am getting is
test.java:20: error: no suitable method found for sort(List<A>)
Collections.sort(a);
^
method Collections.<T#1>sort(List<T#1>) is not applicable
(inference variable T#1 has incompatible bounds
equality constraints: A
upper bounds: Comparable<? super T#1>)
method Collections.<T#2>sort(List<T#2>,Comparator<? super T#2>) is not applicable
(cannot infer type-variable(s) T#2
(actual and formal argument lists differ in length))
where T#1,T#2 are type-variables:
T#1 extends Comparable<? super T#1> declared in method <T#1>sort(List<T#1>)
T#2 extends Object declared in method <T#2>sort(List<T#2>,Comparator<? super T#2>)
I don't understand why is the compiler complaining about the type parameter. Shouldn't the collections work? Because the type parameters are both mutually comparable.
Either you're writing your question wrong in order to hide the class names, or you're mistaken in representing the generics.
If what you're trying to do is making a class that could be sorted, you can implement Comparable in the class A as others have suggested.
public class A < ListType extends Comparable < ListType >> {
...
}
The above code would require the class A to accept a class that extends/implements Comparable, and use ListType as its type erasure.
Since you don't show how would you use the ListType to bound a type, I don't think this is what you want.
Usually generics are used to bound the type of parameter you can use in a class, in order to provide a type-safe operations in compile time.
import java.lang.Override;
public class A <ListType extends Comparable<ListType>>{
ListType lt;
A(ListType b){
this.lt = b;
}
static class B implements Comparable<B>{
B(){};
#Override
public int compareTo(B b){
return 0;
}
}
static class C implements Comparable<B>{
C(){};
#Override
public int compareTo(B c){
return 0;
}
}
public static void main(String[] args){
A<B> a = new A<B>(new B()); //OK
A<C> _a = new A<C>(new C()); //ERROR: is not within bound
System.out.println("");
}
}
Because class C is not implementing a Comparable class with itself, you cannot pass a class C variable to the class A constructor.
If you want to create a type that will accept any classes that extends Comparable, you could use a wildcard ?.
public class A <ListType extends Comparable<?>>
or use a single capital letter as type for better code styling
public class A <T extends Comparable<?>>
Your issue is that A is not Comparable. Notice your type signature:
public class A<ListType extends Comparable<ListType>>
This says that A (which is a poor name for a concrete class, single-letter types are generally reserved for generic types) has a generic type ListType, and that ListType is Comparable with other ListType objects.
The signature of Collections.sort() expects to be passed a List<T> where T is a generic type that implements Comparable. Since A does not implement Comparable you cannot pass it to Collections.sort().
You likely did not mean to define A the way you did. You probably intended to do something like this:
public class A<ListType> implements Comparable<A<ListType>>
This says both that A has a generic type called ListType and that A implements Comparable and therefore can be compared (and sorted) with other instances of A.
Since A now implements the Comparable interface you'll need to define a
compareTo() method on A.
You should check how to use the Comparator Interface.
To compare custom classes you need to implement your customized Comparator and then only you can use the Sorting method provided by the collections interface.
You can look here for reference.
I am reading about generic methods from OracleDocGenericMethod. I am pretty confused about the comparison when it says when to use wild-card and when to use generic methods.
Quoting from the document.
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
We could have used generic methods here instead:
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
// Hey, type variables can have bounds too!
}
[…]
This tells us that the type argument is being used for polymorphism;
its only effect is to allow a variety of actual argument types to be
used at different invocation sites. If that is the case, one should
use wildcards. Wildcards are designed to support flexible subtyping,
which is what we're trying to express here.
Don't we think wild card like (Collection<? extends E> c); is also supporting kind of
polymorphism? Then why generic method usage is considered not good in this?
Continuing ahead, it states,
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
What does this mean?
They have presented the example
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
[…]
We could have written the signature for this method another way,
without using wildcards at all:
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
The document discourages the second declaration and promotes usage of first syntax? What's the difference between the first and second declaration? Both seems to be doing the same thing?
Can someone put light on this area.
There are certain places, where wildcards, and type parameters do the same thing. But there are also certain places, where you have to use type parameters.
If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
Taking your method as example, suppose you want to ensure that the src and dest list passed to copy() method should be of same parameterized type, you can do it with type parameters like so:
public static <T extends Number> void copy(List<T> dest, List<T> src)
Here, you are ensured that both dest and src have same parameterized type for List. So, it's safe to copy elements from src to dest.
But, if you go on to change the method to use wildcard:
public static void copy(List<? extends Number> dest, List<? extends Number> src)
it won't work as expected. In 2nd case, you can pass List<Integer> and List<Float> as dest and src. So, moving elements from src to dest wouldn't be type safe anymore.
If you don't need such kind of relation, then you are free not to use type parameters at all.
Some other difference between using wildcards and type parameters are:
If you have only one parameterized type argument, then you can use wildcard, although type parameter will also work.
Type parameters support multiple bounds, wildcards don't.
Wildcards support both upper and lower bounds, type parameters just support upper bounds. So, if you want to define a method that takes a List of type Integer or it's super class, you can do:
public void print(List<? super Integer> list) // OK
but you can't use type parameter:
public <T super Integer> void print(List<T> list) // Won't compile
References:
Angelika Langer's Java Generics FAQs
Consider following example from The Java Programming by James Gosling 4th edition below where we want to merge 2 SinglyLinkQueue:
public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
// merge s element into d
}
public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
// merge s element into d
}
Both of the above methods have the same functionality. So which is preferable? Answer is 2nd one. In the author's own words :
"The general rule is to use wildcards when you can because code with wildcards
is generally more readable than code with multiple type parameters. When deciding if you need a type
variable, ask yourself if that type variable is used to relate two or more parameters, or to relate a parameter
type with the return type. If the answer is no, then a wildcard should suffice."
Note: In book only second method is given and type parameter name is S instead of 'T'. First method is not there in the book.
In your first question: It means that if there is a relation between the parameter's type and the method's return type then use a generic.
For example:
public <T> T giveMeMaximum(Collection<T> items);
public <T> Collection<T> applyFilter(Collection<T> items);
Here you are extracting some of the T following a certain criteria. If T is Long your methods will return Long and Collection<Long>; the actual return type is dependent on the parameter type, thus it is useful, and advised, to use generic types.
When this is not the case you can use wild card types:
public int count(Collection<?> items);
public boolean containsDuplicate(Collection<?> items);
In this two example whatever the type of the items in the collections the return types will be int and boolean.
In your examples:
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
those two functions will return a boolean whatever is the types of the items in the collections. In the second case it is limited to instances of a subclass of E.
Second question:
class Collections {
public static <T> void copy(List<T> dest, List<? extends T> src) {
...
}
This first code allow you to pass an heterogeneous List<? extends T> src as a parameter. This list can contain multiple elements of different classes as long as they all extends the base class T.
if you had:
interface Fruit{}
and
class Apple implements Fruit{}
class Pear implements Fruit{}
class Tomato implements Fruit{}
you could do
List<? extends Fruit> basket = new ArrayList<? extends Fruit>();
basket.add(new Apple());
basket.add(new Pear());
basket.add(new Tomato());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket);// works
On the other hand
class Collections {
public static <T, S extends T> void copy(List<T> dest, List<S> src) {
...
}
constrain List<S> src to be of one particular class S that is a subclass of T. The list can only contain elements of one class (in this instance S) and no other class, even if they implement T too. You wouldn't be able to use my previous example but you could do:
List<Apple> basket = new ArrayList<Apple>();
basket.add(new Apple());
basket.add(new Apple());
basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();
Collections.copy(fridge, basket); /* works since the basket is defined as a List of apples and not a list of some fruits. */
Wildcard method is also generic - you could call it with some range of types.
The <T> syntax defines a type variable name. If a type variable has any use (e.g. in method implementation or as a constraint for other type), then it makes sense to name it, otherwise you could use ?, as anonymous variable. So, looks like just a short-cut.
Moreover, the ? syntax is not avoidable when you declare a field:
class NumberContainer
{
Set<? extends Number> numbers;
}
I will try and answer your question, one by one.
Don't we think wild card like (Collection<? extends E> c); is also
supporting kind of polymorphism?
No. The reason is that the bounded wildcard has no defined parameter type. It is an unknown. All it "knows" is that the "containment" is of a type E (whatever defined). So, it cannot verify and justify whether the value provided matches the bounded type.
So, it's no sensible to have polymorphic behaviours on wildcards.
The document discourages the second declaration and promotes usage of
first syntax? What's the difference between the first and second
declaration? Both seems to be doing the same thing?
The first option is better in this case as T is always bounded, and source will definitely have values (of unknowns) that subclasses T.
So, suppose that you want to copy all list of numbers, the first option will be
Collections.copy(List<Number> dest, List<? extends Number> src);
src, essentially, can accept List<Double>, List<Float>, etc. as there is an upper bound to the parameterized type found in dest.
The 2nd option will force you to bind S for every type you want to copy, like so
//For double
Collections.copy(List<Number> dest, List<Double> src); //Double extends Number.
//For int
Collections.copy(List<Number> dest, List<Integer> src); //Integer extends Number.
As S is a parameterized type that needs binding.
I hope this helps.
One other difference which is not listed here.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}
}
But the following will result in compile time error.
static <T> void fromArrayToCollection(T[] a, Collection<?> c) {
for (T o : a) {
c.add(o); // compile time error
}
}
? means unknown
The general rule applies:
You can read from it, but not write
given simple pojo Car
class Car {
void display(){
}
}
This will compile
private static <T extends Car> void addExtractedAgain1(List<T> cars) {
T t = cars.get(1);
t.display();
cars.add(t);
}
This method won't compile
private static void addExtractedAgain2(List<? extends Car> cars) {
Car car = cars.get(1);
car.display();
cars.add(car); // will not compile
}
Another example
List<?> hi = Arrays.asList("Hi", new Exception(), 0);
hi.forEach(o -> {
o.toString() // it's ok to call Object methods and methods that don't need the contained type
});
hi.add(...) // nothing can be add here won't compile, we need to tell compiler what the data type is but we do not know
As far as I understand, there is only one use case when wildcard is strictly needed (i.e. can express something that you can not express using explicit type parameters). This is when you need to specify a lower bound.
Apart from that however wildcards serve to write more concise code, as described by the following statements in the document you mention:
Generic methods allow type parameters to be used to express
dependencies among the types of one or more arguments to a method
and/or its return type. If there isn't such a dependency, a generic
method should not be used.
[...]
Using wildcards is clearer and more concise than declaring explicit
type parameters, and should therefore be preferred whenever possible.
[...]
Wildcards also have the advantage that they can be used outside of
method signatures, as the types of fields, local variables and arrays.
Mainly -> Wildcards enforce generics at the parameter/argument level of a Non-Generic method.
Note. It can also be performed in genericMethod by default, but here instead of ? we can use T itself.
package generics;
public class DemoWildCard {
public static void main(String[] args) {
DemoWildCard obj = new DemoWildCard();
obj.display(new Person<Integer>());
obj.display(new Person<String>());
}
void display(Person<?> person) {
//allows person of Integer,String or anything
//This cannnot be done if we use T, because in that case we have to make this method itself generic
System.out.println(person);
}
}
class Person<T>{
}
SO wildcard has its specific usecases like this.
I have a simple generic list class. I'm trying to achieve this: given a list instance of which we know only that it contains instances of a specific subclass of a class, and given an instance of this class, add this instance to the list if it is instance of the contained (subclass) type, otherwise throw an exception (eg. ClassCastException). I tried the following:
class MyList<T>
{
private Class<T> genericClass;
private List<T> list = new ArrayList<>();
public MyList(Class<T> genericClass)
{
this.genericClass = genericClass;
}
public void add(T elem)
{
list.add(elem);
}
//...
public Class<T> getGenericParamClass()
{
return genericClass;
}
}
class A{}
class B extends A{}
class C extends A{}
class Program
{
public static void main(String... args)
{
MyList<B> list1 = new MyList<>(B.class);
MyList<C> list2 = new MyList<>(C.class);
MyList<? extends A> ls = checkStuff() ? list1 : list2;
ls.add(ls.getGenericParamClass().cast(lotsOfStuff())); //ERROR ?!!
}
static boolean checkStuff()
{
Random random = new Random();
return random.nextBoolean();
}
static A lotsOfStuff()
{
return new B();
}
}
I thought that given a Class object whose type parameter is the same as the type of a parameter of a method, I would be able to cast something using the former to be able to pass it to the latter. Alas, it seems I cannot: I get a compile-time error!
I could throw generics out the window, go full unchecked and just say:
A val = lotsOfStuff();
if (myList.getGenericParamClass().isInstance(val))
ls.add(val)
else
throw new SomeException();
But, that would probably create more problems than it would solve, and also it would really bug me.
Am I missing something here, or is it simply not possible the way I thought it out?
Edit:
I understand fully well why something like this cannot work:
List<? extends Number> abc=new ArrayList<Integer>();
abc.add(new Integer(10));
But in my mind, the following transitivity holds: the type of the parameter of add() Is-The-Same-As the type parameter of MyList Is-The-Same-As the type parameter of the Class returned by getGenericParamClass() Is-The-Same-As the return type of the cast() method of that Class. I (as a human) can know that those unknown types are the same, because I am getting them from the same object.
Is there a fault in my logic, or is this a limitation of Java?
The compilation error is:
The method add(capture#2-of ? extends A) in the type MyList is not applicable for the arguments (capture#3-of ? extends A)
To understand that message, recall that ? extends A stands for an unknown type that is a subtype of A. That compiler can not know that the ? extends A returned by lotsOfStuff() is the same (or a subtype of) the ? extends A that the MyList.add method expects, and in fact, your program does not ensure that this is the case (because lotsOfStuff() always returns a B, even if it should be added to a list of C.)
To express that the two are of the same type, we must use a type parameter. The easiest way to get one is to move the code doing the casting and throwing into class MyList<T> (which already has a suitable type parameter), for instance by adding the following method:
void addOrThrow(Object o) {
add(genericClass.cast(o));
}
So I have a class that implements Comparable (I have a dummy method here for brevity)
public class MarkovEntry<T extends Chainable> implements Comparable<MarkovEntry<T>>
{
// Compare two rows by ID
public int compareTo(MarkovEntry<T> e)
{
return 0;
}
}
And a method in another class that takes a Comparable (once again, dummy method)
public class ArrayOps
{
public static int binSearch(ArrayList<Comparable> list, Comparable c)
{
return 0;
}
}
Yet when I try to call my method as follows
int index = ArrayOps.binSearch(entries, newEntry);
Where entries is an ArrayList of MarkovEntry's and newEntry is a MarkovEntry, the compiler tells me
actual argument java.util.ArrayList<com.company.MarkovEntry<T>> cannot be converted
to java.util.ArrayList<java.lang.Comparable> by method invocation.
What is going on here? MarkovEntry specifically implements Comparable -- why doesn't the compiler recognize that?
My class Chainable implements Comparable as well, in case that has anything to do with it.
Generics are a little strange in that
ArrayList<SuperType>
is not actually a supertype of
ArrayList<SubType>
e.g. ArrayList<Number> is not a supertype of ArrayList<Integer>. This is because if such a relationship held you could substitute in an ArrayList<Number> for an ArrayList<Integer>, which would then allow operations that would have been illegal if you didn't make the replacement.
To be more specific, say you did this:
ArrayList<Number> list = new ArrayList<Integer>();
You'd then be able to put in a Double into list because to the compiler, list is an ArrayList<Number>! As you can see, this breaks the guarantees that generics should provide, so it isn't allowed.
What you're looking for is a generic method like this:
public static <T extends Comparable<? super T>> int binSearch(ArrayList<T> list)
Basically, you can generify methods the same way you can generify classes.
More info can be found here: http://docs.oracle.com/javase/tutorial/extra/generics/methods.html
I took a look on questions q1, q2, q3, but they don't cover exactly my question.
Note that ArrayList<A> and ArrayList<? extends A> are to be used for declaring a variable or a parameter (not for creating a new generic class).
Are both expressions equivalent when declaring an object attribute (case 1)?:
class Foo {
private ArrayList<A> aList; // == ArrayList<? extends A> aList;
}
EDIT: Are both expressions equivalent from the point of view of what
kind of objects are allowed to be added to aList?, but different
in the same sense as the following case?
but they are different when used in a parameter declaration (case 2)?:
void methodFoo(ArrayList<A> al) != void methodFoo(ArrayList<? extends A> al)
because the first one only allows to be passed ArrayList objects
while the second would be like "more permissive" allowing to be sent
ArrayList<A1> and ArrayList<A2> (as long as A1 and A2 extends A)?
If this is right, is there any other scenario where the two expressions are
effectively different?
Thanks,
Let's have a look at some practical examples. Say, you have:
List<Number> list;
This means that whatever is assigned to this variable or field takes Number and outputs Number, so you always know what to expect. Integer can be added to this list since Integer extends Number. However, you can't assign, say, ArrayList<Long> to this list.
But consider this case:
List<? extends Number> list;
This one says: hey, that's a list of something that extends Number, but no one knows what exacty. What does this mean? This means that you can assign, for example, ArrayList<Long> to this list, which you couldn't in the first case. You still know that whatever this list outputs will be a Number, but you can't put an Integer in it anymore.
There is also an opposite case:
List<? super Number> list;
By printing that you say: that's a list of Number or its superclasses. This is where everything becomes vice-versa. The list can now refer to ArrayList<Object> and ArrayList<Number>. Now we don't know what this list will output. Will it be a Number? Will it be an Object? But now we know that we could put a Number in this list as well as any subclass of Number like Integer or Long.
There is a rule, by the way, which says producer extends, consumer super (PECS for short). If you need the list to output the values, it is a producer, this is the second case. If you need the list to accept values, it is a consumer, this is the third case. If you need both, don't use wildcards (that's the first case).
I hope this clears up matters.
This will explain the difference:
public class GenericsTest {
private ArrayList<A> la;
private ArrayList<? extends A> lexta;
void doListA(ArrayList<A> la) {}
void doListExtA(ArrayList<? extends A> lexta) {}
void tester() {
la = new ArrayList<SubA>(); // Compiler error: Type mismatch
doListA(new ArrayList<SubA>()); // Compiler error: Type mismatch
lexta = new ArrayList<SubA>();
doListExtA(new ArrayList<SubA>());
}
static class A {}
static class SubA extends A {}
}
As you see, calling a method and assigning a variable/instance field have the same rules. Look at the method call as an assignment of your argument to its declared parameter.
ArrayList<A> means a specific class A, where as ArrayList<? extends A> means class A or any class which extands A (Sub class of A) this make it more generic
Using private ArrayList<A> aList; as a variable declaration is not really equivalent to using the wildcard private ArrayList<? extends A> aList;
The wildcarded version will allow you to assign any ArrayLists of types that extend A and A itself but will refuse to add elements to the list as it cannot decide if it is type safe. With ArrayList<A> on the other hand you can only assign ArrayLists (or extensions of ArrayList) of type A and you can then add A elements and any elements extending A to it.
FYI: you should prefer using a more abstract type for declaring your variables/parameters like List<A> or Collection<A>.
The main difference is that if the generic form is used as an argument or return type in a method in a base class (or interface), it allows a greater range of type signatures to count as overriding instead of overloading.
Function override-overload in Java
For example, the following code is legal (in Java 7):
interface A
{
List<? extends Number> getSomeNumbers();
}
class B implements A
{
#Override
public ArrayList<Integer> getSomeNumbers()
{
return new ArrayList<>();
}
}
Difference between Enumeration<? extends ZipEntry> and Enumeration<ZipEntry>?
All of this means that sometimes you can write come code that requires less casts when someone else is using it. Which should not only reducing the amout of typing they have to do, but also eliminate possible failures.
Of course, the problem with Java generics is that they were introduced in a way that was constrained by backwards compatibility. So not everything works that you might think should, and the details get pretty hairy as to what exactly works and what doesn't.
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ812
It is hard to grasp at first, but inheritance doesn't apply with generics, ie if B extends A, List<B> is not a "subclass" of (can not be assigned to) List<A>. Further, List<? extends A> is not a "subclass" of (can not be assigned to) List<A>.