Imagine the following code:
final Set<ConstraintViolation<User>> violations = validator.validate(user);
while User is defined as
public class User extends SuperModel {
Now, I want to pass the violations to a method like
private void checkViolations(final Set<ConstraintViolation<? extends SuperModel>> violations) {
// do something
}
So I want this helper method to be generic as I do not need to know that the ConstraintViolations in the Set are of the type User.
But the compiler says:
Error:(46, 25) java: incompatible types: java.util.Set<javax.validation.ConstraintViolation<my.package.model.User>> cannot be converted to java.util.Set<javax.validation.ConstraintViolation<? extends my.package.model.SuperModel>>
I do not really understand why this is impossible, because every User is a SuperModel. This should work IMO.
In contrast, here is something that works:
private void checkViolation(ConstraintViolation<? extends SuperModel> violation) {
// do something
}
private void otherMethod() {
[...]
final Set<ConstraintViolation<User>> violations = mValidator.validate(user);
for (ConstraintViolation<User> violation : violations) {
checkViolation(violation);
}
}
Does my first example not work because there are two "levels" of generics involved?
The issue is that ? extends SuperModel means anything that extends SuperModel can be used.
If you want to pass Set<ConstraintViolation<User>> to the wildcard it will not be accepted, because you break the anything extends SuperModel with User only.
Keep in mind that you can pass anything with the constraint ? extends SuperModel. So the Set might consist of a User, a SuperModel or something entirely different which extends SuperModel.
private void checkViolation(final Set<ConstraintViolation<? extends SuperModel>> violation) {
// you know that the Set consists of any object extending SuperModel.
}
Use this instead
private <T extends SuperModel> void checkViolations(final Set<ConstraintViolation<T>> violations) {
// you know the Set consists only of object of type T
}
By declaring the type T you ensure that ever item in the list is of type T. So the Set can only consist of User, SuperModel or any other type extending SuperModel.
Set<ConstraintViolation<User>> is not a subtype of Set<ConstraintViolation<? extends SuperModel>> even though ConstraintViolation<User> is a subtype of ConstraintViolation<? extends SuperModel>, for the same reason that Set<String> is not a subtype of Set<Object> even though String is a subtype of Object.
Basically, when a generic type is parameterized by type and not a wildcard, the parameter must match exactly. Foo<A> is only compatible with Foo<B> if A = B exactly. If you want to be polymorphic on the type parameter, the generic type must be parameterized by a wildcard, e.g. Foo<A> is a subtype of Foo<? extends B> if A is a subtype of B. (Note that in the case of Set<ConstraintViolation<? extends SuperModel>>, Set is parameterized by the type, not a wildcard. There is a wildcard somewhere inside the type ConstraintViolation<? extends SuperModel>, but Set only cares about the top level.)
If you want to be able to accept Set<ConstraintViolation<X>> and Set<ConstraintViolation<Y>>, etc., one way to do it is with a wildcard at the top level:
private void checkViolations(final Set<? extends ConstraintViolation<? extends SuperModel>> violations) {
Related
Why is the unsafe cast (T) needed in this generic interface? If T is comparable to itself, i.e. implements ExtendedComparable<super of T> which means also ExtendedComparable<T>, then why does type erasure require ExtendedComparable<T> to be cast to T?
/* #param <T> T must be comparable to itself or any of its superclass
* (comparables are consumers, thus acc. to the PECS principle
* = producer-extends,consumer-super we use the bounded wildcard type "super")
*/
public interface ExtendedComparable<T extends ExtendedComparable<? super T>> {
Comparator<? super T> getComparator();
default boolean greaterThen(T toCompare) {
return getComparator().compare((T) this, toCompare) > 0;
}
}
Because there is no guarantee that this is actually an instance of class T or even extend it.
For example consider this:
public class T0 implements ExtendComparable<T0> {...}
public class T1 implements ExtendComparable<T0> {...}
In T0 complies fine as it complies with the bound: T0 extends ExtendComparable<T0> and T0 is super of T0. In this case this is an instance of T0 here so you are fine; the cast (T)this (thus (T0)this) makes sense.
With T1 the declaration is correct also because the bound is applied to T0 no T1, T is substituted T0. However this is T1 and T1 is not super nor a child of T0. Yes, both implement
ExtendedCompatible<T0>, but you cannot cast between siblings. For example Integer and Double extend Number but (Integer) new Double(0.0) fails.
So too does the cast (T) translated to (T0) fail.
The assumption you are making is that T is going to be set to the same as the class that is been declared and currently there is no way to force those semantics. I hope this will change at some point in future releases of the Java language but perhaps there is actual reason why the Java language "task force" are avoiding to do so.
There is a way to avoid the cast altogether but is better when you make ExtendedCompatible an abstract class rather than an interface.
You can declare a final field of type T which value would be set by a protected constructor by extending class which in turn must pass this as its value:
public abstract class ExtendedCompatible<T extends ExtendedCompatible<? super T>> {
private final T thiz;
protected ExtendedCompatible(final T thiz) {
if (this != thiz) throw new IllegalArgumentException("you must pass yourself");
this.thiz = thiz;
}
...
public class MyExtendedCompatible extends ExtendedCompatible<MyExtendedCompatible> {
public MyExtendedCompatible() {
super(this);
}
}
The price you pay is the extra memory consumption of having a silly reference to itself and the added code/CPU burden of passing this to the parent constructor.
Another would be to declare an abstract method to get the T (this):
// Parent abstract class:
protected abstract T getThiz();
// Child class... for each class:
protected MyChildClass getThiz() { return this; }
Thanks. Valentin is right. Even if both types implement the same interface, this does not and should not make the cast between them to work. And yes, there is no mechanism in Java to enforce passing in T the same class as the class being declared.
Consider this snipped code:
public class MaxSizeHandler extends AbstractValueHandler<Collection> {
}
and I use eclipse, and It warns me to add infer generic arguments type for Collection and the code changes like this:
public class MaxSizeHandler extends AbstractValueHandler<Collection<?>> {
}
My question is what's the problem if I don't put it, or what's the advantage if I put it?
Passing a raw Collection will imply that the Collection is not parametrized, hence you lose the ability to strongly type (i.e. at compile time) what goes in the Collection.
Passing a Collection<?> is not substantially different, as the wildcard will match anything extending Object.
Of course, it will remove the warning.
The best way would be to pass a Collection<MyObject> or a Collection<? extends MyObject>, etc.
you need to mention Collection type before itself in generic format like below :
public class MaxSizeHandler extends AbstractValueHandler<Collection<? extends T>> {
}
T-> type of collections
Otherwise java compiler will take as default type of collection.
Adding the correct type will allow the class to return the correct type of value, is there a specific type of Object your Collection will hold i.e Integer, then use AbstractValueHandler<Collection<Integer>>.
Depending how you're using the MaxSizeHandler class it may make sense to make this class itself generic. For example, if you need to iterate over the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? extends T>> {
public void handle(Collection<? extends T> coll) {
for(T item : coll) {
// ...
}
}
}
or if you need to add new items to the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? super T>> {
public void handle(Collection<? super T> coll) {
T item = createAnItem();
coll.add(item);
}
}
(These are just toy examples, as you haven't said what kind of methods AbstractValueHandler declares)
I'm trying to create library with a container that releases instances of its contained objects according to descriptors it is passed. I'd like to make it so the descriptor determines the type of the returned object, but the descriptor can specify a bounded type. How do I implement this? For example the closest I can get is:
/*Block 1 - First Attempt. Compiles, but forces user to cast*/
interface ItemDescriptor<I> {
Class<? extends I> getType();
}
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
I getItem(D descriptor);
}
//Implementations
class ChannelItemDescriptor<I extends ByteChannel> implements ItemDescriptor<I>
{
final Class<? extends I> type;
ChannelItemDescriptor(Class<I> type) {
this.type = type;
}
#Override Class<? extends I> getType() {return type;}
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
#Override ByteChannel getItem(ChannelItemDescriptor<? extends ByteChannel> descriptor) {...}
}
The above code compiles, but the problem is ChannelArchive's getItem can return SeekableByteChannels as well. The user of this library knows this at compile time (because they know the type parameter of the descriptor), so I'm trying to avoid adding a method parameter of type Class for forcing the user to explicitly cast the returned value to SeekableByteChannel when necessary. I can't figure out how to get getItem to return a specific subtype of ByteChannel without forcing the user to cast. I want to do this:
/*Block 2 - Test code*/
ChannelArchive archive = ...;
ChannelItemDescriptor<SeekableByteChannel> desc = ...;
ChannelItemDescriptor<ByteChannel> otherDesc = ...;
SeekableByteChannel sbc = archive.getItem(desc);
SeekableByteChannel sbc = archive.getItem(otherDesc); //Should fail to compile, or compile with warning
ByteChannel bc = archive.getItem(otherDesc);
I could add a Class<? extends I> parameter to each method, but the code for the method would completely ignore Class method parameter! It's only purpose would be to help the compiler infer types. I think it just obfuscates the code so much that it would be easier to just have the user use instanceof checks and casts.
I've tried this:
/*Block 3 - Failed attempt.*/
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
//Won't compile, getItem doesn't override
#Override <II extends ByteChannel> II getItem(ChannelItemDescriptor<II> descriptor) {...}
}
but that doesn't work: ChannelArchive is not abstract and does not override abstract method getItem(ChannelItemDescriptor<? extends ByteChannel>) in ArchiveContainer. I assume this is because the second type parameter <II extends ByteChannel> has different type erasure than <? extends ByteChannel>?
I've also tried this, which compiles:
/*Block 4 - Almost specific enough*/
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> {
Iterable<? extends D> getDescriptors();
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);
}
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
#Override <II extends ByteChannel, DD extends ItemDescriptor<II>> II getItem(DD descriptor) {...}
}
Even though it compiles, it won't really work because I need a ChannelItemDescriptor inside that method, and the resulting cast would defeat the purpose of using the added type-safety of generics.
I don't see why I can't do it, because the right types are known at compile time. What I really need on that ArchiveContainer interface is a parameterized type parameter, like: <II extends I, DD extends D<II>>. What am I doing wrong?
NOTE: I don't actually use ByteChannel and SeekableByteChannel, but what I do use is quite similiar.
That's to ruakh, I settled on the code in block 4. In my case, its highly unlikely the user would send the wrong sublcass of ItemDescriptor in a call to a getItem, especially because the descriptors are all returned from the ArchiveContainer itself via getDescriptors!
I think this code, which is (almost?) the same as your third attempt, is as good as you're going to get:
// in ArchiveContainer:
<II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor);
// in ChannelArchive:
public <II extends ByteChannel, DD extends ItemDescriptor<II>>
II getItem(DD descriptor)
{ ... }
Generics do offer a way to declare a type variable with two separate upper bounds:
public <T extends Foo & Bar> Foo fooBar(T t) { ... }
but apparently that's not allowed when one of the upper bounds is a type-parameter rather than a class or interface:
Type variables have an optional bound, T & I1 ... In. The bound consists of either a type variable, or a class or interface type T possibly followed by further interface types I1 , ..., In. […] It is a compile-time error if any of the types I1 ... In is a class type or type variable. [link]
(emphases mine). I don't know why this is.
But I don't think this should be a big problem. Note that, even after Map was genericized to Map<K,V>, its get method still took type Object. Naturally that method will always return null if you pass in a reference to an object that's not of type K (since such an object should never have been inserted into the map), but this doesn't harm type-safety.
I know that this is probably not what you want to hear, but even though Java generics look syntactically like C++ templates, they differ quite a bit in how they work.
Look up java type erasure in your favorite search engine.
Just because a type is known at compile-time does not, unfortunately, mean that the type is recoverable at runtime, or even during later compile phases.
In the code below I would like to get a "? super SomeInterface" from the Map how do I declare the type of "value" to enable me to do so?
class SomeClass { /* override hashCode & equals appropriately */}
interface SomeInterface<T> { }
interface AnotherInterface { }
class MainClass {
private final Map<SomeClass, ? super SomeInterface<? extends AnotherInterface>> someMap;
private final SomeClass someClass = new SomeClass();
public MainClass() {
someMap = new HashMap<SomeClass, SomeInterface<? extends AnotherInterface>>();
someMap.put(someClass, new SomeInterface<AnotherInterface>(){});
}
private void getValue(SomeClass someClass) {
/*
* I want to get a "? super SomeInterface<? extends AnotherInterface>" from the Map
* how do I declare the type of "value" to enable me to do so
*
*/
Object value = someMap.get(someClass);
}
private
<T extends SomeInterface<? extends AnotherInterface>>
T getValue2(SomeClass someClass) {
T value;
// the code below does not work
// Type mismatch: cannot convert from capture#3-of
// ? super SomeInterface<? extends AnotherInterface> to T
value = someMap.get(someClass);
}
}
Thanks in advance.
Object is the only thing you could possibly declare value as, since if you have a ? super Anything it could be any superclass of Anything all the way up to Object. You must therefore assign it to the most general type.
If you have a generic type that produces a <? super Something> it's almost surely a poor design (I don't even think the language supports it). That's because you can make no deductions on what it produces, and almost always gains you nothing (see below for a question I asked on the subject, though). "PECS" is a good mnemonic for remembering this: "produces: (use) extends, consumes: (use) super".
See also
Why can't a Java type parameter have a lower bound?
For your getValue2 method, the compiler cannot guarantee that the provided key will map to that particular type T (whatever the caller is expecting). This is because the map's values are declared using a wildcard, and there is no way to be sure an arbitrary ? super SomeInterface<? extends AnotherInterface> is a T, even if they have the same restrictions. You will need to cast to T (possibly after checking it if you can't be sure it will succeed)
I encountered the same issue a while back when implementing the following Map:
final Map<Class<? extends MyClass>, MyClassMetaInfo<? extends MyClass>> metaMap;
public <T extends MyClass> MyClassMetaInfo<T> getMetaInfo(Class<T> myClass) {
T metaInfo = (T)metaMap.get(myClass); //need to cast here
return metaInfo;
}
Beyond this, though, I'm confused with what you're trying to do here and would like to see an explanation/use case.
Lets try another approach. I replaced the interfaces with classes since I think this helps clarify things a bit. I also made them extend to demonstrate an example.
class SomeClass { /* override hashCode & equals appropriately */ }
class Parent { }
class Child extends Parent { }
class MainClass {
private final Map<SomeClass, ? super Child> someMap;
private final SomeClass someClass = new SomeClass();
public MainClass() {
someMap = new HashMap<SomeClass, Child>(); // #1
// someMap = new HashMap<SomeClass, Parent>(); // #2 , also valid
// someMap = new HashMap<SomeClass, Object>(); // #3 , also valid
someMap.put(someClass, new Child()); // #4
// someMap.put(someClass, new Parent()); // #5 error
// someMap.put(someClass, new Object()); // #6 error
}
private void getValue(SomeClass someClass) {
Object value = someMap.get(someClass);
}
private <T extends Child> T getValue2(SomeClass someClass) {
// error
T value = someMap.get(someClass);
}
}
someMap is defined to hold a map. The line #1 is allowed but #2 and #3 also. So your map can hold maps which hold different kind of objects. Now think a bit which put operations are allowed. The signature of put() is as follows:
? super Child java.util.Map.put(SomeClass key, ? super Child value)
So value is either of type Child, Parent or Object. But the compiler doesn't know since Generics are implemented with type erasure. So if the actual type is Child and you would put a Parent this would not work.
get() looks like this:
? super Child java.util.Map.get(Object key)
Now for the hard part. Again, you don't know what actual type this is. As stated above, #1, #2 or #3 could be used. If you used #2 or #3 and you would expect the return type to be at least Child you would assign a Parent or an Object to a variable of type Child. And this is why the compiler forbids it.
I've always thought the following should work. I get an object which I know is a Class<X> where X extends some class Xyz. In order to make it type-safe I wanted to use Class.asSubclass like in the following method:
private Class<? extends Xyz> castToXyzClass(Object o) {
final Class<?> resultClass = (Class<?>) o;
final Class<? extends Xyz> result = Xyz.class.asSubclass(resultClass);
return result;
}
However, in Eclipse it doesn't work, the only solution I see is an unchecked cast. I'd bet the above code must work, I've used something like this already... no idea what's wrong here.
asSubclass() operates on the object it's called on, not on its parameter - not what one is used to, but it reads quite well. You just have to do this:
final Class<? extends Xyz> result = resultClass.asSubclass(Xyz.class);
The asSubclass is a bit of a confusing name because you're not obtaining a Class object representing the subclass, you're obtaining the same class object that is retyped to reflect that it is a subclass of some parent class.
In fact, this method is fairly single purpose (and I think you've found it)...it's to take a raw or wildcarded class and get a better type parameter with a runtime check. It's not needed when you don't have gaps in your type information:
class Super {}
class Sub extends Super {}
//...
Class<Sub> subClass = Sub.class;
//both work, but the latter introduces a redundant runtime check
Class<? extends Super> subOfSuper1 = subClass;
Class<? extends Super> subOfSuper2 = subClass.asSubclass(Super.class);