How does Java's generics work? - java

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.

Related

Is it possible to use the provided Java Collections methods, like max, min, sort, ect..., on a Stack?

I was working on a problem involving Stacks on HackerRank (See Here). One of the parts of the question asked to provide the max value within the Stack. I thought an easy way to do this was to just write an extended Stack class with a max() method (see below). That worked but I thought an even easier way might be to just take advantage of Java's Collections methods. So I built the craftyMax() method (also seen below).
class MyStack<T> extends Stack<T> {
public T craftyMax() {
return Collections.max(this);
}
public T max() {
Integer max = Integer.MIN_VALUE;
for (T item: this) {
max = Math.max((Integer)item, max);
}
return (T) max;
}
}
Of course this did not work as the compiler replied with:
Solution.java:6: error: no suitable method found for max(MyStack<T#1>)
return Collections.max(this);
^
method Collections.<T#2>max(Collection<? extends T#2>) is not applicable
(inferred type does not conform to upper bound(s)
inferred: T#1
upper bound(s): Comparable<? super T#1>,Object)
method Collections.<T#3>max(Collection<? extends T#3>,Comparator<? super T#3>) is not applicable
(cannot infer type-variable(s) T#3
(actual and formal argument lists differ in length))
where T#1,T#2,T#3 are type-variables:
T#1 extends Object declared in class MyStack
T#2 extends Object,Comparable<? super T#2> declared in method <T#2>max(Collection<? extends T#2>)
T#3 extends Object declared in method <T#3>max(Collection<? extends T#3>,Comparator<? super T#3>)
Note: Solution.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
Since, I have tried a few different things and been looking around but I can't seem to find if what I am trying to do here is possible or not. So my question is:
Is it possible to use the provided Java Collections methods, like max, min, sort, ect..., on / within a Stack? Or am I expecting a little too much?
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
only works for Collections whose element type implements the Comparable interface.
Therefore, your code will work with the proper type bound:
class MyStack<T extends Comparable<T>> extends Stack<T> {
public T craftyMax() {
return Collections.max(this);
}
}
I'm not sure about your second method (max()), though. You are casting T to Integer. If you are certain T is an Integer, why not define MyStack as class MyStack extends Stack<Integer>?
You can only call Collections.max with a single argument on types that implement the Comparable interface. Change your type declaration to
class MyStack<T extends Comparable<T>> extends Stack<T> {
and it should work. Or, as an alternative, you can take the two-argument max that takes a Comparator as the second argument.
you can override the comparator to match your functionality like below.
if (!MyStack.isEmpty()) {
Integer max = Collections.min(MyStack, new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
}

Usage of super in method declaration

I would like to understand what this Java declaration is doing:
public static <AnyType extends Comparable<? super AnyType>> int mymethod( AnyType x ) {
/* ... */
}
From my basic knowledage of Java, I think all it's doing is telling you that the param x must be of any type, but that type must extend Comparable?
Your understanding is correct. This method indicates that it takes an argument of a type that extends a Comparable (Note that I would have called the type parameter T instead of AnyType for readability).
Now for the super in Comparable<? super AnyType>>, it means that this comparable implementation can actually be, for example, an implementation of Comparable<Object>, that is a comparable type that can be compared to an object. More generally, the type accepted by the method can be a Comparable which can be compared to some type that is a superclass or superinterface of it, hence the keyword super. In other words, the method can be invoked as follows:
// An object of this type can be compared to an Object
class X implements Comparable<Object> {
#Override
public int compareTo(Object o) {
...
}
}
X x = new X();
mymethod(x);
This is a generic method, i.e. its type parametrization is not related to the class' parametrization if any.
The <AnyType extends Comparable<? super AnyType>> part is the generic parametrization of the method.
The extends keyword should not be confused with the extends keyword when declaring a class: in this case it looks more like "is assignable from", in other words, IS-A.
Comparable<T> is an interface - see docs here.
Your method parametrization will make it so that your method accepts any parameter, as long as its type implements Comparable.
Specifically, it needs to be a Comparable of itself or any super-type (that's what the super part means, as opposed to extends).
For instance, you can pass a String argument because String implements Comparable<String> (amongst others).
Yes, parameter must be a sub-type of Comparable.

Java Self-Referential Generics With Wildcards

Is it possible to specify that an unknown generic type is self-referential?
A failed attempt:
import java.util.*;
class Generics {
public enum A { A1, A2 }
public enum B { B1, B2 }
public static List<? extends Enum<?>> listFactory(String[] args) {
if (args.length == 0) {
return new ArrayList<A>(Arrays.asList(A.A1, A.A2));
} else {
return new ArrayList<B>(Arrays.asList(B.B1, B.B2));
}
}
public static void main(String[] args) {
List<? extends Enum<?>> lst = listFactory(args);
dblList(lst);
System.out.println(lst);
}
public static <EType extends Enum<EType>> void dblList(List<EType> lst) {
int size = lst.size();
for (int i = 0; i < size; i++) {
lst.add(lst.get(i));
}
}
}
This results in a compilation error:
Generics.java:17: error: method dblList in class Generics cannot be applied to given types;
dblList(lst);
^
required: List<EType>
found: List<CAP#1>
reason: inferred type does not conform to declared bound(s)
inferred: CAP#1
bound(s): Enum<CAP#1>
where EType is a type-variable:
EType extends Enum<EType> declared in method <EType>dblList(List<EType>)
where CAP#1 is a fresh type-variable:
CAP#1 extends Enum<?> from capture of ? extends Enum<?>
1 error
Ideally, the return type of listFactory() would signal that the list contains self-referential generic types (whose exact type is unknown).
Is this possible? If so, what should the types of listFactory() and lst be?
Effective Java Item 28 discourages using wildcards in return types:
Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code.
Properly used, wildcard types are nearly invisible to users of a class. They cause methods to accept the parameters they should accept and reject those they should reject. If the user of a class has to think about wildcard types, there is probably something wrong with the class's API.
This is a good example of exactly the issues EJ describes. listFactory() is really just returning a List<Enum<?>> but by declaring a wildcard return type you have to jump through hoops to accomplish seemingly simple tasks.
If you instead give listFactory() a signature like so:
public static List<Enum<?>> listFactory(String[] args)
You can clean up the signature of dblList() too:
public static <E> void dblList(List<E> lst)
In Java, a type argument is either a concrete type, a wildcard type, or a type variable. A concrete type is not flexible enough for your use case, and wildcards can not be constrained to be self referential (because each occurrence of a wildcard can stand for a different type).
This leaves type variables, which can be constrained to be self referential, but are provided by the caller of the constructor or method, not the callee, so we can't just do:
<E extends Enum<E>> List<E> listFactory(String[] args);
because somebody might invoke this with an incorrect type argument.
One way to work around this is to decorate the return type:
interface EnumList<E extends Enum<E>> extends List<E> {
}
EnumList<?> listFactory(String[] args);
A caller can then do:
EnumList<?> x = listFactory(args);
dblList(x);
where dblList uses wildcard capture to manipulate the list:
<E extends Enum<E>> void dblList(List<E> list);
It is worth noting that this makes the method signatures quite a bit harder to write, so you should only do this if the method in question actually needs to know that the type is self referential. I mention this because your dblList method does not, and could simply be written as:
<E> void dblList(List<E> list);
instead.

Benefits of using ? instead of T for type parameter in Java generics? [duplicate]

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.

Compiler thinks Comparable type is not Comparable

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

Categories

Resources