Java generics and classcastexception - java

not sure whats wrong here, but haven't used generics for a while, so its probably something I don't remember, but basically this code is "supposed to" work as far as I'm concerned, yet it does not:
public static class MyModel {}
protected static <T extends MyModel> FlowableTransformer<Response<T>, T> convert(Class<T> responseClass) {
return observable -> observable.map((Function<Response<T>, T>) response -> {
MyModel m = new MyModel();
return (T)m;
});
}
When using this, I get a Classcastexception at runtime. Basic idea would be that the method could return with either a "MyModel" or any of its subclasses (so T extends MyModel). Yet it cannot return with MyModel itself now?
Obviously just the gist of the problem and not actual code. Any help is appreciated.

Suppose we have these 3 classes:
public class A {}
public class B extends A {}
public class C extends B {}
and the following function:
public static <T extends A> T foo() {
A ret_val = new A();
return (T)ret_val;
}
The following code will work correctly, without any exception:
A obj = foo();
because, here the ret_val inside foo() method is casted to A which is the actual type of ret_val.
But the following code will throw an exception:
B objB = foo(); // throws ClassCastException exception
C objC = foo(); // throws ClassCastException exception
because, what you are trying to do here, is casting an object of type A to B(or C), which is illegal.

Related

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.

Java generic interface in collection

Can anybody explain me why I get an error only when creating B in the following code:
public class factory {
public <T> void createA(List<I<T>> c) {
A a = new A(c);//warning here
}
public <T> void createB(List<I<T>> c) {
B b = new B(c);//error here: The constructor B(List<I<T>>) is undefined
}
}
interface I<T> {
}
class B implements I<Integer> {
public B(List<I<?>> c) {
}
}
class A<T> implements I<T> {
public A(List<I<?>> c) {
}
}
B class is generic and A is not, but I have no idea why it matters in that case.
public B(List<I<?>> c) {
}
The ? is the unknown type. It is not a wild card for any other type. The compiler tells the truth, there is no constructor for the type List<I<T>> (T is not ?)
It doesn't really work for the other method too. You simply exchanged the compile error by a "unchecked conversion" warning. Because class A is parametized, you'd have to call it like that:
public <T> void createA(List<I<T>> c) {
A<T> a = new A<T>(c);
}
And voilĂ , say hello to the same error.
A is a generic class, which means that when you use A by itself, it is a raw type. When you use a raw type, you turn off all the generics for its methods and constructors. So for example, the following will compile:
A a = new A(new ArrayList<String>());
B is not a generic class, so using B by itself is not a raw type, and does not turn off generics.

Method return type to fulfill multiple interfaces - Again

