I stumbled across a Java casting situation involving Generics and Interfaces that I do not understand.
Please consider the following code where I create a List<Interface1>. And then get() an element and cast it to Interface2 without compiler error although these two interfaces are completely unrelated.
import java.util.*;
public class Main {
public static void main(String ... args) {
List<Interface1> list = new ArrayList<>();
list.add(new Interface1() {});
Interface1 ok = list.get(0);
Interface2 why = (Interface2)list.get(0);
}
}
interface Interface1 {
}
interface Interface2 {
}
Can anyone explain why there is not compiler error for the cast at the second get(0)?
Two side notes: Executing the class throws a ClassCastException (as expected). And using two classes instead of interfaces does actually generate compile errors.
This behaviour is unrelated to generics: you can cast any interface to any other without compile errors.
You cannot do this with classes because Java can check at compile time whether one class can be casted to another.
With interfaces however the cast might succeed or fail, depending on the class that is actually implementing the interface. This can be discovered only at runtime though.
If you have a type which implements Interface1 it may as well implement Interface2. Hence the compiler will not blame you, because at runtime the cast may succeed.
This is because JAVA supports multiple interface implementations. As we can have any number of classes of any types(any parent class) that can implement an interface, JVM design is such that untill runtime one cannot identify which type is being passed in place that interface.So there can be any interface placed in the ArryList
The compiler does not know that this won't work: You could have a instance of type Interface2 that is also of type Interface1 (for ex: class ImplementingClass implements Interface1,Interface2). Then the cast would be fine.
"using two classes instead of interfaces does actually generate compile errors."
In this situations compiler knows that it won't work, and due to this you are getting compilation error in this case.
There is possibility, that sub class of Interface1 can be a sub class of Interface2 also. So, it doesn't give the compilation error.
It not generic problem. JVM nothing "known" about compatibilities between Interface1 and Interface2. So you get ClassCastException.
Related
My problem is I do have a class that is created, compiled and initialized at runtime. I did this as writing the file as TestClass which is File f,
then compile with:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null,null,null,f.getPath());
After that I load my class and use my methods etc. according to this example;
http://viralpatel.net/blogs/java-dynamic-class-loading-java-reflection-api/
Now my problem is I need to do this:
MyTask<T> m = new MyTask<T>(0,0,0);
T should be my dynamically created class instead of Integer.class etc. However I couldn't find a way for it yet. If you do examine the example at the link I gave above, you will see I can have a instance of my class as in Object form and I can a Class instance for my dynamic class. However, whatever I tried I couldn't find the solution for this.
It keeps saying that Class myClass, can not be used as a type. So how can I use this dynamically created class as a type. Thank you very much.
There is no useful way to express in source code a type that does not exist at compile time. It would not anyway gain you anything more than using Object as a type parameter could do, because Java generics provide compile-time type checking, not run-time type checking.
It might be that your purposes could be served by creating an interface that your dynamic class will implement, and using the interface type as your type parameter.
You can't due to the fact that the generic type information is available only at compile time. When you create a class at runtime, there's no generic information available anywhere any more.
If your class implements an interface, you should use that as the type in code. Something along the lines of
MyInterface foo = myDynamicClass.newInstance();
someGenericMethod(foo);
public <T extends MyInterface> void someGenericMethod(T param) {}
// Or more likely, if there's no other classes that extend MyInterface
public void someGenericMethod(MyInterface param) {}
Of course it may not make any sense to even bother with generic type information, since it's used for static type checking and you're working with a dynamic class.
I want to simplify a project by removing useless classes. By useless classes I mean something like :
public class MainPage extends TileGridFragment<MainModel> {}
The whole logic of this class is implemented by TileGridFragment, and the data is provided by MainModel, which instance is accessed thanks to a singleton class.
I want to defer the instanciation of such class to a later time, so I simply pass MainPage.class to my methods.
As MainPage is equivalent to TileGridFragment<MainModel>, I would like to remove this class and instead use something like TileGridFragment<MainModel>.class instead.
But this doesn't work and I'm out of idead.
I've also tried Class.forName, but its throws a ClassNotFoundException.
Any idea ?
If the implementation of MainPage is actually {}, just pass TileGridFragment.class. The actual type parameters are irrelevant on runtime because they are removed by erasure.
Also, because of erasure, you can cast the new TileGridFragment (with a raw type, as the result of TitleGridFragment.class.newInstance()) to TitleGridFragment<MainModel>, and ther will be no collateral damages (other than a little warning from the compiler, that can be supressed).
You can't really, you might get some joy from reflection but I'm not sure exactly what you're trying to do.
Try here:
Get generic type of class at runtime
Why does this compile? (tried under both Oracle java 5 & java 6 (yes, I know, I'm slow to adapt)
public abstract class BaseClass
{
public abstract void methodA(String abc);
public abstract String methodB(String abc);
}
public final class ConcreteClass
extends BaseClass
{
}
Just pop those two classes into separate files, call the javac on them and poof, they compile. Since abstract methods are intended to be implemented by implementors, this doesn't make sense. Playing with this a bit further, I only receive a compile error when a chunk of code attempts to call the unimplemented method.
So again, my question here is, does anyone know WHY the compiler allows this (or why we would want it to do this)?
Additional comment:
When I did initial testing, I originally didn't have the ConcreteClass marked as final, and it occurred to me that another class could extend the class and thus, the complier might not complain and assume that you would have some other class later on down the road take care of it, but marking the class as final should make it pretty clear that this is not the case.
As #Jigar has mentioned in the comment, you must be importing wrong version of BaseClass. When I
tried to compile your code, I get following error:
/Users/ShirishP/Desktop/ConcreteClass.java:1: ConcreteClass is not abstract and does not override abstract method methodB(java.lang.String) in BaseClass
public final class ConcreteClass extends BaseClass
^
1 error
It may not be intentional. The code that statically complains about abstract classes may be run when method calls are compiled, not when a class is declared (since calling the method is the potentially-bad part, not not declaring it). It's definitely something they could add, but it wouldn't catch anything useful so they may have figured it wasn't worth it.
(This is somewhat a followup to my previous question)
I've got a Foo<?> object, foo. Foo<T> is an interface.
How to get the type value hidden behind the <?>?
Note that this is not trivial, as foo can be for example an object of class Bar<String>, where Bar<T> implements Foo<T>, or some anonyomus class implementing interface FloatFoo, where FloatFoo extends Foo<Float>. I need a solution that works in all cases.
Thanks in advance :)
This is not possible using reflection because Java Generics has the problem of Type Erasure. At runtime the types that have been defined for the generic class Foo have been removed, so using reflection on that class will not yield its generic type. This type information is used only in compilation for type safety.
C# does not have this issue and it is possible to access the templatized type of a Class.
This is a overview of the differences.
Well, for short, you can't.
However, what you can do is get the value of <?> when using FloatFoo.
Indeed, from what I remember, generics are not kept in class information.
however, when you create a subtype (be it class or interface) of a generics type, the generics information has to be memorized as it may define some of the subtype's methods signature.
As an example, if your Foo interfaceis declared as it :
public interface Foo<T> {
public T doIt();
}
Having a
public interface FloatFoo extends Foo<Float>
implies this interface has a
public Float doIt();
method declared.
For that, the compiler has to have the type information. And this information will be reflected in the reflection API by the fact that FloatFoo's super class will have some Type parameters associated to it. Or it least it is what I remember from the few cases I encountered such cases (or elaborated them, as it may sometimes be mandatory)
But you'll have far more complete informations at Angelika's generics FAQ.
The final-final (and perhaps the best possible) solution: I refactored my code, so it doesn't need this. I moved all code which needed the type parameter into Foo, so I could provide appropriate implementation within the class. It turned out to be much less code.
I ended up with creating a getType() method in the interface:
Class<T> getType();
Maybe it's not the most elegant solution, but definitely the simplest one.
There are two classes
foo.bar.FileUploader and barbar.foofoo.FileUploader
Both are identical and extend Uploader
Somewhere in the code the foo.bar.FileUploader is used and are given as a parameter to my function as an Uploader type.
Now I need to cast it back to FileUploader but the barbar.foofoo.FileUploader. And this gives an error:
ERROR - unhandled error
java.lang.ClassCastException:
foo.bar.FileUploader cannot be cast
to barbar.foofoo.FileUploader
And I can't figure out what's going wrong, I suppose it's because the package is different. In that case: Is there a way to still use the class and get the cast done?
Technically they're not the same class.
You're getting a ClassCastException because the JVM doesn't see them as the same type at all. Perhaps you should have both classes implement the same interface and cast to that? Or alternatively, just have one class in the first place and get rid of the cast?
For Java, the classes are not identical. Consider this
package zoo;
public interface Animal {}
package zoo.london;
public class Lion implements Animal{}
package zoo.newyork;
public class Lion implements Animal{}
Even if the implementation of both Lion classes is identical and they both implement a common interface, you can not cast vice versa like
zoo.london.Lion lion = (zoo.london.Lion) new zoo.newyork.Lion(); // ClassCastException
The two classes foo.bar.FileUploader and barbar.foofoo.FileUploader are NOYT the same as they are defined in different places with different names. Thus java thinks they have no relationship to each other,
If you want then to be identical then you have to make then the same class ie import across the packages. It might be easiest to start refactoring to make one of them extend the other.
Others already said it: The classes are not the same, just because they look like it.
Do the classes implement/extend the same interface/abstract class? cast to the interface or abstract class they are both extended of and use that. What you are trying to do is simply not supported by the JVM. The JVM doesn't care if the classes are identical. If they are really 100 percent identical, it's clearly a messed up design, delete one of the classes.
The Java Language Specification describes exactly what you are allowed to cast and what not.
Get rid of duplicated code. Even if it would work now, because both classes are identical, what would happen if someone edited class A and forgot about class B?
edit: you say they are identical, so I guess they're copies. That would be bad. But since they both extend Uploader, you can cast to Uploader instead of FileUploader.
Thanks for the help people.
I just solved the problem by importing the the barbar.foofoo.FileUploader. Now it runs fine!