Complex Generics Combinations - java

Imagine a generic class MySet which maintains a parent MySet instance and a child MySet instance. The idea is that the parent should be able to hold a superset of T and the child a subset. So given the following sample, consider the following problem:
class MySet<T> {
MySet<? extends T> child;
void doStuff (Collection<? extends T> args) {
child.doStuff(this, args);
}
}
EDIT: fixed question and sample code to reflect the real problem
Now, the child generic <T> may be more restrictive than the parent's <T>, so the parent must pass in a Collection<X> where <X> conforms to the child's <T>. Keep in mind that this parent->child chain could extend to be arbitrarily long. Is there any way to arrange the generics so that parent.doStuff(...) will compile, ie, so that it can only be called with the arguments of it's most restrictive child?
This would mean that the java compiler would pass up generic information all the way up the parent->child chain to determine what the allowable arguments to doStuff could be, and I don't know if it has that capability.
Is the only solution to ensure children cannot be more restrictive than their parents using generics (ie, MySet<T> child; rather than MySet<? extends T>) and have children be more restrictive than their parents elsewhere in the code?

I can give a negative answer to part of that question right away:
Is there any way to arrange the
generics so that parent.doStuff(...)
will compile, ie, so that it can only
be called with the arguments of it's
most restrictive child?
This would mean that the java compiler
would pass up generic information all
the way up the parent->child chain to
determine what the allowable arguments
to doStuff could be, and I don't know
if it has that capability.
The simple answer is no, because the actual extend (and type requirements) of that chain are only known at run time, and by then any information about generics has been lost through erasure.
To push it even further, if you had a checked type instead of vanilla generics, with a method that could pass up in the chain the (most restrictive) actual type accepted, you could do a check at runtime, and raise a runtime error, but it will never be a compile error.
So no, unless the actual final type is known (and specified, maybe by a second type arg) in advance, the compiler is not going to be able to help you there.
What you can (and should do imo) is keep with what you just wrote (which should compile just fine), and pass it an argument that can be unsafe. Whether you type-check it yourself, or let the JVM raise a ClassCastException is needed, remains a matter of choice.

The code as presented doesn't seem to be attempting to make any sense.
Consider
MySet<String> c = ...;
MySet<Object> p = new MySet<Object>(c);
Collections<Integer> ints = ...;
p.doStuff(ints);
That is going to call c.doStuff(???, ints). ints is of type Collection<Integer>, but the callee requires doStuff(Collection<? extends String>).

Related

What type is <?> when making instantiating lists?

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

When is it acceptable to pass a Class<T> argument to a generic method?

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?

Java Generics: how can i assign a method's return value which uses multiple inheritance

