Issue with class cast exception between subclasses and collections in Java - java

So, I have the following two classes:
Class A { }
Class B extends A { }
Class C extends A { }
And the following method:
public void foo(Collection<A> bar) {
List<A> listA = new ArrayList<>();
for(A a : bar) {
//a and anotherA are both of the same subtype of A
A anotherA = getAnotherA(a);
listA.add(anotherA);
}
bar.clear();
bar.addAll(listA);
}
Now, I am trying to call this method two separate ways, but I cannot get the casting to work properly... Hopefully I am just overlooking something small.
So, here are the two ways I am calling it:
Way 1:
A obj = ...;
Field field = //get field representing a collection of sub-type of A
Collection<A> collection = field.get(...);
foo(collection);
way 2:
B obj = ...;
Set<C> setOfC = b.getSetOfC();
foo(setOfC);
I have tried numerous casting attempts, but I cannot seem to get it to compile! For instance, in way 2, I tried casting setOfC to Set<A>, but I get a class cast exception. I have tried to cast bar to Collection<? extends A>, but then bar.addAll(..) fails. I have tried to add a generic to foo, but also get errors. In way 1, I have also tried to cast collection to Collection<? extends A>, but still not luck.

You cannot pass a Set<C> into a method expecting a Collection<A>, even though a Set is a Collection, and even though a C is an A, because Java's generics are invariant.
You can introduce a type parameter on the foo method, with an A upper bound. Then you can use the type parameter throughout the method. This will ensure that the same subtype of A is used.
public static <T extends A> void foo(Collection<T> bar) {
List<T> listA = new ArrayList<>();
for(T a : bar) {
//a and anotherA are both of the same subtype of A
T anotherA = getAnotherA(a);
listA.add(anotherA);
}
bar.clear();
bar.addAll(listA);
}
Your comment seems to indicate that a and anotherA are of the same type, so this should compile for you. If not, then the getAnotherA method will need some work so that passing in a C will return a C and not an A.

if you have this classes:
Class YourA { }
Class YourB extends YourA { }
Class YourC extends YourA { }
your method's signature most be like
public <G extends YourA> void foo(Collection<G> bar) {...}

Related

Java generics Enum subtyping Interface

