This is an Android app, but presumably it happens the same in Java. I have a type LevelFactory from which I derive Level1Factory, Level2Factory, etc. I want to have an array of these classes so I can instantiate a level given the array index.
I can just have a Class[] and put them in that and then just cast them to LevelFactory when I need to use them, but I was wondering what the proper thing to do is.
This is obviously an error "Incompatible types":
new Class<LevelFactory>[] {Level1Factory.class,Level2Factory.class};
However, I was surprised to see that this is also an error "Generic array creation":
new Class<? extends LevelFactory>[] {Level1Factory.class,Level2Factory.class};
The following works, but it gives the "Unchecked assignment" warning when assigned to a variable:
new Class[] {Level1Factory.class,Level2Factory.class};
The last is the only option I can get to work. I just ignore the warning, but I would like to do it using generics if that's actually possible.
I would recommend you to read Item 25 "Prefer lists to arrays" of book "Effective Java". There Joshua Bloch writes:
Why is it illegal to create a generic array? Because it isn’t typesafe. If it were
legal, casts generated by the compiler in an otherwise correct program could fail at
runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system.
UPD: Maybe with concrete example it would be more understandable.
First of all arrays are covariant which means that SuperClass[] can be cast to SubClass[] and vice versa. It also means that it's legal to cast AnyConcreteClass[] to, say, Object[].
So Let's assume that it's possible to have Set<Cat>[] (but it is NOT). If somebody cast this array to Object[] and then add there a set of Dog instances, Java couldn't guarantee anymore that our array contains only sets of Cat instances. Breaking type safety it breaks essence of generics. That is why it's illegal have generic array.
Set<Cat>[] cats = new Set<Cat>[]; // illegal
Object[] objects = cats;
objects[1] = new Set<Dog>();
cats[1].add(new Cat()); // Oops! TypeCastException
Honestly saying this example also was taken from Effective Java :)
Two questions:
Do you really need an Array? Arrays don't work great with generics. So an ArrayList<LevelFactory> might be the better solution
Do you really need the downcast to the special type (Level1Factory, Level2Factory)? If they have a common super method which is defined in LevelFactory (lets say Level getLevel()) you should not need to downcast them. Just call getLevel() and you get the correct Level instance from your factory.
Another note because this seems to be a common pitfall:
new Class<? extends LevelFactory>
This is not a valid statement (it does not matter if its an array or not). <? extends T> is only valid for the type on the left side. It defines that the generic type of the created Object can be T or derived from T. For Collections this does not mean that they can store objects of T or derived from T (which can a Collections of T anyway).
List<LevelFactory> list = new ArrayList<LevelFactory>() This means you can add objects of LevelFactory, Level1Factory and Level2Factory to list. When you want to receive objects from list they are of type LevelFactory.
List<? extends LevelFactory> list = new ArrayList<LevelFactory>() Means you can receive objects of LevelFactory from list. BUT you cannot add any object to list in a typesafe way because you don't know the exact generic type of list. That because you can also assign new ArrayList<Level1Factory>() to list. Which means that you can't even add LevelFactory objects to list because they don't implement Level1Factory.
In general <? extends Something> on collections is not what you want in most cases.
You can't create array this way new SomeClass<Type>[10] but only this way new SomeClass[10]. Consider using ArrayList<SomeClass<Type>> instead.
Related
I have seen in multiple different places people who instantiate a list or ArrayList like:
List<?> l = new ArrayList<>();
What type is ?? Does this mean that it can hold any types in it? If so, why would this be used instead of just and ArrayList?
Does this mean that it can hold any types in it?
No. It means that your l variable could be referring to a list parameterized with any type. So it's actually a restriction: you will not be allowed to add any object to l because you have no idea which items it accepts. To give a concrete example, l could be a List<String> or it could be a List<ExecutorService>.
As correctly pointed by Marko, its an unknown restriction on the List type.
The Java docs says that:
The unbounded wildcard type is specified using the wildcard character
(?), for example, List<?>. This is called a list of unknown type.
There are two scenarios where an unbounded wildcard is a useful
approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear.
In fact, Class<?> is so often used because most of the methods in
Class do not depend on T.
Let me make this a long bed time story; read it to fall asleep:)
Let's begin with this point -- To invoke a generic method, its type arguments must be supplied. (Unless the method is invoked in a "raw" manner, i.e. in the erased form, which is another topic:)
For example, to invoke Collections.<T>emptyList(), T must be supplied. It can be supplied explicitly by the programmer --
List<String> list = Collections.<String>emptyList(); // T=String
But that is tedious, and kind of dumb. Obviously in this context, T can only be String. It's stupid if the programmer has to repeat the obvious.
That's where type inference is helpful. We can omit the type argument, and the compiler can infer what the programmer intends it to be
List<String> list = Collections.emptyList(); // T=String is implied
Remember, <String> is still supplied, by the programmer, implicitly.
Supposedly, the programmer is the all-knowing dictator of all type arguments, and, the compiler and the programmer have a common understanding on when type arguments can be omitted and inferable from context. When the programmer omits a type argument, he knows the compiler can infer it exactly as he intended, based on a rigorous algorithm (which he masters:)
It is not the compiler's discretion to pick and choose type arguments, rather, the programmer does, and conveys it to the compiler.
Realistically, type inference is so complex, few no programmer has any idea what's going on in a lot of cases:) The programmer is more like a dictator making vague commands, and the compiler tries its best to make sense out of it. We mostly write code on intuition, not paying attention to details, and we sort of believe that the code does what we want if the compiler approves it.
In any case, all type arguments are fixed precisely and predictably at compile time. Any omitted type argument is equivalent to an explicitly specified one.
Some type arguments are "undenotable", e.g. a type variable introduced by capture conversion. They can not be explicitly specified, they can only be inferred. (Nevertheless the programmer is supposed to know what they are, even though they cannot be named)
In the previous example, T can only be inferred as String, there's no other choices. But in a lot of cases, there are more candidates for T, and the type inference algorithm must have a strategy to resolve it to one of the candidates. For example, consider this lonely statement
Collections.emptyList();
T could be any type; T is resolved to Object, because, well, there's no good reason to resolve it to anything else, like Integer or String etc. Object is more special because it's the supertype of all.
Now, let's get to constructors. Formally speaking, constructors are not methods. But they are very much alike in a lot of aspects. Particularly, type inference on constructors is almost the same as on methods. Invoking a constructor of a class CLASS takes the form of new CLASS(args).
Just like methods, a constructor can be generic, with its own type parameters. For example,
class Bar
{
<T>Bar(T x){ .. }
and type inference works on generic constructors too
new Bar("abc"); // inferred: T=String
To explicitly supply type arguments for a constructor,
new <String>Bar("abc");
It's pretty rare though that a constructor is generic.
A generic constructor is different from a generic CLASS! Consider this
class Foo<T>
{
Foo(T x){ .. }
The class is generic, the constructor is not. To invoke the constructor for class Foo<String>, we do
new Foo<String>(""); // CLASS = Foo<String>
Method type inference we've been talking about so far does not apply here, because the constructor is not even generic. In Java 5/6, there is no type inference on CLASS, therefore <String> must be explicitly specified. It's stupid, because <String> is obvious in this context. There were workarounds (i.e. using static factory methods), but people were of course very upset and demanded a solution.
In Java 7, this problem is solved by "diamond inference" -
new Foo<>(""); // inferred: T=String
"diamond" refers to the curious <> operator. It is required; we cannot simply write
new Foo("");
because that already had a different meaning - invoking the constructor of "raw" Foo.
With diamond inference, we can do things we couldn't in Java 5/6
List<Object> list = new ArrayList<>(); // Java 7. inferred: E=Object
// equivalent to
List<Object> list = new ArrayList<Object>(); // <Object> is required in Java 5/6
Remember, T=Object is still supplied, through diamond inference.
Finally, we come back to your original question
List<?> list = new ArrayList<>();
Here, E=Object is inferred (what else?). The code is equivalent to
List<?> list = new ArrayList<Object>();
Yep, the list object is indeed an ArrayList<Object>, not ArrayList<SomethingElse>.
Also note that the following would be illegal and nonsensical
List<?> list = new ArrayList<?>();
^^^
CLASS in new CLASS(args) must be a concrete type. We can only instantiate an ArrayList of a specific element type.
The declared type List<?> of variable list is too general though. For a local variable, it is the best practice IMO to declare it in its more specific type
ArrayList<Object> list = new ArrayList<>();
Don't use <?> here - it just causes confusion to everybody.
On a related note, a lot of people would argue for "program against interface"
List<Object> list = new ArrayList<>();
^^^^
That is wrong IMO. Who are we providing abstraction for in a local block? Use the most specific type in implementation for max clarity;
use abstract types in interfaces.
zzzzzzzzzz
I have seen a lot of cases where in, the ? type is used only to create references. And we are not able to add any Objects other than null. So, is the use of '?', only to create references?
Also, what is the need / use of giving the option to add a null? They could simply have implemented with no add() method at all, right? Any reason for giving the option of adding null into List < ? > ?
List is a generic interface, and the same interface regardless of the generic type. As such, all implementors are required to redefine all methods in it. As far as being able to add null into an "unbounded" list, it's not as much a matter of methods as much as a requisiste of respecting the interface:
the unbound generic wildcard allows a reference to a List (or other generic class) to be passed around to methods without requiring a compile-time knowledge of the specific type it will contain. However, the contract of the generic must still be respected. This poses no big problem for read operations, since whatever is in the List, it will always (also) be a java.lang.Object. On the other hand, insert operations are almost impossible, since lacking informations about the accepted types, no type can be accepted - e.g. a List can only accept strings, but an Object could be anything else - a Number for example, and thus cannot be accepted safely.
Null works safely since (assuming the List accept null values), it will be the only value that's always valid to be put inside the list (a null can be cast to any valid type).
Edit: just since i noticed i didn't actually answer your question: yes, the <?> wildcard (and the extended forms as well <? extends X> and <? super X> are only valid when defining references, and cannot be used in generic instantiation.
Firstly, null is a member of all types. That's part of the language specification that pre-dates generics, so you can' do anything about that.
As for the use of ?, you can't * instantiate* a wildcard-typed generic class, that you can't do this:
List<? extends Number> list = new ArrayList<? extends Number>(); // error
because it does't make sense. The wildcard type is used to tell the compiler "I don't know what the type of the list will be, but it will be bounded by Number". However, when the code executes, a List with a type bounded by Number will be assigned to the variable.
Wildcards are most often seen as parameters:
public static void doSeomthing(List<? extends Number> list) {
// use the list knowing only that the elements are a subclass of Number
// but knowing which exact class they are
}
I'm writing a small API to deal with objects that have specific 'traits' In this case, they all have an interval of time and a couple of other bits of data, So I write an interface TimeInterval with some getters and setters.
Now most of these API methods deal with a Set or List of Objects. Internally these methods use the Java Colletions Framework (HashMap/TreeMap in particular). So these API methods are like:
getSomeDataAboutIntervals(List<TimeInterval> intervalObjects);
Couple of Questions:
a) Should this be List<? extends TimeInterval> intervalObjects instead?
Is it mostly a matter of style? The one disadvantage of taking strictly an interface that I can see is, you need to create your list as a List<TimeInterval> rather than List<ObjectThatImplementsTimeInterval>.
This means potentially having to copy a List<Object..> to List<TimeInterval> to pass it to the API.
Are there other pros & cons to either approach?
b) And, one dumb question :) The collections framework guarantees I always get out the same instance I put in, the collections are really a collection of references, correct?
1) Yes.
Method parameters should be as general as possible. List<? extends A> is more general than List<A>, and can be used when you don't need to add things to the list.
If you were only adding to the list (and not reading from it), the most general signature would probably be List<? super A>
Conversely, method return types should be as specific as possible. You rarely to never want to return a wildcard generic from a method.
Sometimes this can lead to generic signatures:
<T extends MyObject> List<T> filterMyObjects(List<T>)
This signature is both as specific and as general as possible
2) Yes, except possibly in some rare very specific cases (I'm thinking of BitSet, although that isn't technically a Collection).
If you declare your list as List<? extends A>, then you can pass in any object which static type is List<X>, where X extends A if A is a class, or X implements A id A is an interface. But you'll not be able to pass in a List or a List<Object> to it (unless A is Object) without force-casting it.
However, if you declare the parameter as a List<A>, you'll only be able to pass lists which static type is strictly equivalent to List<A>, so not List<X> for instance. And by "you are not able to do otherwise", I really mean "unless you force the compiler to shut up and accept it", which I believe one should not do unless dealing with legacy code.
Collections are really collections of references. The abstraction actually is that everything you can put in a variable is a reference to something, unless that variable is of a primitive type.
1) I would recommend ? extends TimeInterval. Because of Java's polymorphism, it may not actually make a difference, but it is more robust and better style
2) Yes
a) No. List<? extends TimeInterval> will only accept interfaces that extend the interface TimeInterval. Your assertion that "you need to create your list as a List<TimeInterval> is wrong, unless I misunderstand your point. Here's an example:
List<List> mylist= new ArrayList<List>();
mylist.add(new ArrayList());
b) Yes.
Should this be List intervalObjects instead?
You only do that if you want to pass in a List<TimeIntervalSubclass>. Note you can put instances of subclasses of TimeInterval into a List<TimeInterval>. Keep in mind that the type of the list is different than the types in the list.
If you do List<? extends A> myList -- that only affects what you can assign to myList, which is different than what is in myList.
And, one dumb question :) The collections framework guarantees I
always get out the same instance I put in, the collections are really
a collection of references, correct?
When you create a collection Map myMap = new HashMap(), myMap is a reference to the underlying collection. Similarly, when you put something into a collection, you are putting the reference to the underlying object into the collection.
I don't understand what is the use of unbound wildcards generics. Bound wildcards generics with upper boundary <? extends Animal> makes perfect sense, because using polymorphism I can work with that type or collection. But what is the point of having generics that can be of any type? Doesn't it defeat the purpose of generics? Compiler doesn't find any conflict and after type erasure it would be like no generics was used.
An unbound type can be useful when your method doesn't really care about the actual type.
A primitive example would be this:
public void printStuff(Iterable<?> stuff) {
for (Object item : stuff) {
System.out.println(item);
}
}
Since PrintStream.println() can handle all reference types (by calling toString()), we don't care what the actual content of that Iterable is.
And the caller can pass in a List<Number> or a Set<String> or a Collection<? extends MySpecificObject<SomeType>>.
Also note that not using generics (which is called using a raw type) at all has a quite different effect: it makes the compiler handle the entire object as if generics don't exist at all. In other words: not just the type parameter of the class is ignored, but also all generic type parameters on methods.
Another important distinctions is that you can't add any (non-null) value to a Collection<?>, but can add all objects to the raw type Collection:
This won't compile, because the type parameter of c is an unknown type (= the wildcard ?), so we can't provide a value that is guaranteed to be assignable to that (except for null, which is assignable to all reference types).
Collection<?> c = new ArrayList<String>();
c.add("foo"); // compilation error
If you leave the type parameter out (i.e. use a raw type), then you can add anything to the collection:
Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());
Note that the compiler will warn you not to use a raw type, specifically for this reason: it removes any type checks related to generics.
When you need to perform an instanceof check.
You can't parameterize like this:
Object value;
if (value instanceof List<String>) {
// ...
}
So you do:
Object value;
if (value instanceof List<?>) {
// ...
}
While using raw types means that you don't know about generics (because you're lazy or code was written ages ago), using <?> means that you know about generics and explicitly emphasize that your code can work with any kind of objects.
There are (rare) perfectly correct use cases for unbound wildcards. The SDK contains some of them.
One example is a method that does a definite action on a list of any kind and does not return anything as rotate in Collections:
static void rotate(List<?> list, int distance)
Another example is when you want to list the possible constructors for a class, the method is :
Constructor<?>[] getConstructors()
Here it in not even possible to use a generic, because by definition the array will contain different constructor each with its own actual class. By contrast, the API does use a generic signature for getting one single constructor : Constructor<T> getConstructor(Class<?>... parameterTypes).
The conclusion is that even if it is mainly used for compatibility with older code, there are still places where unbound wildcard generics are the correct way.
Allow me to rephrase the question:
"What is the difference between List<Object> and List<?> ?"
The answer to that is that List<?> is more restrictive. It tells us that we have a bunch of object of some type, but that type is not necessarily Object.
Since we don't know what that type is, we cannot add to the list at all - anything we add may be of wrong type. In fact, we cannot pass any argument of ? type to any method, not just add().
On the plus side, when we specify that a method takes List<?>, it can take List<String> or List<Integer> or any other List<>. List<Object> can only take List<Object>.
Using unbounded wildcards only makes sense, AFAIK, when wrapping old code that is not using generics, basically Collections.
If you look at what you can do with such a generic it's basically nothing.
If you have a collection you can't add anything, if you try to read something out you will always get an Objectand so on.
This in turns helps guaranteeing that you will handle the data in a type safe way, whereas using the raw type would have caused the compiler to ignore any mess you'd make.
Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type? from Angelika Langers Java Generics FAQ might be of interest.
List<Object> is a List that may contain any Object, e.g. l[0] may be an Integer, l[1] may be a String, etc.
List<?> may be a List<Integer> or List<String>, etc. If it is a List<Integer>, it stores only Integers, if it is List<String>, it stores only Strings.
I've come into something I haven't come across before in Java and that is, I need to create a new instance of say the ArrayList class at runtime without assigning a known type then add data to the list. It sounds a bit vague so here is an example:
Class<?> c = i.getClass();
Constructor<?> con = ArrayList.class.getConstructor();
ArrayList<?> al = (ArrayList<?>)con.newInstance();
al.add("something");
Now the reason I'm doing this versus just using generics is because generics are already being used heavily and the "i" variable in this example would be given to use as type "?". I would really rather not throw in another generic as this would cause more work for the user and would be much less flexible in the end design. Is there any way to use something like below (Note: what is below doesn't work). Anyone have ideas?
ArrayList<c> al = (ArrayList<c>)con.newInstance();
You can't add objects in a Collection defined using wildcards generics. This thread might help you.
Indeed you are creating a collection that is, yes, the super type of every collection, and as such, can be assigned to any collection of generics; but it's too generic to allow any kind of add operation as there is no way the compiler can check the type of what you're adding. And that's exactly what generics are meant to : type checking.
I suggest you read the thread and see that it also apply to what you wanna do.
Your collection is just too generic to allow anything to be added in. The problem has nothing to do with the right hand side of the asignment (using a singleton or reflection), it's in the left hand side declaration type using wildcards.
If I get what you mean, you have a class C, which is unknown at compile time, and you want to create an ArrayList<C>, in a type safe way. This is possible:
Class<?> c = ...;
ArrayList<?> al = listOf(c);
static <T> ArrayList<T> listOf(Class<T> clazz)
{
return new ArrayList<T>();
}
This is the theoretically correct way of doing it. But who cares. We all know about type erasure, and there's no chance Java will drop type erasure and add runtime type for type parameters. So you can just use raw types and cast freely, as long as you know what you are doing.
You could just use ArrayList<Object>, to which you can add() anything.