Raw types inside of generic definition - java

I wonder why the following generic definition does not produce a compiler warning:
class MyClass<T extends List> { }
and how the above definition is different to
class MyClass<T extends List<?>> { }
Whenever you read about generics, you read about how raw types should be avoided and consequently, whenever you handle generic types, you get a compiler warning. The raw type inside of the first definition does however not create such a warning.
Secondly, I wonder how the exact subtyping definition between raw types and generic types are. According to this summary, raw types are kind of an "opt-out" of type checking such that type checking is simply inactive whenever a raw type is involved. Is this assumption correct? And how does this effect the above "raw" generic definitions?
Thank you for your help!
UPDATE: I understand what you are saying. However, this is not what I am confused about. Look at this scenario:
class MyClass<T extends MyClass<T>> {}
public void callWildcard1(MyClass<?> node) {
callBound1(node);
}
public <T extends MyClass<T>> void callBound1(T node) {
// Do something
}
public void callWildcard2(MyClass<?> node) {
callBound2(node);
}
public <T extends MyClass> void callBound2(T node) {
// Do something
}
The first call from callWildcard1 to callBound1 is not allowed because of the generic constraint. The second is however allowed. How can I perform the first call without "inner raw types"? I don't see why the compiler would forbid the first. Shouln't any parameter valid wildcard parameter imply ? extends MyClass<?>?
UPDATE 2: I found out by trial and error, that I can solve the problem by defining:
public <T extends MyClass<? extends T> void callBound2(T node) {
// Do something
}
even though I do not quite understand why. But there is even more confusion, when looking at this example: (this is a very simple version of what I am actually trying to do.)
public void call() {
genericCall1(new MyFilter<MyClass<?>>(), MyClass.class);
genericCall2(new MyFilter<MyClass<?>>(), MyClass.class);
}
public <T extends MyClass<? extends T>> void genericCall1(MyFilter<T> filter, Class<? extends T> filterBoundary) {
// Do something.
}
public <T extends MyClass<? extends T>, U extends T> void genericCall2(MyFilter<T> filter, Class<? extends U> filterBoundary) {
// Do something.
}
class MyClass<T extends MyClass<T>> { }
class MyFilter<T extends MyClass<? extends T>> { }
Why is genericCall1 prohibited and genericCall2 is not? Again, I found the solution by an academic guess instead of true understanding. Sometimes, when working with Java and its generics I want to cry...

The difference is that when you use class MyClass<T extends List> { } inside MyClass you lose type safety.
for example:
class A <T extends List<?>>{
void someFunc(T t) {
t.add(new Object());//compilation error
}
}
class B <T extends List>{
void someFunc(T t) {
//compiles fine
t.add(new Object());
t.add("string");
t.add(new Integer(3));
}
}

Related

Incompatible types when using upper bounding wildcard

