I want to create a Java class with two generic types.
public class BinaryContractInfo<T, U>
The thing is that I would like U to be either the same type of T or T[].
Basically I would like to know if T extends T[] or vice versa. Then I could do something like
public class BinaryContractInfo<T, U extends T[]>
Is that possible? Is there a way to do that?
You cannot specify a type as being either T or T[] Instead you can use varargs
public void method(T... ts);
which can be called either
method(t);
method(t1, t2, t3);
T[] ts =
method(ts);
For return types you can specify
public T[] method();
if the caller assumes there is only one return value
T t = method()[0];
No, AFAIK, you can't do that, not to mention that arrays and generics don't play well together. The simplest thing would be to wrap your array in a collection type (List or a very thin wrapper over an array), if you are allowed to do it that is.
Also, why not just use T[] directly in your code instead of having a separate type parameter for it? If you can't, then do explain why you can't.
Related
Imagine this piece of code:
public static <T> T[] superClassArray(Class<? extends T[]> subClass) {
T[] superArray = (T[]) Array.newInstance(subClass.getComponentType().getSuperclass(), 0);
return superArray;
}
The return type T[] of this method would be of whatever type was given as argument subClass, even thought subClassis not garanted to actually represent T[] but just a subclass (? extends T). So the actual return type should be Object since T[] is not declared more explicitly than being any superclass of subclass.
However,
Integer[] objA = superClassArray(Integer[].class);
compiles because it is erroneously expected to return a Integer[] object but obviously throws a ClassCastException because a Number[] object is actually returned.
So is there a justification for poor handling of generic types only declared through rather vague wildcards, or am I mistaken at any point of my consideration?
As far as I understand, you are not very consistent in what you are trying to do.
With your method you are creating an array of SUPERTYPE of your class, which actually succeds.
But then you are trying to assign it to a reference to a SUBTYPE which is illegal. If you are actually sure that this array cannot contain values of any other type than Integer you can explicitly cast it:
Integer[] objA = (Integer[]) superClassArray(Integer[].class);
BUT I don't see any value at all in a code like that and in the real world if you have a task that you are trying to solve with something like this, you sould really think about it a few more times and come up with a better solution. :)
You are not supposed to do any manual casting. Generics has to handle that during compile time. If you get compile time error, You better fix this instead of doing unsafe casting in your below code snippet.
T[] superArray = (T[])Array.newInstance(subClass.getComponentType().getSuperclass(), 0);
I am not very familiar with some of the generic syntax in Java.
I came across some code like this:
public static<T> T foo(T... a)
Can somebody explain what it means in a succinct way?
Does it mean foo() takes in an array of type T and returns type T?
Why isn't the syntax like this below?
public static T foo(T[] a)
I had a look at the Oracle docs but the example they have seems much easier to understand: Oracle Generics
Two things:
1) This is a varargs method, a method that takes a variable number of arguments. That is not the same as a method that takes an array (even though under the hoods it is implemented using an array).
You call this method as foo(a,b,c) (as opposed to foo(arrayWithABC)).
2) If you want to use the generic type placeholder T, you have to declare it. This is exactly what the first <T> does.
The difference between public static T foo(T a) and public static <T> T foo(T a) is that the latter introduced a "local" T for the scope of this method. That means "method returns an instance of whatever type parameter a has". In the first version, the T would need to be a type placeholder declared elsewhere (such as on the class as a whole), or a class name.
Since <T> is completely unrestricted you can pass anything. What the generics do is bind the return value to the same type. If you just had public static Object foo(Object a), you could pass in an Integer and get back a String. The T prevents that.
If you wanted to restrict the acceptable types, you could do public static <T extends Number> T foo(T a).
T... a
means variable number of T type objects arguments for the method whereas
T[] a
means a single argument of array of T objects
This means the type 'T' will match to any real type. Its like a wild-card type :)
It is a pretty simple one. I want to declare a list of objects, but I want make sure all objects implemented the Comparable interface. What should I do? I try to write
List<Comparable> heap = new ArrayList<Comparable>();
But compiler gives me a warning. What is the proper way to write it?
Thanks
Follow up:
I thought I had finished the question before I post it but apparently I didn't. So let me finish it up.
My purpose is to have a list of objects that:
Implements the Comparable interface
Are all with the same type
Can I make it
List<Comparable<?>> heap = new ArrayList<Comparable<?>>()
No, I can't. The reason is because I need to retrieve the elements from the list and compare them. like:
if( heap.get(0).compareTo(heap.get(1)) > 0)
If I use wildcard List<Comparable<?>>, the complier will give me an error. Saying heap.get(0) cannot match heap.get(1) So I need to know the correct way to declare it.
I find somebody asking me what the warning is.... that surprises me.....well, the warning is:
Comparable is a raw type. References to generic type Comparable should be parameterized
It's because you're using the raw type Comparable. You can try giving Comparable a wildcard type parameter:
List<Comparable<?>> heap = new ArrayList<Comparable<?>>();
If you want the objects to all be of the same type, you can do something along the lines of
public static <T extends Comparable<? super T>> List<T> getList() {
...
}
and return your list from getList().
Since all your objects are of the same type (let's say f.e. FooType), then just use a List<FooType>.
Perhaps you could write a method that only takes a type that extends Comparable and returns a List of that type:
public <T extends Comparable> List<T> getComparableList(T t) {
List<T> heap = new ArrayList<T>();
return heap;
}
Methods that are generic using the T parameter can for sure be handy. However, I am curious what the use of a generic method would be if you pass an argument such as Class<T> clazz to the method. I've come up with a case that maybe could be an possible use. Perhaps you only want to run a part of the method based on the type of class. For example:
/** load(File, Collection<T>, Class<T>)
* Creates an object T from an xml. It also prints the contents of the collection if T is a House object.
* #return T
* Throws Exception
*/
private static <T> T void load(File xml, Collection<T> t, Class<T> clazz) throws Exception{
T type = (T) Jaxb.unmarshalFile(xml.getAbsolutePath(), clazz); // This method accepts a class argument. Is there an alternative to passing the class here without "clazz"? How can I put "T" in replace of "clazz" here?
if (clazz == House.class) {
System.out.println(t.toString());
} else {
t.clear();
}
return T;
}
Is this an accepted practice? When is the Class<T> clazz argument useful with generic methods?
Is this an accepted practice?
Well, to me.. no not really. To me, it seems somewhat pointless when you can simply define some boundaries on the type of T. For example:
private static <T extends House> void load(Collection<T> t)
This will guarantee that either the object is of type House or of a subclass of House, but then again if you only want an instance of type House or it's subclasses, it should really just be:
private static void load(Collection<House> houses)
The idea of generics is to make a method or a class more malleable and extensible, so to me it seems counter-intuitive to start comparing class types in the method body, when the very notion of generics is to abstract away from such details.
I'd only pass class objects if the generic type could not be derived otherwise. In your case, the compiler should be able to infer T from the collection. To treat specific objects differently, I'd use polymorphism - e.g. House#something() and Other#something(), and just call anyObject.something().
I think it is acceptable but if it can be avoided then you should. Typically, if you can have different methods which accepts different type, then do it instead of one method which uses if clauses to do something different depending on the type of the parameter. You could also delegates to the class the operation you want to make specific for a given type.
In your case, you could simply test the type of each element of the collection using instanceof, to do what you need for the specific type. But it won't work if the list is empty.
A typical use is if you need to get the type to create it and you can find it from another way. For instance, Spring uses it to load a bean from its name:
<T> T getBean(Class<T> requiredType)
In that case, it cannot be avoided (without having to cast).
If the returned value or other parameters types are dependent or need to be equal, generics will add compile time checks, so that there's no need to cast to T.
Examples
<T> T createNewInstanceOfType(Class<T> type);
<T> void addValueToCollection(Collection<T> collection,T value);
<T> List<Class<? extends T>> findSubClassesInClasspath(Class<T> superType);
Raw types
It is still possible to defer a casting error until runtime (ClassCastException) with some casts, e.g. with implicit casts from non-generic (raw) types to generic ones:
List nonGenericList = new ArrayList();
nonGenericList.add(new Integer(42));
List<String> wreckedList = nonGenericList;
The compiler will generate a bunch of warnings, unless you suppress them with annotations or compiler settings.
Compiler Settings (Eclipse):
For example, the usage of raw types generates a warning per default, one can treat warnings as errors and even as fatal errors:
You would pass a Class<T> argument in generics if, and only if, you would pass a Class argument before generics. In other words, only if the Class object is used in some way. Generics serves as a compile-time type checking tool. However, what arguments you pass should be determined by the runtime logic of the program, and should be irrelevant of generics.
I haven't seen passing a Class object in order to check the runtime type of an object as a common use case for generics. If you're doing that, there's a good chance that there's a better way to set up your class structure.
What I have seen is if you need to create a new instance of the class in question, or otherwise use reflection. In that case you do have to pass the Class object, because Java cannot derive it at runtime thanks to type erasure.
In your case actually having the Generic parameter is not strictly needed.
Since the output of the function you are describing does not depend on the type of the input you might as well use wild cards.
private static void stuff(Collection<?> t){
Object next = t.iterator().next(); //this is ugly and inefficient though
if(next instanceof House){
System.out.print(next.toString());
}else{
t.clear();
}
}
The only time you should use generic parameter is when the type of the result of a function will be dependent of the type of the parameters.
You will need to pass the Class corresponding to the type when your code will need it; most of the time this happens when:
- You need to cast/type check objects to T
- There is serialization/deserialization involved.
- You cannot access any instance of T in your function and you cannot call the getClass() method when you need it.
Passing a Class on every generic function will result in you passing an unnecessary parameter most of the time, which is regarded as bad practice.
I answered a similar discussion in the past:
When to use generic methods and when to use wild-card?
I have a class that maps incoming messages to matching readers based on the message's class. All message types implement the interface message. A reader registers at the mapper class, stating which message types it will be able to handle. This information needs to be stored in the message reader in some way and my approach was to set a private final array from the constructor.
Now, it seems I have some misunderstanding about generics and / or arrays, that I can't seem to figure out, see the code below. What is it?
public class HttpGetMessageReader implements IMessageReader {
// gives a warning because the type parameter is missing
// also, I actually want to be more restrictive than that
//
// private final Class[] _rgAccepted;
// works here, but see below
private final Class<? extends IMessage>[] _rgAccepted;
public HttpGetMessageReader()
{
// works here, but see above
// this._rgAccepted = new Class[1];
// gives the error "Can't create a generic array of Class<? extends IMessage>"
this._rgAccepted = new Class<? extends IMessage>[1];
this._rgAccepted[0] = HttpGetMessage.class;
}
}
ETA:
As cletus correctly pointed out, the most basic googling shows that Java does not permit generic arrays. I definitely understand this for the examples given (like E[] arr = new E[8], where E is a type parameter of the surrounding class). But why is new Class[n] allowed? And what then is the "proper" (or at least, common) way to do this?
Java does not permit generic arrays. More information in the Java Generics FAQ.
To answer your question, just use a List (probably ArrayList) instead of an array.
Some more explanation can be found in Java theory and practice: Generics gotchas:
Generics are not covariant
While you might find it helpful to
think of collections as being an
abstraction of arrays, they have some
special properties that collections do
not. Arrays in the Java language are
covariant -- which means that if
Integer extends Number (which it
does), then not only is an Integer
also a Number, but an Integer[] is
also a Number[], and you are free to
pass or assign an Integer[] where a
Number[] is called for. (More
formally, if Number is a supertype
of Integer, then Number[] is a
supertype of Integer[].) You might
think the same is true of generic
types as well -- that List<Number>
is a supertype of List<Integer>, and
that you can pass a List<Integer>
where a List<Number> is expected.
Unfortunately, it doesn't work that
way.
It turns out there's a good reason it
doesn't work that way: It would break
the type safety generics were supposed
to provide. Imagine you could assign a
List<Integer> to a List<Number>.
Then the following code would allow
you to put something that wasn't an
Integer into a List<Integer>:
List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415));
Because ln is a List<Number>, adding
a Float to it seems perfectly legal.
But if ln were aliased with li, then
it would break the type-safety promise
implicit in the definition of li --
that it is a list of integers, which
is why generic types cannot be
covariant.
It is right what cletus said. There is a general mismatch between the usually enforced invariance of generic type parameters vs. covariance of Java arrays.
(Some background: Variance specifies how types relate to each other concerning subtyping. I.e. because of generic type parameters being invariant
Collection <: Collection does not hold. So, concerning the Java type system, a String collection is no CharSequence collection. Arrays being covariant means that for any types T and U with T<:U, T[] <: U[]. So, you can save a variable of type T[] into a variable of type U[]. Since there is a natural need for other forms of variance, Java at least allows wildcards for these purposes.)
The solution (the hack, actually) I often use, is declaring a helper method which generates the array:
public static <T> T[] array(T...els){
return els;
}
void test(){
// warning here: Type safety : A generic array of Class is created for a varargs parameter
Class<? extends CharSequence>[] classes = array(String.class,CharSequence.class);
}
Because of erasure the generated arrays will always be of type Object[].
And what then is the "proper" (or at least, common) way to do this?
#SuppressWarnings(value="unchecked")
public <T> T[] of(Class<T> componentType, int size) {
return (T[]) Array.newInstance(componentType, size);
}
public demo() {
Integer[] a = of(Integer.class, 10);
System.out.println(Arrays.toString(a));
}
Arrays are always of a specific type, unlike how Collections used to be before Generics.
Instead of
Class<? extends IMessage>[] _rgAccepted;
You should simply write
IMessage[] _rgAccepted;
Generics don't enter into it.
IMHO,
this._rgAccepted = (Class<? extends IMessage>[])new Class[1];
is the appropriate way to handle this. Array component types have to be reified types, and Class is the closest reified type to Class<whatever>. It'll work just as you would expect a Class<whatever>[] to work.
Yes, technically it is unchecked and might cause issues later if you cast it to another more general array type and put wrong stuff in it, but since this is a private field in your class, I presume you can make sure it is used appropriately.