有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java不能将类“X”强制转换为类“Y”,即使X扩展了Y?

出于某种原因,在第三个类Z中,试图将一个类X强制转换为另一个类Y会抛出一个ClassCastException。在我看来,这似乎是错误的,因为类X扩展了另一个类Y。类X不能被强制转换为Y,即使X扩展了它,有什么具体原因吗

参考以下代码:

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(此代码是ClassCastException源代码。)

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) {}
    }
}

如果已知loader.loadClass(description.getMain()).newInstance();会创建X的新实例,那么为什么对Y进行强制转换会导致ClassCastException


共 (1) 个答案

  1. # 1 楼答案

    为了进一步说明,这里有一个例子:

    创建一个自定义的ClassLoader,例如下面(从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;
        }
    }
    

    下面是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();
        }
    }
    

    以下是输出:

    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)