Reading the Java online tutorial I haven't understood anything about wildcard capture.
For example:
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
i.set(0, i.get(0));
}
}
Why can't the compiler retain the assignment safely?
It knows that, by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it tries to set an Integer value at index 0 to the same Integer list (i).
So, what's wrong? Why write Wildcard helper?
why the compiler can't retain the assignment safe? It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it try to set an Integer value at index 0 to the same Integer list (i).
Put differently, why does the compiler not know that the two usages of the wildcard type List<?> in
i.set(0, i.get(0));
refer to the same actual type?
Well, that would require the compiler to know that i contains the same instance for both evaluations of the expression. Since i isn't even final, the compiler would have to check whether i could possibly have been assigned in between evaluating the two expressions. Such an analysis is only simple for local variables (for who knows whether an invoked method will update a particular field of a particular object?). This is quite a bit of additional complexity in the compiler for rarely manifesting benefits. I suppose that's why the designers of the Java programming language kept things simple by specifying that different uses of the same wildcard type have different captures.
why the compiler can't retain the assignment safe?
The compiler doesn't know anything about the type of elements in List<?> i, by definition of ?. Wildcard does not mean "any type;" it means "some unknown type."
It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value.
That's true, but as I said above: the compiler can only know – at compile time, remember – that i.get(0) returns an Object, which is the upper bound of ?. But there's no guarantee that ? is at runtime Object, so there is no way for the compiler to know that i.set(0, i.get(0)) is a safe call. It's like writing this:
List<Foo> fooz = /* init */;
Object foo = fooz.get(0);
fooz.set(0, foo); // won't compile because foo is an object, not a Foo
More reading:
Can't add value to the Java collection with wildcard generic type
Java Collections using wildcard
Generic collection & wildcard in java
Generics - Cannot add to a List with unbounded wildcard
What is the difference betwen Collection<?> and Collection<T>
According to Get-Put principle:
If you have extends wildcard as in List<? extends Something>, then:
1A. You can get from the structure using Something or its superclass reference.
void foo(List<? extends Number> nums) {
Number number = nums.get(0);
Object number = nums.get(0); // superclass reference also works.
}
1B. You cannot add anything to the structure (except null).
void foo(List<? extends Number> nums) {
nums.add(1); Compile error
nums.add(1L); Compile error
nums.add(null); // only null is allowed.
}
Similarly, if you have super wildcard as in List<? super Something>, then:
2A. You can add to the structure which is Something or its subclass.
For eg:
void foo(List<? super Number> nums) {
nums.add(1); // Integer is a subclass of Number
nums.add(1L); // Long is a subclass of Number
nums.add("str"); // Compile error: String is not subclass of Number
}
2A. You cannot get from the structure (except via Object reference).
For eg:
void foo(List<? super Integer> nums) {
Integer num = nums.get(0); // Compile error
Number num = nums.get(0); // Compile error
Object num = nums.get(0); // Only get via Object reference is allowed.
}
Coming back to OP's question, List<?> i is just the short representation for List<? extends Object> i. And since it's a extends wildcard, the set operation fails.
The final piece remaining is WHY the operation fails ? Or why the Get-Put principle in the first place? - This has to do with type safety as answered by Jon Skeet here.
I also find this question hard to understand; splitting the single command into two commands helped me.
Below code is what actually happens in the background when the original method is inspected&compiled, the compiler makes its own local variable: the result of the i.get(0) call is placed in the register on the local variable stack.
And that is - for the understanding of this issue - the same as making a local variable which for convenience I have given the name element.
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
Object element = i.get(0); // command 1
i.set(0, element); // command 2
}
}
When command 1 is inspected, it can only set the type of element to Object (--> upperbound concept, see Matt's answer), as it can not use ? as a variable type; the ? is only used for indicating that the generic type is unknown.
Variable types can only be real types or generic types, but since you don't use a generic type in this method like <T> for example, it is forced to use a real type. This forcing is done because of the following lines in the java specification (jls8, 18.2.1):
A constraint formula of the form ‹Expression → T› is reduced as follows:
[...]
– If the expression is a class instance creation expression or a method invocation expression, the constraint reduces to the bound set B3 which would be used to determine the expression's invocation type when targeting T, as defined in §18.5.2. (For a class instance creation expression, the corresponding "method" used for inference is defined in §15.9.3).
Solution Will Be,
import java.util.List;
public class WildcardError {
private void fooHelper(List<T> i){
i.set(0, i.get(0));
}
public void foo(List<?> i){
fooHelper(i);
}
}
here fooHelper will capture type T of wildcard ? (so as the name wildcard capture).
I think you misunderstand the ? in Generics. It isn't "wildcard capture" at runtime. It is "wildcard capture" at compile time. Since that capture is gone after compilation, the List<?> often becomes List<Object> or a list of some interface or common base class that is the lowest subclass that is shared amongst the instances according to the Generics type.
Because Java had to make the Generics system compatible with non-Generics supporting JVMs, there are no Generics types at runtime. This means that all checks / captures don't exist at runtime. Either the compiler permits a very narrow range of compatible Generics type assignments when it compiles, or it throws an error.
Now if you want to hold a Generics type at runtime, there are approaches. Most of them involve passing the Class object as a parameter into a constructor, which holds it in a field. Then you can refer to the field for the exact passed type. You can entangle this type with your Generics parameters; and by doing so, you can then have the actual type in places in the runtime code where the "Generics type parameters" have been replaced by their most permissive type supported in the real Java type system. I don't recommend doing this for many situations, as it is a lot of work (and not likely to give you much more security); but, occasionally you really do need the type.
I guess your misunderstanding of the restriction comes from substitution of ? for any type, Object or something like that in your mind. But that assumption is not correct, ? in fact means unknown type. So in the following line
fooz.set(0, foo);
you're trying to assign the variable of some type to the variable of unknown type (since the function signature is like void set(int, ?)), which can never be possible, whatever the type of foo would be. In your case the type of foo is Object and you cannot assign it to a variable of some unknown type, which in fact may be Foo, Bar or any other.
Related
I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.
Suppose we have the following generic class
public class SomeType<T> {
public <E> void test(Collection<E> collection){
System.out.println("1st method");
for (E e : collection){
System.out.println(e);
}
}
public void test(List<Integer> integerList){
System.out.println("2nd method");
for (Integer integer : integerList){
System.out.println(integer);
}
}
}
Now inside main method we have the following code snippet
SomeType someType = new SomeType();
List<String> list = Arrays.asList("value");
someType.test(list);
As a result of executing someType.test(list) we will get "2nd method" in our console as well as java.lang.ClassCastException. As I understand, the reason of why second test method being executed is that we don't use generics for SomeType. So, compiler instantly removes all generics information from the class (i.e. both <T> and <E>). After doing that second test method will have List integerList as a parameter and of course List matches better to List than to Collection.
Now consider that inside main method we have the following code snippet
SomeType<?> someType = new SomeType<>();
List<String> list = Arrays.asList("value");
someType.test(list);
In this case we will get "1st method" in the console. It means that first test method being executed. The question is why?
From my understanding on runtime we never have any generics information because of type erasure. So, why then second test method cannot be executed. For me second test method should be (on runtime) in the following form public void test(List<Integer> integerList){...} Isn't it?
Applicable methods are matched before type erasure (see JSL 15.12.2.3). (Erasure means that runtime types are not parameterized, but the method was chosen at compile time, when type parameters were available)
The type of list is List<String>, therefore:
test(Collection<E>) is applicable, because List<Integer> is compatible with Collection<E>, where E is Integer (formally, the constraint formula List<Integer> → Collection<E> [E:=Integer] reduces to true, because List<Integer> is a subtype of Collection<Integer>).
test(List<String>) is not applicable, because List<String> is not compatible with List<Integer> (formally, the constraint formula List<String> → List<Integer> reduces to false because String is not a supertype of Integer).
The details are explained hidden in JSL 18.5.1.
For test(Collection<E>):
Let θ be the substitution [E:=Integer]
[...]
A set of constraint formulas, C, is constructed as follows: let F1, ..., Fn be the formal parameter types of m, and let e1, ..., ek be the actual argument expressions of the invocation.
In this case, we have F1 = Collection<E> and e1 = List<Integer>
Then: [the set of constraint formulas] includes ‹ei → Fi θ›
In this case, we have List<Integer> → Collection<E> [E:=Integer] (where → means that e1 is compatible with F1 after the type-variable E has been inferred)
For test(List<String>), there is no substitution (because there are no inference variables) and the constraint is just List<String> → List<Integer>.
The JLS is a bit of a rat's nest on this one, but there is an informal (their words, not mine) rule that you can use:
[O]ne method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.
For the sake of argument, let's call <E> test(Collection<E>) method 1, and test(List<Integer>) method 2.
Let's throw a spanner in here - we know that this entire class is generic, so instantiation of it without a type of some kind produces... less than desirable type checks at runtime.
The other part to this is due to the fact that List is more specific than Collection, if a method is passed a List, it will seek to accommodate that more readily than a Collection, with the caveat that the type should be checked at compile time. Since it isn't with that raw type, I believe that this particular check is skipped, and Java is treating List<Integer> as more specific than Collection<capture(String)>.
You should file a bug with the JVM, since this appears to be inconsistent. Or, at least, have the folks who penned the JLS explain why this is legal in slightly better English than their wonky math notation...
Moving on; with your second example, you give us the courtesy of typing your instance as a wildcard, which allows Java to make the correct compile-time assertion that test(Collection<E>) is the safest method to choose.
Note that none of these checks happen at runtime. These are all decisions made before Java runs, as ambiguous method calls or a call to a method with an unsupported parameter results in a compile time error.
Moral of the story: don't use raw types. They're evil. It makes the type system behave in strange ways, and it's really only there to maintain backwards compatibility.
How can I create a list with a specified type argument?
For example:
LinkedList<Integer> list = createList(LinkedList.class, Integer.class);
I've tried creating a method for it, but the method doesn't include the type argument when creating the new instance.
public static <T, L extends List<T>> L createList(Class<L> listClazz, Class<T> valueClazz) throws Exception
{
return listClazz.getConstructor().newInstance();
//Instead of
// new L<T>();
//does
// new L();
}
I hope my question is clear enough, thank you for any help.
You can't do that. Generics have no business at runtime, so you can't create parameterized instance at runtime using reflection. At runtime, LinkedList<Intege> is just a LinkedList. The type information - Integer is erased at compile time through "type erasure". The point is, why would you like to do that?
//Instead of
// new L<T>();
//does
// new L();
The two "do" exactly the same thing. How do you know it "does" one and not the other? Type parameters are compile-time illusions for type-checking. They are not relevant in what the code "does". To create an instance of LinkedList<T>, you do not need to know what T is, because it doesn't really exist after type erasure.
I think the issue you are having has nothing to do with the code inside the function, but with the signature of the method. By the very fact that the method is declared as it is, and you are passing an expression of type Class<LinkedList> (the type of LinkedList.class) to it, L must be LinkedList, and since the method returns L, the compiler must consider its return to by type LinkedList. None of this has anything to do with the code inside the method.
If you want the method's return type to be considered as LinkedList<Integer>, then just pass in an expression of type Class<LinkedList<Integer>>. Simple, right? How do you get an expression of type Class<LinkedList<Integer>>? For one, you could do (Class<LinkedList<Integer>>)(Class<?>)LinkedList.class.
If that seems kind of bogus, it's because Class is fundamentally a runtime thing -- it allows runtime creation of an object from that class. Using it with Generics, a compile-time type-checking mechanism, is fundamentally flawed. There is just one class object in existence for any class, e.g. LinkedList. Is it LinkedList or LinkedList<Integer> or LinkedList<String>? Well, it could be all of these, in the sense the the newInstance() method could create any of them (there is no difference at runtime).
I am currently studying Java and have recently been stumped by angle brackets(<>). What exactly do they mean?
public class Pool<T>{
public interface PoolFactory<T>{
public T createObject();
}
this.freeObjects = new ArrayList<T>(maxsize)
}
What does the <T> mean? Does it means that I can create an object of type T?
<T> is a generic and can usually be read as "of type T". It depends on the type to the left of the <> what it actually means.
I don't know what a Pool or PoolFactory is, but you also mention ArrayList<T>, which is a standard Java class, so I'll talk to that.
Usually, you won't see "T" in there, you'll see another type. So if you see ArrayList<Integer> for example, that means "An ArrayList of Integers." Many classes use generics to constrain the type of the elements in a container, for example. Another example is HashMap<String, Integer>, which means "a map with String keys and Integer values."
Your Pool example is a bit different, because there you are defining a class. So in that case, you are creating a class that somebody else could instantiate with a particular type in place of T. For example, I could create an object of type Pool<String> using your class definition. That would mean two things:
My Pool<String> would have an interface PoolFactory<String> with a createObject method that returns Strings.
Internally, the Pool<String> would contain an ArrayList of Strings.
This is great news, because at another time, I could come along and create a Pool<Integer> which would use the same code, but have Integer wherever you see T in the source.
It's really simple. It's a new feature introduced in J2SE 5. Specifying angular brackets after the class name means you are creating a temporary data type which can hold any type of data.
Example:
class A<T>{
T obj;
void add(T obj){
this.obj=obj;
}
T get(){
return obj;
}
}
public class generics {
static<E> void print(E[] elements){
for(E element:elements){
System.out.println(element);
}
}
public static void main(String[] args) {
A<String> obj=new A<String>();
A<Integer> obj1=new A<Integer>();
obj.add("hello");
obj1.add(6);
System.out.println(obj.get());
System.out.println(obj1.get());
Integer[] arr={1,3,5,7};
print(arr);
}
}
Instead of <T>, you can actually write anything and it will work the same way. Try writing <ABC> in place of <T>.
This is just for convenience:
<T> is referred to as any type
<E> as element type
<N> as number type
<V> as value
<K> as key
But you can name it anything you want, it doesn't really matter.
Moreover, Integer, String, Boolean etc are wrapper classes of Java which help in checking of types during compilation. For example, in the above code, obj is of type String, so you can't add any other type to it (try obj.add(1), it will cast an error). Similarly, obj1 is of the Integer type, you can't add any other type to it (try obj1.add("hello"), error will be there).
It is related to generics in java. If I mentioned ArrayList<String> that means I can add only String type object to that ArrayList.
The two major benefits of generics in Java are:
Reducing the number of casts in your program, thus reducing the number of potential bugs in your program.
Improving code clarity
is called a generic type. You can instantiate an object Pool like this:
PoolFactory<Integer> pool = new Pool<Integer>();
The generic parameter can only be a reference type. So you can't use primitive types like int or double or char or other primitive types.
<> is used to indicate generics in Java.
T is a type parameter in this example. And no: instantiating is one of the few things that you can't do with T.
Apart from the tutorial linked above Angelika Langers Generics FAQ is a great resource on the topic.
Generic classes are a type of class that takes in a data type as a parameter when it's created. This type parameter is specified using angle brackets and the type can change each time a new instance of the class is instantiated. For instance, let's create an ArrayList for Employee objects and another for Company objects
ArrayList<Employee> employees = new ArrayList<Employee>();
ArrayList<Company> companies = new ArrayList<Company>();
You'll notice that we're using the same ArrayList class to create both lists and we pass in the Employee or Company type using angle brackets. Having one generic class be able to handle multiple types of data cuts down on having a lot of classes that perform similar tasks.
Generics also help to cut down on bugs by giving everything a strong type which helps the compiler point out errors. By specifying a type for ArrayList, the compiler will throw an error if you try to add an Employee to the Company list or vice versa.
I saw a java function that looked something like this-
public static<T> foo() {...}
I know what generics are but can someone explain the in this context? Who decides what T is equal to? Whats going on here?
EDIT: Can someone please show me an example of a function like this.
You've missed the return type out, but apart from that it's a generic method. As with generic types, T stands in for any reference type (within bounds if given).
For methods, generic parameters are typically inferred by the compiler. In certain situations you might want to specify the generic arguments yourself, using a slightly peculiar syntax:
List<String> strings = Collections.<String>emptyList();
In this case, the compiler could have inferred the type, but it's not always obvious whether the compiler can or can't. Note, the <> is after the dot. For syntactical reasons the type name or target object must always be specified.
It's possible to have generic constructors, but I've never seen one in the wild and the syntax gets worse.
I believe C++ and C# syntaxes place the generic types after the method/function name.
The context is a generic method as opposed to a class. The variable <T> applies only to the call of the method.. The Collections class has a number of these; the class itself is not generic, but many of the methods are.
The compiler decides what T is equal to -- it equals whatever gets the types to work. Sometimes this is easier then others.
For example, the method static <T> Set<T> Collections.singleton(T o) the type is defined in the parameter:
Collections.singleton(String T)
will return a Set<String>.
Sometimes the type is hard to define. For example sometimes there is not easily enough information to type Collection.emptyList(). In that case you can specify the type directly: Collection.<String>emptyList().
T it's the formal type parameter wich will be replaced by the actual type
argument used at the instantiation of the object.
For example, here is the List and Iterator definitios in package java.util:
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
boolean hasNext();
}
Then you can instantiate a List this way:
List<String> ls = new ArrayList<String>()
Where you might imagine that List stands for a version of List where E has
been uniformly replaced by String:
public interface StringList{
void add(String x)
Iterator<String> iterator();
}