类热更的主要问题在于,尽管你可以加载一个新版本的class,但它却会获取到一个完全不同的唯一标识(译者:这里的意思就是,两个classloader是不一致的,即使加载同一个class文件)。并且,旧的对象依然引用的是class 的旧版本。因此,当调用该对象的方法时,其依然会执行老版本的方法。
我们假设,我们加载了 MyObject 的一个新版本的class,旧版本的类,名字为 MyObject_1,新的为 MyObject_2。MyObject_1 中的 method() 方法会返回 “1”,MyObject_2 中会返回 “2”。 现在,假设 mo2 是一个 MyObject_2 类型的对象,那么以下是成立的:
mo.getClass() != mo2.getClass()
mo.getClass().getDeclaredMethod("method").invoke(mo) != mo2.getClass().getDeclaredMethod("method").invoke(mo2)
(译者: 这两句原文里没解释。第一句就是说,两个的class 对象不一致,第二行是说, mo.method ()会返回 “1”,而 mo2. method ()会返回“2”,当然不相等)
而接下来这句, mo.getClass().getDeclaredMethod("method").invoke(mo2) 会抛出 ClassCastException,因为 mo 和 mo2 的 class 是不一样的。
这就意味着,热更的解决方案,只能是创建一个 mo2,(mo2 是 mo 的拷贝),然后将程序内部所有引用了mo的地方都换成 mo2。 要理解这有多困难,想想上次你改电话号码的时候。改你的电话号码很简单,难的是要让你的朋友们知道你的新号码。改号码这个事就和我们这里说的问题一样困难(甚至是不可能的,除非你能控制对象的创建),而且,所有的对象中的引用,必须同一时刻更新。
例子展示
ps:原标题是 Down and Dirty?这什么意思。。。
我们将在一个新的类加载器中,去加载一个新版本的class。这里, IExample 是一个接口, Example 是它的一个实现。
public interface IExample { String message(); int plusPlus(); }