还有什么可以在java中抛出ClassCastException?

还有什么可以在java中抛出ClassCastException?,java,caching,classcastexception,Java,Caching,Classcastexception,这是一个面试问题 面试结束了,但这个问题仍在我脑海里 我不能问面试官,因为我没有得到这份工作 场景: 使用键“a”将类别C1的对象放入缓存 后续代码: c1c1fromcache=(C1)cache.get(“a”) 此代码引发ClassCastException 原因是什么? 我说是因为其他人用同一个键放了另一个对象,所以写得太多了。我被告知不,想想其他的可能性 我说可能定义类C1的jar在此节点上不可用(不确定这是否会导致类强制转换或类NotFoundException,但我现在正在寻找

这是一个面试问题

面试结束了,但这个问题仍在我脑海里

我不能问面试官,因为我没有得到这份工作

场景:

  • 使用键“a”将类别C1的对象放入缓存
后续代码:

c1c1fromcache=(C1)cache.get(“a”)

此代码引发ClassCastException

原因是什么?

我说是因为其他人用同一个键放了另一个对象,所以写得太多了。我被告知不,想想其他的可能性

我说可能定义类C1的jar在此节点上不可用(不确定这是否会导致类强制转换或类NotFoundException,但我现在正在寻找线索。然后我说可能是类的版本错误?他们说所有节点中都有相同的类C1 jar)

Edit/Add询问get是否正在抛出ClassCast,但被告知否。之后,我告诉他,我解决此类问题的措施是插入一个测试jsp,该测试jsp将模拟这些操作,并在异常后放置更好的日志记录(堆栈跟踪)。这是问题的第二部分(如果在生产中发生这种情况,您会怎么做)


还有人知道为什么缓存获取会导致强制转换问题吗?

一个原因可能是插入对象的代码部分使用了与检索对象的代码不同的类加载器。
类的实例不能强制转换为由不同类装入器装入的同一个类

对编辑的响应:

如果在生产中发生这种情况,您会怎么做

这通常发生在读取和插入模块都包含包含
C1

由于大多数容器首先尝试父类加载器,然后尝试本地类加载器(父类优先策略),因此问题的常见解决方案是将类加载到离插入和读取模块最近的公共父类中。

如果将包含
C1
类的模块移动到父模块,则会强制两个子模块从父模块获取类,删除任何类加载器差异。

如果同一类由多个不同的类加载器加载,并且这些类的实例在它们之间共享,则会发生
类卡斯特例外

考虑以下示例层次结构

SystemClassloader <--- AppClassloader <--+--- Classloader1
                                         |
                                         +--- Classloader2

包类装入器测试;
导入java.util.concurrent.ConcurrentHashMap;
公共类MyRunnable实现Runnable{
私有ConcurrentHashMap缓存;
私有字符串名称;
公共MyRunnable(字符串名,ConcurrentHashMap缓存){
this.name=名称;
this.cache=cache;
}
@凌驾
公开募捐{
System.out.println(“Run”+name+“:running”);
//在缓存中设置对象
A=新的A(名称);
cache.putIfAbsent(“key”,a);
//从缓存中读取对象,如果已经设置,则可能与上面的不同。
缓存=(A)cache.get(“key”);
System.out.println(“Run”+name+”:cache[\“key\”]=“+cached.toString());
}
}
独立于上面的类运行以下程序。它不能与上述类共享类路径,以确保它们是从JAR文件加载的

package classloadertest;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.ConcurrentHashMap;

public class Main {
    public static void run(String name, ConcurrentHashMap<String, Object> cache) throws Exception {
        // Create a classloader using a.jar as the classpath.
        URLClassLoader classloader = URLClassLoader.newInstance(new URL[] { new File("a.jar").toURI().toURL() });

        // Instantiate MyRunnable from within a.jar and call its run() method.
        Class<?> c = classloader.loadClass("classloadertest.MyRunnable");
        Runnable r = (Runnable)c.getConstructor(String.class, ConcurrentHashMap.class).newInstance(name, cache);
        r.run();
    }

    public static void main(String[] args) throws Exception {
        // Create a shared cache.
        ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<String, Object>();

        run("1", cache);
        run("2", cache);
    }
}
包类装入器测试;
导入java.io.File;
导入java.net.MalformedURLException;
导入java.net.URL;
导入java.net.URLClassLoader;
导入java.util.concurrent.ConcurrentHashMap;
公共班机{
公共静态无效运行(字符串名称,ConcurrentHashMap缓存)引发异常{
//使用.jar作为类路径创建类加载器。
URLClassLoader classloader=URLClassLoader.newInstance(新URL[]{new File(“a.jar”).toURI().toURL()});
//从.jar中实例化MyRunnable并调用其run()方法。
c类=classloader.loadClass(“classloadertest.MyRunnable”);
Runnable r=(Runnable)c.getConstructor(String.class,ConcurrentHashMap.class).newInstance(名称,缓存);
r、 run();
}
公共静态void main(字符串[]args)引发异常{
//创建共享缓存。
ConcurrentHashMap缓存=新建ConcurrentHashMap();
运行(“1”,缓存);
运行(“2”,缓存);
}
}
运行此命令时,将显示以下输出:

Run 1: running
Run 1: cache["key"] = <A value="1">
Run 2: running
Exception in thread "main" java.lang.ClassCastException: classloadertest.A cannot be cast to classloadertest.A
        at classloadertest.MyRunnable.run(MyRunnable.java:23)
        at classloadertest.Main.run(Main.java:16)
        at classloadertest.Main.main(Main.java:24)
Run 1:正在运行

运行1:cache[“key”]=也可以。

可能是因为C1是一个抽象类,get函数也会返回对象(当然是C1的一个子类),该对象在返回之前被强制转换到C1?

最后,有人入侵了字符串
字符串
intern


请看一个如何实现的示例。

一些代码证明了这一点,这很可能会让您获得金牌+1正是这一情景让我在《雄猫》中陷入了困境。Tomcat使用分层类加载器,如果你有跨越分层边界的类依赖,你基本上不能强制转换,除非你将所有类移动到高公共级别哇,我想说的是,在同一个JVM中有两个不同的web应用程序,但我认为最好不要,为什么这会导致类强制转换。学习:就像在代码和数据库中一样,在一个地方有一个函数很好,在其他地方也一样(所有web应用程序的公共库/添加容器主类路径,如果可以的话),或者每个容器有一个应用程序。这绝对是正确的答案。只有一个补充:如果缓存作为远程EJB访问,对象将被序列化和反序列化,因此不会发生类强制转换异常(但是如果您有不兼容的类版本,则可能会出现序列化异常)。因此,OP的一个更深层次的答案实际上是关于JavaEE应用程序的体系结构,特别是不能直接调用不同JavaEE容器中的对象。听起来像是面试
package classloadertest;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.ConcurrentHashMap;

public class Main {
    public static void run(String name, ConcurrentHashMap<String, Object> cache) throws Exception {
        // Create a classloader using a.jar as the classpath.
        URLClassLoader classloader = URLClassLoader.newInstance(new URL[] { new File("a.jar").toURI().toURL() });

        // Instantiate MyRunnable from within a.jar and call its run() method.
        Class<?> c = classloader.loadClass("classloadertest.MyRunnable");
        Runnable r = (Runnable)c.getConstructor(String.class, ConcurrentHashMap.class).newInstance(name, cache);
        r.run();
    }

    public static void main(String[] args) throws Exception {
        // Create a shared cache.
        ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<String, Object>();

        run("1", cache);
        run("2", cache);
    }
}
Run 1: running
Run 1: cache["key"] = <A value="1">
Run 2: running
Exception in thread "main" java.lang.ClassCastException: classloadertest.A cannot be cast to classloadertest.A
        at classloadertest.MyRunnable.run(MyRunnable.java:23)
        at classloadertest.Main.run(Main.java:16)
        at classloadertest.Main.main(Main.java:24)