Java Generics Curiosity - java

I have an interface A, which class B implements.
The following generic method works
public static <T, U extends T> List<T> listFactory(Collection<U> source) {
return new ArrayList<T>(source);
}
but
public static <T> List<T> listFactory(Collection<? extends T> source) {
return new ArrayList<T>(source);
}
does not (compilation error, type mismatch), when I am directing the output into
List<A> tester = listFactory(B.defaultCollectionFactory(3));
defaultCollectionFactory(int count) statically provides a collection of Bs, with a default labeling scheme.
Any insights as to why that is? It seems like the generic U and wildcard are doing the same thing.

The compiler is inferring a different type parameter for the listFactory method than you expect. It infers that T is type B, so the signature is effectively List<B> listFactory(Collection<? extends B> source). Specify the type parameter A by being explicit in the method invocation:
List<A> tester = Test.<A> listFactory(B.defaultCollectionFactory(3));

In the first construct, you are specifying that you are returning a List of the interface of the item that was passed in. You specify the relationship between the passed in Object and the return Object type in the U extends T direction. In this case, the compiler can associate A and B with T andU respectively.
In the second, there is no such differentiation, so the compiler assumes that T refers to B and will type the return value as List<B>. You then fall into the trap where, although B is an instance of A, List<B> is not an instance of List<A>. The compiler will complain:
Type mismatch: cannot convert from List<B> to List<A>
You will find that, with the first construct, you have the liberty of specifying a List of any interface the B implements or any superclass in the B hierarchy (List<Object>, for example), and the compiler will not complain.

Related

Java Generics Type Inference Confusion