I'm really confused of how upper bounded types work in Java generics.
Let's say I have
interface IModel<T>
interface I
class A implements I
class B implements I
class C implements I
then I have a method with parameter as follows
foo(IModel<Map<? extends I, Map<? extends I, List<? extends I>>>> dataModel)
calling that method like
IModel<Map<A, Map<B, List<C>>>> model = ...
foo(model)
ends with compilation error
Error:(112, 49) java: incompatible types: IModel<java.util.Map<A,java.util.Map<B,java.util.List<C>>>> cannot be converted to IModel<java.util.Map<? extends I,java.util.Map<? extends I,java.util.List<? extends I>>>>
I have read docs about Java generics from the Oracle web, trying to google it, but there must be something I totally misunderstood.
This question can be shorted as why
foo(IModel<List<? extends I>> dataModel)
can not accept argument like
IModel<List<A>> model
Explanation
List<A> is a subtype of List<? extends I>, so it is ok:
public void bar(List<? extends I> list);
List<A> listA;
bar(listA);
But, it does not make IModel<List<A>> a subtype of IModel<List<? extends I>>, just like IModel<Dog> is not a subtype of IModel<Animal>, so the code you posted can not be compiled.
Solution
You can change it to:
foo(IModel<? extends Map<? extends I, ? extends Map<? extends I, ? extends List<? extends I>>>> dataModel)
or
<FIRST extends I, SECOND extends I, THIRD extends I> void foo(IModel<Map<FIRST, Map<SECOND, List<THIRD>>>> dataModel)
to make it compile.
First of all, I wonder how much effort it would have been for you (one person) to sort out the code to be in this form:
import java.util.List;
import java.util.Map;
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
IModel<Map<A, Map<B, List<C>>>> model = null;
foo(model);
}
static void foo(IModel<Map<? extends I, Map<? extends I, List<? extends I>>>> dataModel)
{
}
}
instead of letting hundreds of people (who want to help you) do this on their own, in order to have something that they can compile and have a look at in their IDE. I mean, it's not that hard.
That being said: Technically, you're missing a few more extends clauses here. This compiles fine:
import java.util.List;
import java.util.Map;
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
IModel<Map<A, Map<B, List<C>>>> model = null;
foo(model);
}
static void foo(IModel<? extends Map<? extends I, ? extends Map<? extends I, ? extends List<? extends I>>>> dataModel)
{
}
}
But you should
not
implement it like that. That's obscure. Whatever this dataModel parameter is, you should consider creating a proper data structure for that, instead of passing along such a mess of deeply nested generic maps.
The reason of why the original version did not compile was already mentioned in other answers. And it can be made clearer by showing an example using a much simpler method call. Consider this example:
interface IModel<T> {}
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
public class UpperBounds
{
public static void main(String[] args)
{
List<List<A>> lists = null;
exampleA(lists); // Error
exampleB(lists); // Works!
}
static void exampleA(List<List<? extends I>> lists)
{
}
static void exampleB(List<? extends List<? extends I>> lists)
{
}
}
The exampleA method cannot accept the given list, whereas the exampleB method can accept it.
The details are explained nicely in Which super-subtype relationships exist among instantiations of generic types? of the generics FAQ by Angelika Langer.
Intuitively, the key point is that the type List<A> is a subtype of List<? extends I>. But letting the method accept only a List<List<? extends I>> does not allow you to pass in a list whose elements are subtypes of List<? extends I>. In order to accept subtypes, you have to use ? extends.
(This could even be simplified further: When a method accepts a List<Number>, then you cannot pass in a List<Integer>. But this would not make the point of List<A> being a subtype of List<? extends I> clear here)
Having a method method1(Map<I> aMap>) and A being a class implementing I doesn't allow you to call the method with a Map<A> and that's for a reason.
Having the method:
public static void foo2(IModel<I> dataModel) {
System.out.println("Fooing 2");
}
Imagine this code:
IModel<A> simpleModel = new IModel<A>() {};
foo2(simpleModel);
This shouldn't work because you supply a more specific type to a method that requires a generic type. Now imagine foo2 does the following:
public static void foo2(IModel<I> dataModel) {
dataModel = new IModel<B>() {};
System.out.println("Fooing 2 after we change the instance");
}
Here you will try to set IModel to IModel which is valid - because B extends I, but if you were able to call that method with IModel it wouldn't work
Create your model like:
IModel<Map<I, Map<I, List<I>>>> model = ...
and in the corresponding maps and lists add objects of type A, B and C which will be valid and then call the function foo(model)

Java generics - cast assignable capture type to subclass

I have the following scenario in Java generics:
public abstract class A<T> {
protected final Class<T> typeOfX;
public A(final Class<T> typeOfX) {
this.typeOfX = typeOfX;
}
public abstract void load(final T x);
}
public class AnyA<S> extends A<S> {
private final Map<String, A<? extends S>> map;
public AnyA(final Class<S> superTypeOfX,
final Map<String, A<? extends S>> map) {
super(superTypeOfX);
this.map = map;
}
#Override
public void load(final S superx) {
for (final A<? extends S> a: map.values())
if (a.typeOfX.isAssignableFrom(superx.getClass())) //Here I want to say: "if superx can be casted to a.typeOfX".
a.load(a.typeOfX.cast(superx)); //Here I want to cast superx to a.typeOfX (so as to call the load method). Here's the compile error.
}
}
I'm getting the error:
incompatible types: S cannot be converted to CAP#1
where S is a type-variable:
S extends Object declared in class AnyA
where CAP#1 is a fresh type-variable:
CAP#1 extends S from capture of ? extends S
AnyA is a composite A, i.e. is an A which maintains several other A instances.
AnyA in its load(...) method shall decide which of the maintained A instances should be used to "pass the loading process to" of the argument.
In other words, AnyA is responsible for finding the correct A to load the argument.
But also AnyA is an A because it handles loading the argument.
My question is:
Why is this cast not possible, by the time I know that S is a sub-class of T and all A instances in AnyA can load a subclass of S?
How can I overcome this problem without changing the class diagram too much?
I have read about "helper methods" but cannot match the example shown there to my problem.
I'm using NetBeans IDE with Java SDK 8.
Note that regardless of what you do, the code is not "syntactically type safe" in any case. There is an unchecked cast, and the only safety belt that prevents this from going wrong is the isAssignableFrom check.
(That is often OK, I'm just mentioning it for completeness)
The reason for the error may be more obvious when you pull the lines apart (here, S stands for SuperType, according to the Type Parameter Naming Conventions - please follow them!)
A<? extends S> a = ...;
S s = a.typeOfX.cast(s);
a.load(s);
The A<? extends S> intuitively means that it is an A that can accept an unknown type in its load method. You know that it extends type S, but you do not know which type this is.
It may become blatantly obvious when you insert Object for S:
A<String> specificA = ...;
// So the "specificA" can load "String" objects. Then this is fine:
A<? extends Object> a = specificA;
Object s = a.typeOfX.cast(s);
// But here's the error: "s" is only an Object, and not a String!
a.load(s);
I think the main point of confusion (and the main reason for the question) was the following: When calling
Object s = a.typeOfX.cast(s);
and typeOfX is String.class, then the return type of the cast will not be String, but only the type that the compiler can infer at this point. And this is Object, in the example above.
However, you already referred to the Helper Methods, and indeed, with some trickery, you can make this compile,
but... (see notes below)
import java.util.Map;
abstract class A<T>
{
protected final Class<T> typeOfX;
public A(Class<T> typeOfX)
{
this.typeOfX = typeOfX;
}
public abstract void load(T x);
}
class AnyA<S> extends A<S>
{
private final Map<String, A<? extends S>> map;
public AnyA(Class<S> superTypeOfX,
Map<String, A<? extends S>> map)
{
super(superTypeOfX);
this.map = map;
}
#Override
public void load(S s)
{
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(s.getClass()))
{
callLoad(a, s);
}
}
}
private static <S, T extends S> T cast(A<T> a, S s)
{
T t = a.typeOfX.cast(s);
return t;
}
private static <T, S extends T> void callLoad(A<S> a, T s)
{
a.load(cast(a, s));
}
}
I would not recommend this in practice.
Personally and subjectively: I think that when you are doing the isAssignableFrom check, then the (unchecked) cast should be as close as possible to this check. Otherwise, the code will be very hard to understand.
So although unchecked casts are a code smell in practice, and I try to avoid SuppressWarning whenever possible, I would consider this as far more readable:
for (A<? extends S> a : map.values())
{
if (a.typeOfX.isAssignableFrom(superx.getClass()))
{
// This call is safe as of the check done above:
#SuppressWarnings("unchecked")
A<Object> castA = (A<Object>) a;
castA.load(superx);
}
}

