For some reason, attempting to cast a class, X
, to a another class, Y
, in a third class Z
throws a ClassCastException
. This seems wrong to me, seeing as the class X
extends the other class Y
. Is there any specific reason why class X
could not be cast to Y
even though X
extends it?
See the following code for reference:
Y
:
public abstract class Y {
/**
* Called when the extension is enabled.
*/
public void onEnable() {
}
}
X
:
public class X extends Y {
@Override
public void onEnable() {
// Extension specific code.
}
}
Z
: (This code is the code where the ClassCastException
originates.)
public class Z {
private boolean loadExtension(ExtensionDescription description) {
try {
URLClassLoader loader = new ExtensionClassLoader(new URL[]{description.getFile().toURI().toURL()});
Y y = (Y) loader.loadClass(description.getMain()).newInstance();
} catch (Throwable t) {}
}
}
If loader.loadClass(description.getMain()).newInstance();
is known to create a new instance of X
, then why would casting to Y
cause a ClassCastException
?
Just to illustrate further, here is an example:
Create a Custom ClassLoader
, e.g. below (copied from here)
package com.dd;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class CustomClassLoader extends ClassLoader {
/**
* The HashMap where the classes will be cached
*/
private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
@Override
public String toString() {
return CustomClassLoader.class.getName();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (classes.containsKey(name)) {
return classes.get(name);
}
byte[] classData;
try {
classData = loadClassData(name);
} catch (IOException e) {
throw new ClassNotFoundException("Class [" + name
+ "] could not be found", e);
}
Class<?> c = defineClass(name, classData, 0, classData.length);
resolveClass(c);
classes.put(name, c);
return c;
}
/**
* Load the class file into byte array
*
* @param name
* The name of the class e.g. com.codeslices.test.TestClass}
* @return The class file as byte array
* @throws IOException
*/
private byte[] loadClassData(String name) throws IOException {
BufferedInputStream in = new BufferedInputStream(
ClassLoader.getSystemResourceAsStream(name.replace(".", "/")
+ ".class"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i;
while ((i = in.read()) != -1) {
out.write(i);
}
in.close();
byte[] classData = out.toByteArray();
out.close();
return classData;
}
}
And here's class Z
package com.dd;
import java.lang.reflect.InvocationTargetException;
public class Z {
public static void main(String[] args) throws ClassNotFoundException,
InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException,
InvocationTargetException {
CustomClassLoader loader = new CustomClassLoader();
Class<?> c1 = loader.findClass("com.dd.X");
System.out.println("Classloader:: "+ X.class.getClassLoader());
System.out.println("Classloader:: "+ loader.findClass("com.dd.X").getClassLoader());
X x = (X)c1.newInstance();
}
}
And here's the output:
Classloader:: sun.misc.Launcher$AppClassLoader@781fb069
Classloader:: com.dd.CustomClassLoader
Exception in thread "main" java.lang.ClassCastException: com.dd.X cannot be cast to com.dd.X
at com.dd.Z.main(Z.java:18)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With