All,
To test the Java Generics Type Inference I created below sample code.
public static <U> U addBox2(U u1, U u2) {
return u2;
}
static interface A {}
static interface B {}
static class S {}
static class C extends S implements A,B {}
static class D extends S implements B,A {}
If you see above A and S have no relationship.
In the code below -
A a = addBox2(new C(),new D());
I was hoping to receive the compilation error since the type inferred was S and I am assigning it to A and A and S has no relationship still this worked just fine.
Can someone help me explain why this behavior?
As requested:
A and S don't have a relationship indeed but since you pass a C and D to the method and both implement A (and B) they have something in common, i.e. they both are As.
That means the following would work:
A a = addBox2(new C(),new D()); //common type is A
B b = addBox2(new C(),new D()); //common type is B
S s = addBox2(new C(),new D()); //common type is S
Object o = addBox2(new C(),new D()); //common type is Object
As long as type inference can solve the generic type from the assignment as well as the parameters it should work (note that type inference isn't as good in Java versions prior to 8, especially in 5 and 6).
You can, however, define the type yourself by passing it to the method call:
A a = EnclosingClass.<S>addBox2(new C(),new D()); //static method within EnclosingClass
A a = this.<S>addBox2(new C(),new D()); //instance method
In both cases you define the generic type to be S and thus the assignment won't work.
Type parameter U is inferred from the type of the a variable you are assigning the result of addBox2(...) to, which in your case is A. As both C and D implement A it works flawlessly.
The following of course won't work:
S s = addBox2(new C(),new D());
A a = s; // compile error, type mismatch
I suspect Eclipse and IntelliJ aren't annotating these properly. With this (slightly tweaked) example:
public static <U> U getU(U u1, U u2) {
return u2;
}
static interface A {}
static class S {}
static class C extends S implements A {}
static class D extends S implements A {}
static class T implements A {}
public static void main(String[] args) {
A a = getU(new C(), new D());
A b = getU(new C(), new T());
}
I see the following when I mouse-over the first call to getU() in main():
<? extends S> ? extends S analysis.Delme.getU(? extends S u1, ? extends S u2)
Which is clearly not correct - A does not extend S. I suspect Eclipse is mistakenly oversimplifying the generics here, and preferring to report that C and D both extend from S, rather than both implement A.
If I mouse-over the second call I instead get the much more reasonable:
<A> A analysis.Delme.getU(A u1, A u2)
Which is presumably what the compiler is actually doing here for both calls.
Note as Thomas points out, even if two classes have nothing in common (such as S and T) they still extend from Object, so Object c = getU(new S(), new T()); is valid.
Don’t trust the tooltip of an editor that might not cope with complex generic constructs. The inferred type is S & A & B (before Java 8), which can be assigned to A. In Java 8, the inferred type is just A, as generic method invocations are so-called poly expressions using the target type. For your addBox invocation, it makes no difference.
To illustrate the issue, you may write
Object o = Arrays.asList(new C(), new D());
in Eclipse using Java 7 compliance mode, and hover the mouse over asList. It will print
<? extends S> List<? extends S> java.util.Arrays.asList(? extends S... a), similar to the addBox invocation of your question, but when you change the code to
List<A> list = Arrays.asList(new C(), new D());
you get the compiler error “Type mismatch: cannot convert from List<S&A&B> to List<A>” (still in Java 7 mode), showing that the actual inferred type is S & A & B, not ? extends S.
When you turn the language compliance level to Java 8, the compiler error will go away, as in Java 8, the target type will be used to infer the type, which will be A instead of S & A & B.
As said, for your addBox invocation, it makes no difference whether A or S & A & B is inferred, as both can be assigned to A, so it works under both, Java 7 and Java 8 compliance level. But when you use an invocation, where it makes a difference, like with Arrays.asList, you can see the actually inferred type, which is never ? extends S as the editor’s tooltip claims…

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.

Java generics type deduction error

I've come across error with what I thought would have been a straight forward deduction where a method using generics specifies a version of a generic class as one parameter and for a second parameter it specifies something of the type used for the version of the previous parameter.
static class GenericClass<T0>
{
T0 getT()
{
return null;
}
static <T1> void func3( GenericClass<T1> a, T1 b )
{
}
}
void testcase( GenericClass<? extends Integer> a )
{
GenericClass.func3( a, a.getT() );
}
Unfortunately it shows as an error:
"The method func3(GenericClass<T1>, T1) in the type GenericClass is not applicable for the arguments (GenericClass<capture#6-of ? extends Integer>, capture#7-of ? extends Integer)"
However this change to the header of func3 works.
static <T1> void func3( GenericClass<? extends T1> a, T1 b )
and so does this change to the header of the testcase method.
void testcase( GenericClass<Integer> a )
Even if the testcase header doesn't give a concrete type for the class, the class specifies the return type will be the same as its generic type so why does the error message suggest they are potentially two different types?
This example isn't obvious because Integer is final, so let's take an example where Parent has two subclasses, Foo and Bar.
? extends Parent means some specific subtype of Parent. So GenericClass<Foo> and GenericClass<Bar> could be used where a GenericClass<? extends Parent> is expected.
Here
static <T1> void func3( GenericClass<T1> a, T1 b )
you have a generic method where the generic type parameter is used in both parameter declarations. The compiler must guarantee that the type is correct in both provided arguments during a method invocation.
Given this
GenericClass<? extends Parent> a = ...;
GenericClass.func3( a, a.getT() );
it has no way to do that. You must first understand that Java doesn't know that both those arguments come from the same source. All it looks at is their types.
The first argument is of type GenericClass<? extends Parent> while the second argument is of type ? extends Parent. Consider the following
GenericClass<? extends Parent> a = new GenericClass<Foo>(someFoo);
GenericClass<? extends Parent> b = new GenericClass<Bar>(someBar);
GenericClass.func3( a, b.get());
The two arguments have the exact same compile time type as the method call above, but it is easier to see why it would fail. It cannot guarantee that T will be bound to the same type for both arguments. It must therefore fail.

What is causing this compile error with java Generics and reflection?

I have a Generic method that should work similarly to recursion, but calling different instances of the method for each calling.
public <M extends A> void doSomething(Class<M> mClass, M mObject)
{
// ... Do something with mObject.
A object = getObject();
Class<? extends A> objectClass = object.getClass();
doSomething(objectClass, objectClass.cast(object)); // Does not compile.
}
private A getObject() {...}
The problem is the line with a comment does not compile, giving the following error:
The method doSomething(Class, M) in the type MainTest is not applicable for the arguments (Class, capture#3-of ? extends A)
I don't quite understand why the compiler does not compile if it can call doSomething with M = "? extends A".
Why doesn't it compile?
Ok here is a crude explanation
You've typed your method so that it will accept M which is a subtype of A
Now you are calling your method using 'objectClass' which is a subtype of A BUT not necessarily a subtype of M.
Hence the compiler is complaining...
If you can explain what you are trying to do a bit more, I can help with a solution.
The language does not track wildcards like that (it seems). What you need to do is to capture that wildcard, which can be done with a method call with type inference.
public <M extends A> void doSomething(Class<M> mClass, M mObject) {
// ... Do something with mObject.
A object = getObject();
Class<? extends A> objectClass = object.getClass();
privateSomething(objectClass, object);
}
private <T extends A> void privateSomething(Class<T> objectClass, A object) {
doSomething(objectClass, objectClass.cast(object)); // Should compile.
}
As always, whilst reflection has some uses, it's usually a sign of confusion.
When you are asking the compiler to perform a cast, the exact type to perform the cast must be known. It is not sufficient to tell the compiler that you don't know about the exact type excerpt that it's a subclass of A.
Class tell the compiler that the type of the object is a subclass of A but it doesn't tell the compilator the exact type to be used for the casting.
Your problem is that you are trying to replace Polymorphism with Generic. As you are learning the hard way, Generic is not the new modern way of doing Polymorphism.

Why is there an extra <E> in this generic method?

I learned java generics some time ago, but now I'm learning collections and found some code that I don't understand. Here is the code:
static <E> List<E> nCopies(int n, E value)
It is from class java.util.Collections.
My question is why there is:
<E> List<E>
and not only
List<E>
Obviously I am missing something, can someone clarify this for me?
You use the <E> to typify the method you are defining.
The most common example of generics is to have a typified class like this:
public class SomeClass<E> {
...
}
Then, when you are creating a new object of that class you define the type directly like this:
new SomeClass<String>();
That way any method in that class that refers to <E>, will treat <E> as a String, for that instance.
Now consider a static method (which is not bound to any particular instance of a class), in order to typify that method you have use another kind of typification which applies to methods, like this:
static <E> List<E> nCopies(int n, E value)
You use the <E> before the return type to say "this particular method will consider some E when it executes". What <E> will be is decided when you invoke the method:
nCopies(3, "a");
In this example <E> will be a String, so the return type will be a List<String>.
Finally, you can even mix them both:
public class SomeClass<E> {
public <F> void doSomething(E e, F f) {
...
}
}
In this case, if you have an instance of SomeClass, the E in the doSomething method will always be String (for that instance), but the F can be anything you want it to be.
In <E> List<E>, the first <E> denotes that E is a type parameter. If you hadn't specified it, then Java would think the E in E value referred to an actual class named E, and ask you to import it. See generic methods.
The <E> is required to tell the compiler that you intend to use E as a type parameter, the same way you do when you make a generic class (e.g. public interface List<E>).
Since there is no rule (only conventions) on interface or class names being more than one character, and no rule (only conventions) that type parameter names have to be one character, the compiler would not know you intended it to be a type parameter rather than a concrete class name.
Edit
A lot of people have been saying this is directly related to static methods. That is not true. You can have an instance method that is generic on its own type parameters as well (though typically, the type parameters will be related to the class type parameters).
Here's an example of where you could have this:
public class MyList<E> {
public <N super E> MyList<N> createCopy() {
//...
}
}
This method would allow you to create a copy of the list but not restrain you to using the same type as the list you have, but rather allowing you to use a supertype. For example:
MyList<Integer> integers = createList(1, 2, 5);
MyList<Number> numbers = integers.createCopy();
List<E> is the return type for the method whereas <E> is the type being passed in (This is inferred by the compiler from what is being passed as E value).
static <E> List<E> someMethod(E myObject)
{
E objectOfMyType = myObject;
List<E> myList = new ArrayList<E>();
...
return myList;
}
This would be called as:
MyObject o = new MyObject();
List<MyObject> myList = SomeClass.someMethod(o);
IMHO the syntax for methods is kinda goofy, but there you have it. The relavent Oracle tutorial is here:
http://download.oracle.com/javase/tutorial/extra/generics/methods.html
in simple words: to indicate that E is not a class. List<E> would be a valid return type if E was a class (or interface) - despite not recommended, a class can be named with a single letter (as a type variable also could be named with more letters, even using an existing class name, to confuse anyone: static <Integer> List<Integer> method() {...}).

Categories

Resources