Incompatible classes of java generics

It seems I'm stuck with java generics again. Here is what I have:
Couple of classes:
class CoolIndex implements EntityIndex<CoolEntity>
class CoolEntity extends BaseEntity
Enum using classes above:
enum Entities {
COOL_ENTITY {
#Override
public <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls() {
return CoolIndex.class;
}
#Override
public <E extends BaseEntity> Class<E> getEntityCls() {
return CoolEntity.class;
}
}
public abstract <E extends BaseEntity, I extends EntityIndex<E>> Class<I> getIndexCls();
public abstract <E extends BaseEntity> Class<E> getEntityCls();
}
Function I need to call with use of result of getIndexCls() function call:
static <E extends BaseEntity, I extends EntityIndex<E>> boolean isSomeIndexViewable(Class<I> cls)
The problem is that compiler complains about return CoolIndex.class; and return CoolEntity.class; and it's not clear to me why... Of course I can cast it to Class<I> (first case) but it seems to me like I'm trying to mask my misunderstanding and it doesn't feel right.
The problem with getIndexCls is that because it's generic, the type parameters can be interpreted to be any classes that fit the bounds on the declarations. You may think that CoolIndex.class fits those bounds, and it does, but a caller of the method can supply their own type arguments which would be incompatible, e.g.:
Entities.COOL_ENTITY.<UncoolEntity, UncoolIndex>getIndexCls();
That would break type safety, so the compiler disallows this. You can cast to Class<I>, but the compiler will warn you about an unchecked cast for the same reason. It will compile, but it can cause runtime problems as I've described.
Other situations can resolve such a situation by passing a Class<I> object to make the type inference work properly, but that defeats the point of this method -- returning a Class<I> object.
Other situations call for moving the generic type parameters from the method to the class, but you are using enums, which can't be generic.
The only way I've come up with to get something similar to compile is by removing the enum entirely. Use an abstract class so you can declare class-level type parameters. Instantiate constants with the type arguments you desire.
abstract class Entities<E extends BaseEntity, I extends EntityIndex<E>> {
public static final Entities<CoolEntity, CoolIndex> COOL_ENTITY = new Entities<CoolEntity, CoolIndex>() {
#Override
public Class<CoolIndex> getIndexCls() {
return CoolIndex.class;
}
#Override
public Class<CoolEntity> getEntityCls() {
return CoolEntity.class;
}
};
// Don't instantiate outside this class!
private Entities() {}
public abstract Class<I> getIndexCls();
public abstract Class<E> getEntityCls();
}
This can be reproduced by much simpler example:
public <E extends BaseEntity> E get() {
return new BaseEntity(); // compilation error here
}
The problem in such declaration <E extends BaseEntity> is that your method claims to return an instance of any type E that caller should ask:
MyCoolEntity1 e = get(); // valid, E is MyCoolEntity1
MyCoolEntity2 e = get(); // valid, E is MyCoolEntity2
This code should be compile-time safe, so you have to cast result of your method to E
public <E extends BaseEntity> E get() {
return (E) new BaseEntity(); // no error, but unsafe warning
}
In your example it's pretty the same, you claim to return value of type Class<E>:
public <E extends BaseEntity> Class<E> getEntityCls()
But return a concrete class SomeEntity.class which is Class<CoolEntity>
OK, how should I fix that?
You can add type cast return (Class<I>) CoolIndex.class; / return (Class<E>) CoolEntity.class;
You can replace enum with classes, since enums can not be generic and classes can
You can entirely remove generics, since there's no much value in it