Given the following setup:
public class TestType {
public static void main(String[] args) {
List<Constants> list = new ArrayList<>();
accept(list); //Does not compile
}
static void accept(Iterable<MyInterface> values) {
for (MyInterface value : values) {
value.doStuff();
}
}
}
interface MyInterface<T> {
T doStuff();
}
enum Constants implements MyInterface<Integer> {
ONE, TWO, THREE;
#Override
public Integer doStuff() {
return ordinal();
}
}
Why won't the compiler accept the list as parameter to accept()?
List extends Iterable via Collection so that isn't the problem.
On the other hand, the compiler tells me that
incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>
But Constants IS a MyInterface... isn't it?
The problem is with how Generics work. Specifically, Generics are non-reified... meaning that the compiler will not see an Iterable<enum.Constants> as an Iterable<enum.MyInterface> even if Constants is a sub-class of MyInterface.
However, there is a way to get around it: Generic wildcards.
If you change static void accept(Iterable<MyInterface> values) to static void accept(Iterable<? extends MyInterface> values), it should work.
You need to use Iterable<? extends MyInterface> instead of Iterable<MyInterface> because even though Constants is a subtype of MyInterface, Iterable<Constants> is not a subtype of Iterable<MyInterface> - and I'll show you why:
If it was so (let's use List instead of Iterable for the next example), I would be able to do this:
List<Constant> constantsList = new ArrayList<Constants>(); // list of constants
List<MyInterface> ifaceList = constantsList; // you said this would be OK ...
// assume MyOtherImplementation is another implmentation of MyInterface
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.
Generic types do not inherit this way, although it may seem counter-intuitive at first glance. Using Iterable<? extends MyInterface> will allow you to use any Iterable (e.g., a List) of a type that extends MyInterface (e.g. Constants).

How to perform a checked cast?

I am new to Generics and am having an issue.
Consider the following code:
public class A {}
public class B extends A {}
public <T extends A> T getB()
{
A test = new B();
Class<B> clazz = B.class;
if (clazz.isInstance(test))
{
return (T)test;
}
return null;
}
This generates an Unchecked cast warning. on the return (T)test; line.
but clearly I am checking the type with the if (clazz.isInstance(test)) line.
Is there a way to do a "checked cast"?
I'm not looking to just suppress the warning but actually implement a checked cast. Unfortunately I can't find information on how to perform a checked cast.
Is there a way to do a "checked cast"?
Sure, although it's important to note that it doesn't really help you here, because your method is hard-coded to use B in a few places. You can perform the cast with:
clazz.cast(test)
... but that will cast to B, not T. In particular, suppose I ran:
public class C extends A {}
...
C c = foo.<C>getB();
How would you expect that to work?
You might want to change your code to something like:
public <T extends A> T getB(Class<T> clazz)
{
A test = // get A from somewhere
return clazz.isInstance(test) ? clazz.cast(test) : null;
}
Then that's fine, because clazz.cast will return a value of type T, which you're fine to return.

how to convert generics in java?

What is the correct way to convert generics in java?
interface A {
}
class B implements A {
}
class C {
public Set<B> returnSomeB(){
//some logic
}
}
C c = new C();
Set<A> = c.returnSomeB();
Set<A> = c.returnSomeB(); this line would give me a compile time error, what's the most proper way to seamlessly convert this since class B is a concrete class of A interface?
A variable of type Set<A> can only hold a Set<A> object, not a Set<B>, even though B is a subtype of A.
The reason is this: What if you stored a Set<B> object in a Set<A> variable, then added an object of type A (but not B) to it? It would fit all the right argument types, but the end result would be a violation of Java's type safety.
To get around this, you can use wildcards. Instead of declaring a variable of type Set<A>, declare one of type Set<? extends A>.
Try bounding your type parameter to the widest possible scope of acceptable values:
interface A {
}
interface B extends A {
}
class C {
public static void main(String[] args) {
final Set<A> foo = C.returnSomeB();
final Set<B> bar = C.returnSomeB();
}
public static <T extends A> Set<T> returnSomeB() {
return null;
}
}

Generics: Instantiating a generic class of type <? super someClass, AnotherClass<? extends YetAnotherClass>>

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.

Java generics: How to encode a Functor interface in Java?

I want to define a Functor class in Java. This works:
//a Function
public interface F<A,R> {
public R apply(A a);
}
public interface Functor<A> {
public <B> Functor<B> fmap(F<A,B> f);
}
However the return value of fmap should be not Functor, but the appropriate subclass. Usually this can be encoded with the CRTP, but here I seem to hit a wall because of the additional parameter A. E.g. the following and similar encodings don't work ("type parameter FInst is not within its bounds"):
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
[Clarification]
With "appropriate subclass" I mean the type of the class being called itself. E.g. Lists are functors, so I would like to write something like
public class ListFunctor<A> implements ??? {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
<B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
I'm aware that I could write this even with the first definition I gave (because covariant return types are allowed), but I want that the return type "ListFunctor" is enforced by the type system (so that I can't return a FooFunctor instead), which means that the Functor interface needs to return the "self-type" (at least it is called so in other languages).
[Result]
So it seems what I want is impossible. Here is a related blog-post: http://blog.tmorris.net/higher-order-polymorphism-for-pseudo-java/
[Aftermath]
I stumbled over this age-old question of mine, and realized that this was the starting point of the amazing journey with my library highJ, containing much more than a simple Functor. I would have never imagine that people would use this crazy stuff for anything serious, but it happened, and that makes me very happy.
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
This code generates an error because when you define I, you define it to be a subclass of Functor<B,FInst>, but the FInst parameter must be a subclass of Functor<B,FInst> in this case, while it is defined above as being a subclass of Functor<A,FInst>. Since Functor<A,FInst> and Functor<B,FInst> aren't compatible, you get this error.
I haven't been able to solve this completely, but I could do at least a half of the job:
import java.util.ArrayList;
import java.util.List;
interface F<A,R> {
public R apply(A a);
}
interface Functor<A, FClass extends Functor<?, FClass>> {
public <B> FClass fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
This works, and it properly limits the set of allowed return types to ListFunctor, but it doesn't limit it to subclasses of ListFunctor<B> only. You could declare it as returning ListFunctor<A> or any other ListFunctor, and it would still compile. But you can't declare it as returning a FooFunctor or any other Functor.
The main problem with solving the rest of the problem is that you can't limit FClass to subclasses of ListFunctor<B> only, as the B parameter is declared at the method level, not at the class level, so you can't write
public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {
because B doesn't mean anything at that point. I couldn't get it working with the second parameter to the fmap() either, but even if I could, it would just force you to specify the return type twice - once in the type parameter and once more as the return type itself.
Looking from a different angle, it seems Functor shouldn't be modeled as a "Wrapper" around the data, but actually more like a type-class, which works on the data. This shift of perspective allows to encode everything without a single cast, and absolutely type-safe (but still with a lot of boilerplate):
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A,B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for(A a: instance) result.add(f.apply(a));
return result;
}
}
List<String> stringList = Arrays.asList("one","two","three");
ListFunctor<String,Integer> functor = new ListFunctor<String,Integer>();
List<Integer> intList = functor.fmap(stringList, stringLengthF);
System.out.println(intList);
//--> [3, 3, 5]
It seems I was too focused on packing both FromInstance and ToInstance in one type parameter (e.g. List in ListFunctor), which isn't strictly necessary. However, it's a heavy burden to have now not only A but also B as type parameter, which may make this approach practically unusable.
[Research]
I found a way to make this version at least a little bit useful: This functor can be used to lift a function. E.g. if you have F<String, Integer>, you can construct a F<Foo<String>, Foo<Integer>> from it when you have a FooFunctor defined as shown above:
public interface F<A,B> {
public B apply(A a);
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
Functor<A,B,FromInstance, ToInstance> functor);
}
public abstract class AbstractF<A,B> implements F<A,B> {
#Override
public abstract B apply(A a);
#Override
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
final Functor<A, B, FromInstance, ToInstance> functor) {
return new AbstractF<FromInstance, ToInstance>() {
#Override
public ToInstance apply(FromInstance fromInstance) {
return functor.fmap(fromInstance, AbstractF.this);
}
};
}
}
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A, B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for (A a : instance) {
result.add(f.apply(a));
}
return result;
}
}
//Usage:
F<String, Integer> strLenF = new AbstractF<String, Integer>() {
public Integer apply(String a) {
return a.length();
}
};
//Whoa, magick!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
F<List<String>,List<Integer>> liftedF = strLenF.lift(new ListFunctor<String, Integer>());
List<String> stringList = Arrays.asList("one", "two", "three");
List<Integer> intList = liftedF.apply(stringList);
System.out.println(intList);
//--> [3, 3, 5]
I think it's still not very useful, but at least way cooler than the other attempts :-P
Building on the answer of Sergey, I think I came close to what I wanted. Seems like I can combine his idea with my failed attempt:
public interface Functor<A, Instance extends Functor<?, Instance>> {
public <B, I extends Functor<B,Instance>> I fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B, I extends Functor<B, ListFunctor<?>>> I fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return (I) new ListFunctor<B>(result);
}
}
List<String> list = java.util.Arrays.asList("one","two","three");
ListFunctor<String> fs = new ListFunctor<String>(list);
ListFunctor<Integer> fi = fs.<Integer,ListFunctor<Integer>>fmap(stringLengthF);
//--> [3,3,5]
The remaining problem is that I could write e.g. ListFunctor<StringBuilder> fi = fs.<Integer,ListFunctor<StringBuilder>> without complaints from the compiler. At least I can look for a way to hide the ugly guts behind a static method, and to enforce that relation behind the scenes...
Does anyone still use Java and ponder this problem? You might find this useful...
I've been pondering this for a looooong time. I believe I've made something satisfactory. What I would really like to is indeeed impossible in Java.
This is ideal:
interface Functor<T, CONCRETE<A> extends Functor<A, CONCRETE>> {
CONCRETE<U> fmap(Func<T, U>);
}
Unfortunately, this is make-believe syntax. This kind of thing is possible in C++ with template-template parameters, but not Java.
I was tempted to write this simple thing:
interface Functor<T> {
Functor<U> fmap(Func<T, U>);
}
This works in some cases, because an implementation can return a covariant return type (for example, List could return a List from this function), but it breaks down when you try passing around generic variables of type "F extends Functor", or a subclass of Functor, etc...
What I ended up doing was introduce a "dummy type variable", like so:
interface Functor<CONCRETE, T> {
Functor<CONCRETE, U> fmap(Func<T, U>);
}
The "concrete type" should be the type itself, or some dummy type that guarantees the uniqueness of its implementors. Here's an example implementation:
public final class Array<T> implements Functor<Array<?>, T> {
private final T[] _values;
#SafeVarargs
public Array(T... values) {
_values = values;
}
#SuppressWarnings("unchecked")
#Override
public <A, RESULT extends Functor<Array<?>, A>> RESULT fmap(Function<T, A> f) {
A[] result = (A[]) new Object[_values.length];
for (int i = 0; i < _values.length; ++i) {
result[i] = f.apply(_values[i]);
}
return (RESULT) new Array<A>(result);
}
}
The cast to (RESULT) is safe because there can only be one type that matches "Functor, T>", and that's "Array". The disadvantage of this, is that generic code may need to pass around this "CONCRETE" type in a bunch of places, and it makes your signatures unwieldy. For instance:
public class Test {
public static <CONCRETE, FInt extends Functor<CONCRETE, Integer>, FBool extends Functor<CONCRETE, Boolean>> FBool intToBool(FInt ints) {
return ints.fmap(x -> x > 5);
}
public static void main() {
Array<Integer> ints = new Array<>();
Array<Boolean> bools1 = ints.fmap(x -> x > 5); // this works because Array<> implements fmap covariantly
Array<Boolean> bools2 = intToBool(ints); // but this also works thanks to our dummy CONCRETE type
}
}
I think you want to do something that makes no sense (type wise).
interface Getter<Type> {
Type get();
}
If your application wants a getter that returns Integers, don't give it one that returns Objects.
If you don't know if it will return Objects or Integers you are trying to do something the wrong way.
If YOU KNOW it will return Integers, then wrap the getter so that it casts to integers.
Hope this is what you are looking for .
EDIT:
Explanation of why (I think) this can not be done.
Objects have there types set when you use new.
Take each type and replace it with a letter.
Take any number of another objects and do the same.
What letter do you want your function to return?
If the answer is that you want a mix, well then its too late. Types are decided at new, and you are already past new.

Categories

Resources