I have a method which returns a complex generic type (which implements multiple interfaces)
protected abstract <BOB extends Stan & Jan<I>> BOB getStanAndJanItem();
This compiles fine, and i'm able to override it and return values. As soon as i call it i get compilation errors though (it doesn't even have to be assigned to anything). And i guess this makes sense, since BOB is only defined inside the method.
So, how do i define bob at a class level?
And YES, I know i can just split up the calls and have them return the same object, or introduce some additional inheritance (and i'll probably end up doing that) but can it be done this way as well?
Error Received:
Bound mismatch: The generic method getStanAndJanItem() of type MyAbstractClass<I> is not applicable for the arguments (). The inferred type Stan is not a valid substitute for the bounded parameter <BOB extends Stan & Jan<I>>
In order to call the method, you need to pass a generic type parameter that matches your constraint.
Even if your particular call doesn't need it, you still need to pass the type parameter.
Therefore, you can only call the method if you parameterize it with some class or interface that implements both of those types.
The real problem is the lack of support of intersection type. Suppose language support it directly, we can write intersection type like A&B etc, and your example would be like
Stan&Jan<I> getStanAndJanItem()
void setStanAndJanItem(Stan&Jan<I> item)
Stan&Jan<I> result = getStanAndJanItem();
result.doStanStuff();
result.doJanStuff();
setStanAndJanItem(result);
Without such support, we are stuck. Your generic declaration is probably wrong: it implies that the caller decides the BOB type, while you probably want the implementation to decide the BOB type. The implementation can return anything that implements both Stan and Jan<I>. Currently, that requirement cannot be expressed.

How to do `MyClass<String>.class` in Java?

How can call public <T> T doit(Class<T> clazz); using MyClass<String>.class as clazz where I can not instantiate or extend MyClass.
EDIT: 'David Winslow' and 'bmargulies' responses are correct (MyClass<String>) doit(MyClass.class); works for the original question BUT surprisingly when the method returns say MyClass<T> instead of T casting will not compile any more.
Edit: I have replaced List with MyClass and added the condition to my original question.
Use List.class. Because of type erasure type parameters to Java classes are entirely a compile-time construct - even if List<String>.class was valid syntax, it would be the exact same class as List<Date>.class, etc. Since reflection is by nature a runtime thing, it doesn't deal well with type parameters (as implemented in Java).
If you want to use the Class object to (for example) instantiate a new List instance, you can cast the result of that operation to have the appropriate type parameter.
List<String> list = (List<String>)(ArrayList.class.newInstance());
I've seen similar questions asked several times, for example
Acquiring generic class type
There are legitimate reasons to construct static generic types. In op' case, he would probably like to
MyClass<String> result = doit(MyClass<String>.class);
Without language syntax support, casting is the correct way to go. If this is needed quite often, the casting should be put in a method, as
public class MyClass<T>
{
#SuppressWarnings("unchecked")
// may need a better method name
static public <T2> Class<MyClass<T2>> of(Class<T2> tClass)
{
return (Class<MyClass<T2>>)(Class<?>)(MyClass.class);
}
}
MyClass<String> result = doit(MyClass.of(String.class)); // no warning
We can supress the warning on that method alone, after making sure the cast is safe. Any call site will not see the warning.
This is all compile time casting game. At runtime all the type parameters are erased, and really only the naked class object is passed around. The of method will most likely be optimized off, so to JVM the last line is nothing but
MyClass result = doit(MyClass.class)
There are also times when at runtime we need a complete MyClass<String> type. A ParameterizedType object needs to be obtained to represent MyClass<String>.
When the two requirements are combined together, that is, we need a compile time expression regarding MyClass and String that will evaluate at runtime to a ParameterizedType
ParameterizedType type_MyClass_String = ???? MyClass ?? String ???
There is a technique involving an anonymous subclass of MyClass<String>
ParameterizedType type_MyClass_String = superTypeOf( new MyClass<String>(){} );
which I find quite disturbing.
See http://jackson.codehaus.org/1.7.0/javadoc/org/codehaus/jackson/type/TypeReference.html and the references that it references for a comprehensive discussion of the issues around generics.
the bottom line is that, if you really want to work with generic types in this way, you have to stop using Class and start using Type and its subclasses.
Contrary to your comment on another answer, you can write List<List<String>> obj = (List<List<String>>) doit(List.class);, you just can't avoid a warning when you write it.
Since after your update your question does not appear to be an exact duplicate:
You would need to call getClass() on an instance of MyClass. Better have a dummy static final instance somewhere:
public static final MyClass INSTANCE = new MyClass();
...
return (Class<MyClass<String>>) instance.getClass();
T corresponds to List, so any reference to String as the generic paramter of List is irrelevant.
How to do MyClass<String>.class in
Java?
You can't.
Generics in Java use type erasure; the type of the parametrized argument is enforced during compilation, but it is lost after compilation. The resulting byte code for an instance of a generic class does not contain any run-time meta-data on its arguments whatsoever.
As it is now, it is just not possible, a major language design blunder IMO.

Java: getting inner type in nested parameterized types (reflection)

Most of the documentation regarding type erasure handling in Java assumes that the use case is handling a type like SomeType<ParamType>.
I am trying to process method parameter for the following method:
public void setOtherReferenceRanges(List<ReferenceRange<T>> referenceRanges)
When the container class is instantiated with a type DvQuantity, this signature should become
public void setOtherReferenceRanges(List<ReferenceRange<DvQuanitity>> referenceRanges) in runtime.
Using reflection one can see that the List has an actualTypeArgument which is ReferenceRange<T>. Since reflection uses class information, I would not expect it to give me ReferenceRange<DvQuantity>.
However, when I created the class containing this method, I passed the DvQuantity type as T. So the type filling in T should be available to Java runtime, but I could not find a way of getting it. I end up with a TypeVariableImpl object accessed via reflection, which does not seem to contain any useful data.
Can you think of any ways to discover this information in runtime?
When you say
when I created the class containing this method
I guess you mean when you create an object of that type, for example:
foo = new ContainerClass<DvQuantity>();
In that case, because of erasure, there is no way to recover the type DvQuantity.
However, if you create a class passing a type parameter to the superclass, like this
class DvQuantityContainerClass extends ContainerClass<DvQuantity> {...}
...
foo = new DvQuantityContainerClass();
Or, shorter, an inline anonymous subclass (which looks almost like the first example but with a subtle but important difference):
foo = new ContainerClass<DvQuantity>(){};
Then you can recover the type parameter, because you recover the type parameter used to extend a superclass at runtime. Unfortunately, Java itself doesn't provide an easy way to now get the type of the DvQuantityContainerClass.setOtherReferenceRanges method with the T filled in. For that, I've written gentyref, to do advanced reflection on generic types:
Method m = DvQuantityContainerClass.class.getMethod("setOtherReferenceRanges", List.class);
// this will return List<ReferenceRange<DvQuanity>>, like you are lookingn for
return GenericTypeReflector.getExactParameterTypes(m, DvQuantityContainerClass.class)
Generic type information is erased by the compiler and is not available at runtime. When I need to ensure a certain type at runtime I pass in a class argument:
public <T> void doSomething(T t, Class<T> c);
This is not always convenient or even possible, but for many cases it is possible.
So the type filling in T should be available to Java runtime, but I could not find a way of getting it.
Perhaps it's not entirely correct, but the way I think about it is that at runtime there is no actual class - just an object without a specific type which meets the interface of T. In other words, erasure happens not with objects, but instead with these nebulous (in the OOP world at least) type-things.
http://java.sun.com/docs/books/tutorial/java/generics/erasure.html
There are ways of capturing the type information inside the class itself (T types would need a method getUnderlyingType()... or something), but that's a bad idea. If you truly need to raw type of the object, I'd reconsider using generics.

Categories

Resources