How to check whether Java generic type is subclass of Comparator?

When I try to complete a task, there's one case need to be handled: throw exception of generic type of class is not comparable. Refer to the following code for the detail.
public class C <T>
{
public C()
{
// throw exception if T is not comparable
}
}
You can enforce the generic to be a subclass of Comparator like so:
public class C <T extends Comparator> {
public C(){
}
}
As you see in the below code, it would be a good idea to add another generic (here it is K), which you supply to Comparator, since the generic of Comparator will otherwise default to Object.
public class C <K, T extends Comparator<K>> {
public C(){
}
}
You generally use this in the form of T x K, where T is the generic, x is super or extends and K is the class/interface.
Comparator docs
You should make sure that the generic parameter T is a Comparableby writing:
public class C <T extends Comparable>
There are two ways:
1) Make it T extends Comparable, so you know it will always be.
2) In the constructor, pass Class < T > as a parameter, so you'll know at runtime what T is. (because it's erased)
Add a generic constraint, that is would be better since it will be handle it at compile time rather than throw an exception on runtime.
class C <T extends Comparable>
You should verify that your parameter T is Comparable.
public class C <T extends Comparable>
This is the same if you want a generic type implements some interface.
public class C <T implements <interface what you want> >
Or if you want that were a superclass of another one.
public class C <T super <class what you want> >
If you always want the type T to implement Comparable you can enforce this as follows.
public class C<T extends Comparable<? super T>> {
public C() {
}
}
This is better than throwing an exception at runtime. It will not even compile if someone tries to write new C<some non-Comparable type>(). Note that Comparable is a generic type, so it should not be used without type parameters; it should not simply be
public class C<T extends Comparable>
If the type T will not always implement Comparable, but you want a specific constructor that will only work for Comparable types, then the answer is that you can't do this with constructors, but you can do it with a static method.
public class C<T> {
public C() {
// Constructor that works with any T
}
public static <T extends Comparable<? super T>> C<T> getNew() {
C<T> c = new C<>();
// Do stuff that depends on T being Comparable
return c;
}
}

Java: Specifying generic type restrictions in a subtype

I have a question regarding generic types in Java. Specifically, at present, I have some code similar to this:
public interface Foo {
public <T> void bar(T[] list)
}
public class FooImpl implements Foo{
#Override
public <T extends Comparable<? super T>> void bar(T[] list) {
...
}
}
The problem is, that the compiler now complaints, that I have not implemented the bar-method in my FooImpl class.
What I want is to put some extra restriction on the generic type, specifically that they should be comparable. But I don't want to put that restriction in my Foo interface, as all implementations does not need that restriction.
Is this possible, and what should I do to fix it?
Thanks a lot in advance!
EDIT 1: Fixed typos Class --> class and Interface --> interface. But the return types are still void, not T, which is irrelevant, I suppose. My actual return type is a boolean.
EDIT 2: The actual code, as requested:
public interface SortedCriteria {
public <E> boolean isSorted(E[] list);
}
public class AscendingCriteria implements SortedCriteria {
#Override
public <E extends Comparable<? super E>> boolean isSorted(E[] list) {
int length = list.length;
for (int i = 1; i < length; i++) {
if (list[i].compareTo(list[i-1]) < 0) return false;
}
return true;
}
}
What you want to do is rejected because it would completely break polymorphism. A caller having a Foo instance could have an instance of your subclass or an instance of any other subclass. And since the interface guarantees that the method can be called with any kind of array as argument, your subclass can't break this contract by limiting the kind of array it accepts (unless it does that at runtime, by checking the type of the array and by throwing an exception, of course).
This boils down to the Liskov substitution principle, which is the basis of polymorphism and OO.
But maybe what you actually want is to make Foo a generic type:
public interface Foo<T> {
public void bar(T[] list);
}
public class FooImpl<T extends Comparable<? super T>> implements Foo<T> {
#Override
public void bar(T[] list) {
...
}
}

Categories

Resources