最近在看一本叫《Component Development for the Java Platform》的书,里面内容非常有兴趣,但是碰到不少疑惑,希望高手加以指点。
下面代码均可直接编译运行。思想如下:
Point类是一个接口,PointImpl实现了Point接口,但是它存在缺陷,即它的move()函数只对x进行了操作而未对y进行操作;假设应用程序PointClient已经运行并已载入了这个有缺陷的类,通过PointServe,我们可以用一个没有缺陷的版本(去掉PointImpl中Move函数的y的注释),在运行期替换掉有缺陷的版本,并重新load进来(ServerPoint的Reload())不影响程序的运行。由于PointImpl不能放在code/hapter2/ection2_5目录下,因为这样reload时会引起PointImpl的装载器和原来的装载器是同一个而导致不会load新版本,于是我在code/hapter2/ection2_5建了一个子目录subdir,将PointImpl.class放到了subdir中,并删掉了code/hapter2/ection2_5中的PointImpl.class,运行时出现了
Exception in thread "main" java.lang.ClassNotFoundException: code.chapter2.section2_5.PointImpl
当我在code/hapter2/ection2_5也保留一份PointImpl.class是就会出现
Exception in thread "main" java.lang.ClassCastException: code.chapter2.section2_5.PointImpl
at code.chapter2.section2_5.PointServer.createPoint(PointServer.java:14)
at code.chapter2.section2_5.PointClient.main(PointClient.java:12)
我弄了很久都不明白,希望高手指点一下(我使用Eclipse3.1编译运行)
给出代码:
代码1:
package code.chapter2.section2_5;public interface Point {
public int getX();
public int getY();
public void move(int dx, int dy);
}
-----------------------------------------------------------------------
代码2:
package code.chapter2.section2_5;public class PointImpl {
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
} public void move(int dx, int dy) {
x += dx;
//y += dy;
// oops! forgot to move y
}
public String toString() {
return "Point at " + x + ", " + y;
}
}
//-------------------------------------------------------------------
代码3:
package code.chapter2.section2_5;import java.net.*;public class PointServer {
static ClassLoader cl; static Class ptClass; public static synchronized Point createPoint(Point template)
throws Exception {
if (ptClass == null)
reloadImpl();
Point newPt = (Point)ptClass.newInstance();
if (template != null) {
newPt.move(template.getX(), template.getY());
}
return newPt;
} public static synchronized void reloadImpl() throws Exception {
URL[] serverURLs = new URL[] { new URL("file:subdir/") };
cl = new URLClassLoader(serverURLs);
ptClass = cl.loadClass("code.chapter2.section2_5.PointImpl");
}
}
-----------------------------------------------------------------------------------
代码4:
package code.chapter2.section2_5;import java.io.*;public class PointClient {
static Point pt; public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
pt = PointServer.createPoint(null);
System.out.println(pt);
while (true) {
System.out.println("MOVE, RELOAD, or EXIT");
String cmdRead = br.readLine();
String cmd = cmdRead.toUpperCase();
if (cmd.equals("EXIT") || cmd.equals("exit")) {
return;
} else if (cmd.equals("RELOAD") || cmd.equals("reload")) {
PointServer.reloadImpl();
pt = PointServer.createPoint(pt);
System.out.println(pt);
} else if (cmd.equals("MOVE") || cmd.equals("move")) {
pt.move(1, 1);
System.out.println(pt);
}
}
}
}
下面代码均可直接编译运行。思想如下:
Point类是一个接口,PointImpl实现了Point接口,但是它存在缺陷,即它的move()函数只对x进行了操作而未对y进行操作;假设应用程序PointClient已经运行并已载入了这个有缺陷的类,通过PointServe,我们可以用一个没有缺陷的版本(去掉PointImpl中Move函数的y的注释),在运行期替换掉有缺陷的版本,并重新load进来(ServerPoint的Reload())不影响程序的运行。由于PointImpl不能放在code/hapter2/ection2_5目录下,因为这样reload时会引起PointImpl的装载器和原来的装载器是同一个而导致不会load新版本,于是我在code/hapter2/ection2_5建了一个子目录subdir,将PointImpl.class放到了subdir中,并删掉了code/hapter2/ection2_5中的PointImpl.class,运行时出现了
Exception in thread "main" java.lang.ClassNotFoundException: code.chapter2.section2_5.PointImpl
当我在code/hapter2/ection2_5也保留一份PointImpl.class是就会出现
Exception in thread "main" java.lang.ClassCastException: code.chapter2.section2_5.PointImpl
at code.chapter2.section2_5.PointServer.createPoint(PointServer.java:14)
at code.chapter2.section2_5.PointClient.main(PointClient.java:12)
我弄了很久都不明白,希望高手指点一下(我使用Eclipse3.1编译运行)
给出代码:
代码1:
package code.chapter2.section2_5;public interface Point {
public int getX();
public int getY();
public void move(int dx, int dy);
}
-----------------------------------------------------------------------
代码2:
package code.chapter2.section2_5;public class PointImpl {
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
} public void move(int dx, int dy) {
x += dx;
//y += dy;
// oops! forgot to move y
}
public String toString() {
return "Point at " + x + ", " + y;
}
}
//-------------------------------------------------------------------
代码3:
package code.chapter2.section2_5;import java.net.*;public class PointServer {
static ClassLoader cl; static Class ptClass; public static synchronized Point createPoint(Point template)
throws Exception {
if (ptClass == null)
reloadImpl();
Point newPt = (Point)ptClass.newInstance();
if (template != null) {
newPt.move(template.getX(), template.getY());
}
return newPt;
} public static synchronized void reloadImpl() throws Exception {
URL[] serverURLs = new URL[] { new URL("file:subdir/") };
cl = new URLClassLoader(serverURLs);
ptClass = cl.loadClass("code.chapter2.section2_5.PointImpl");
}
}
-----------------------------------------------------------------------------------
代码4:
package code.chapter2.section2_5;import java.io.*;public class PointClient {
static Point pt; public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
pt = PointServer.createPoint(null);
System.out.println(pt);
while (true) {
System.out.println("MOVE, RELOAD, or EXIT");
String cmdRead = br.readLine();
String cmd = cmdRead.toUpperCase();
if (cmd.equals("EXIT") || cmd.equals("exit")) {
return;
} else if (cmd.equals("RELOAD") || cmd.equals("reload")) {
PointServer.reloadImpl();
pt = PointServer.createPoint(pt);
System.out.println(pt);
} else if (cmd.equals("MOVE") || cmd.equals("move")) {
pt.move(1, 1);
System.out.println(pt);
}
}
}
}
解决方案 »
- Java中“==”和equals的比较
- 求教一个java初级问题,是Why is "ture"?
- java.io.IOException: 拒绝访问。
- 这个递归算法是什么意思呢
- Java 如何通过 SNMP 获取 window 的信息呢?
- [在线]如何用Java来实现一个random逐步取数的功能。
- 请教 如何得到一个string中包含几个某字符
- 运行 deploytool 时出现: error: can't not connect to server localhost
- 我想问关于scjp的事
- 奇怪,通过 JAVA xmlbean jar 开发JAVA操作XML文件的问题,获取value值的问题
- windows 2003安装jdk和tomcat的问题
- 关于ECLIPSE的插件VE.EMF.GEF.................朋友!请进!(解决问题都另开贴加100分,分有的是)!
注决eclipse的user.dir目录在哪里
假设你的类是生成在 [工程目录]/bin目录的要不要给个工程你运行一下
或者[email protected]
是相对于整个应用程序(也就是code的父目录)还是相对于 code.chapter2.section2_5.PointServer.class(即code/chapter/section2_5)的呢?
收到你的信了,非常感谢你的帮忙,又遇到些新问题。我做了回复,也不知道你收到没有,于是在这里再把我回复的内容说一下。运行完你的工程以后,找不到class的问题解决了,可是没能起到热装载的作用。我将PointServer.java中的reloadImpl()加上打印,修改如下:
public static synchronized void reloadImpl() throws Exception {
URL[] serverURLs = new URL[] { new URL("file:bin/bin/subdir/") };
cl = new URLClassLoader(serverURLs);
System.out.println("cl's loader:"+cl.getClass().getClassLoader());
ptClass = cl.loadClass("code.chapter2.section2_5.PointImpla");
System.out.println("ptClass's loader:"+ptClass.getClassLoader());
}
运行时的结果如下:
user.dir=D:\Java资源\电子书\Component Development for the Java Platform\ttt
cl's loader:null
ptClass's loader:sun.misc.Launcher$AppClassLoader@82ba41
newPt:sun.misc.Launcher$AppClassLoader@82ba41
Point at 0, 0
MOVE, RELOAD, or EXIT
可以看到ptClass的装载器是系统类装载器(AppClassLoader)而不是URLClassloader,我在createPoint()加入了对newPt的打印System.out.println("newPt:"+newPt.getClass().getClassLoader());结果newPt也是由AppClassLoader而不是URLClassloader载入的,根据JVM的载入规则,同一装载器是不会重复载入某个同名class的,所以在subdir下的那个PointImpla.class根本没被载入(或者通过运行结果也能看出来,我把一个修改过的PointImpla放到subdir里,没修改过的还放到原位置不动,运行结果是修改过的没有被载入)。请问为什么ptClass的装载器是系统类装载器(AppClassLoader)而不是URLClassloader呢?(我试过奖cl的类型由ClassLoader改为URLClassLoader,结果同上)。
不好意思,麻烦你了,等待你的回复。