Today I ran into the following problem. Consider the setup:
interface A {
void foo();
}
interface B {
void bar();
}
class Impl implements A,B {
public void foo() { }
public void bar() { }
}
class Usage {
void worksAsParameter(){
acceptIt(new Impl());
}
<T extends A & B> void acceptIt(T foo){
}
<T extends A & B> T returnIt(){
return new Impl(); // <-- Compile error
}
}
The code compiles except in the last statement as marked. Eclipse gives me the error: Type mismatch: cannot convert from Impl to T
My question is: Why is Impl assignable to T when given as a parameter (shown in worksAsParameter but not when T is a return type ?
And also, what expression aside from null will satisfy the type T in the case where Impl does not?
Please note that this question is not the same as this SO question although similar.
Edit: Fixed typo.
=== Summary ===
It would seem I had misunderstood how generic return types work. I will try to write up my new understanding of it.
Lets look at the issue:
<T extends A & B> T returnIt(){
return new Impl(); // <-- Compile error
}
My initial assumption was that the implementing class (in this case Usage) decided on the concrete type for T with the restriction that it must extend A and B. Apparently it is the caller/callsite that gets to decide what T is and Usage must supply a value that is assignable to T. However, as T is a compile time deal only it is impossible to supply such a value aside from null (as it is assignable to anything).
Afaik this means that any code of the form will only ever be able to return null:
<T extends A> T returnIt(){
return x; // <-- Compile error
}
A fairly unintuitive feature that is hopefully more useful in a different setting. Thanks Peter!
The reason
<T extends A & B> T returnIt(){
return new Impl();
}
doesn't compile is that T could be any class which extends A and B. You happen to know there is only one possible class at the moment, but the compile doesn't "know" this.
e.g.
class AB extends A, B { }
Usage usage = ...
AB ab = usage.<AB>returnIt(); // T is AB not Impl.
You can force the issue with
<T extends A & B> T returnIt(){
return (T) new Impl(); // unchecked cast warning.
}
but a better solution is
Impl returnIt(){
return new Impl();
}
This defines two generics
<T extends A, B>
T extends A and also B extends Object
What you may have intended is
<T extends A & B>
where T must extend A and B.
You can also do something like below to avoid compilation error.
<T extends A & B> T returnIt(Class<T> type) {
return type.cast(new Impl());
}

Java Generics: Multiple Inheritance in Bounded Type Parameters <T extends A & I>

I am about to create a factory which creates objects of a certain type T which extends a certain class A and another interface I. However, T must not be known. Here are the minimum declarations:
public class A { }
public interface I { }
This is the factory method:
public class F {
public static <T extends A & I> T newThing() { /*...*/ }
}
This compiles all fine.
When I try to use the method the following works fine:
A $a = F.newThing();
...while this does not:
I $i = F.newThing();
The compiler complains:
Bound mismatch: The generic method newThing() of type F is not applicable for the arguments (). The inferred type I&A is not a valid substitute for the bounded parameter
I can't understand why. It is clearly stated that "newThing returns something of a certain type T which does extend the class A and implement the interface I". When assigning to A everything works (since T extends A) but assigning to I does not (because of what?, clearly the thing returned is both an A and an I)
Also: When returning an object, say B of the type class B extends A implements I, I need to cast it to the return type T, although B matches the bounds:
<T extends A & I> T newThing() {
return (T) new B();
}
However, the compiler does not throw any warnings like UncheckedCast or the like.
Thus my question:
What is going wrong here?
Is there an easy away to achieve the desired behavior (i.e. assigning to a variable of static type A or I), like there is in solving the return-type-problem by casting, in the factory method?
Why does the assignment to A work, while to I does not?
--
EDIT: Here the complete code snippet which totally works using Eclipse 3.7, project set up for JDK 6:
public class F {
public static class A { }
public static interface I { }
private static class B extends A implements I { }
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
}
}
EDIT: Here is a complete example with methods and invocation which does work at runtime:
public class F {
public static class A {
int methodA() {
return 7;
}
}
public static interface I {
int methodI();
}
private static class B extends A implements I {
public int methodI() {
return 12;
}
}
public static <T extends A & I> T newThing() {
return (T) new B();
}
public static void main(String... _) {
A $a = F.newThing();
// I $i = F.newThing();
System.out.println($a.methodA());
}
}
As for the second question:
Consider this case:
class B extends A implements I {}
class C extends A implements I {}
Now, the following uses type inference:
<T extends A & I> T newThing() {
return (T) new B();
}
So you could call this:
C c = F.newThing(); //T would be C here
You see that T could be anything that extends A and I you can't just return an instance of B. In the case above the cast could be written as (C)new B(). This would clearly result in an exception and thus the compiler issues a warning: Unchecked cast from B to T - unless you're supressing those warnings.
This doesn't do what you expect it to. T extends A & I indicates that the caller can specify any type that extends A and I, and you'll return it.
I think that one way to explain it is by replacing the type parameter with the actual type.
The parameterized signature of the methods is:
public static <T extends A & B> T newThing(){
return ...;
}
The <T extends A & B> is what is called a type parameter. The compiler would expect that this value is actually substituted with the actual type (called type argument) when you actually use it.
In the case of your method the actual type is decided by means of type inference. That is, <T extends A & B> should be replaced by a real existing type that extends A and implements B.
So, let's say that classes C and D both extends A and implements B, then if your signature were like this:
public static <T extends A & B> T newThing(T obj){
return obj;
}
Then, by type inference, your method would be evaluated as follows:
public static C newThing(C obj){
return obj;
}
if you invoke with newThing(new C()).
And would be as follows
public static D newThing(D obj){
return obj;
}
if you invoke with newThing(new D()).
This would compile just fine!
However, since you are not actually providing any kind of type to validate type inference in your method declaration, then the compiler could never be sure what is the actual type (type argument) of your type parameter <T extends A & B>.
You might expect that the actual type is C, but there may be thousands of different classes that satisfy that criteria. Which of those should the compiler use as the actual type of your type argument?
Let's say that C and D are two classes that extend A and implements B. Which of these two actual types should the compiler use as type argument for your method?
You could have even declared a type argument for which there is not even an existing type that you can use, like saying something that extends Serializable and Closable and Comparable and Appendable.
And perhaps there is not a class in the whole world that satisfies that.
As such, you must understand that the type parameter here is just a requirement for the compiler to validate the actual type that you use, a placeholder for the actual type; and this actual type must exist at the end and the compiler will use it to replace appearances of T. Therefore the actual type (type argument) must be inferable from the context.
Since the compiler cannot tell with certainty which is the actual type that you mean, basically because there is no way to determine that by type inference in this case, then you are forced to cast your type, to ensure the compiler that you know what you are doing.
As such, you could implement your method using type inference like this:
public static <T extends A & B> T newThing(Class<T> t) throws Exception{
return t.newInstance();
}
This way, you would be actually telling the compiler what is the actual type argument to be used.
Take into account that when the bytecodes are generated, the compiler must substitute T for a real type. There is no way to write method in Java like this
public static A & B newThing(){ return ... }
Right?
I hope I have explained myself! This is not simple to explain.
Simplest solution is create an abstract base class that extends and implements whatever class and interfaces you want and return that type. It doesn't matter that you're constraining your return type to extend this base class as you were already constraining the return type to its superclass.
eg.
class C {}
interface I {}
abstract class BaseClass extends C implements I {}
// ^-- this line should never change. All it is telling us that we have created a
// class that combines the methods of C and I, and that concrete sub classes will
// implement the abstract methods of C and I
class X extends BaseClass {}
class Y extends BaseClass {}
public class F {
public static BaseClass newThing() {
return new X();
}
public static void main(String[] args) {
C c = F.newThing();
I i = F.newThing();
}
}

Get the the type of the class of a generic type?

A class which has a method declared as this:
public class A{
public <T> T test(java.lang.Class<T> classOfT)
}
Normally it can be called against an object like this:
A a = new A()
String s = "test";
a.test(String.class); //I wrote this as s.class at first,which is wrong.Thanks Nick.
Now I would like to generalize the object passed to it, so I declare a class like this:
public class B <T>{
private A a = new A();
private T obj = null;
T test(){return a.test(obj.getClass()); }
}
But the code wont' compile.I am wondering is it possible to achieve my goal?
Thank you in advance Java gurus ;)
T obj = ...;
obj.getClass()
The last line returns Class<? extends T> -- but T is unbounded, so it is basically bounded by Object, which means it returns Class<? extends Object>, which is the same as Class<?>.
So doing this:
T test () { return a.test(obj.getClass()); }
Will actually invoke a.test with a parameter of type Class<?>, which returns an Object, and not a T.
Just cast the parameter to Class<T> or the return type to T and it should work -- although I am yet to understand why you need something like this. Also, there is this strange error in the original post:
String s = "test";
a.test(s.class);
Doing "test".class is wrong -- it should be String.class.
Class<T> clazz = (Class<T>) obj.getClass();
return a.test(clazz);
Try
#SuppressWarnings("unchecked")
T test() {
return (T) a.test(obj.getClass());
}
In complement of the other answers, when defining your function as
public class A{
public <T> T test(java.lang.Class<T> classOfT) { ... }
}
if you are using the classOfT parameter just to determine the type of T, you might be better off defining your method with no parameter at all. For instance, do this instead of the above declaration :
public class A{
public <T> T test() { ... }
}
That way you can just call it using this qualified method-call syntax. This is how I would rewrite your code:
public class A{
public <T> T test() {
// ...
}
public static void main(String[] args) {
A a = new A();
String result = a.<String>test();
}
}
public class B <T> {
private A a = new A();
T test() {
return this.a.<T>test();
}
}
This way you do not need to pass the generic A#test() function a class parameter, which would possibly have been unused at runtime.
Of course if you do use the classOfT at runtime, this solution may not be that much interesting for you...

Categories

Resources