Re: [J2SE] class loader
不知道原 po 的意思是否是問 reflection?
reflection 應該是 runtime load class, new instance, 再 call method.
如果原 Po 的意思是要 runtime "換掉" code 的話,reflection 是達不到的。
下面是個不成功的例子:
// A.java
public interface A {
public void s();
}
// Main.java
import java.io.*;
import java.net.*;
public class Main {
static void writefile(String name, String content) throws Exception {
FileWriter fo = new FileWriter(name+".java");
fo.write(content);
fo.close();
Runtime.getRuntime().exec("javac -cp . "+name+".java").waitFor();
Runtime.getRuntime().exec("jar cf "+name+".jar "+name+".class").waitFor();
new File(name+".java").delete();
new File(name+".class").delete();
}
public static void main(String[] args) throws Exception {
writefile("B",
"public class B implements A{public void s(){System.out.println(\"bfr\");}}");
A cls = (A)Class.forName("B").newInstance();
cls.s();
writefile("B",
"public class B implements A{public void s(){System.out.println(\"aft\");}}");
cls = (A)Class.forName("B").newInstance();
cls.s();
}
}
// compile
javac A.java Main.java
// run
java -cp .;B.jar Main
// resule
bfr
bfr
此例中,雖然執行過程中換掉 B.jar 的內容,但因為程式在第一次從 B.jar 載入 B
後,就會 cache 在記憶體中而不會再去重新載入程式了,後來再去修改 B.jar 的內容
是沒用的。
要如何強制 class 重新載入程式呢? 在這裡可以發現官方解答
http://java.sun.com/docs/books/jls/unloading-rationale.html
A class or interface may be unloaded if and only if its class loader is
unreachable. Classes loaded by the bootstrap loader may not be unloaded.
這個 unreachable 其實蠻玄的,不過簡單的說,就是用另一個 class loader
來要求載入 class 就會有重新載入程式的效果了。
請把上例的 main 改成如下
public static void main(String[] args) throws Exception {
writefile("B",
"public class B implements A{public void s(){System.out.println(\"bfr\");}}");
URL url = new URL("file:B.jar");
ClassLoader clsldr = new URLClassLoader(new URL[]{url},
Main.class.getClassLoader());
A cls = (A)clsldr.loadClass("B").newInstance();
cls.s();
writefile("B",
"public class B implements A{public void s(){System.out.println(\"aft\");}}");
clsldr = new URLClassLoader(new URL[]{url}, Main.class.getClassLoader());
cls = (A)clsldr.loadClass("B").newInstance();
cls.s();
}
// compile
javac A.java Main.java
// run, 注意 classpath 不同
java -cp . Main
// resule
bfr
aft
(雖然還是有點複雜,但已是我能想出最簡單的範例了)
這種用法非常有用,例如 tomcat 可以不用重新啟動就更新程式等:
http://wctang-old.blogspot.com/2004/10/
dynamic-load-and-unload-class-in-tomcat.html
(唔,好久前的事了)
可以用這個技巧來做 on-line code update.
※ 引述《jlovet (Want 2 see u no more)》之銘言:
: 你要自己去 load那個class
: 那樣寫,JVM在initialize的時候就會幫你load了
: 也不會自動重新load
: //Main.java
: import java.lang.reflect.*;
: public class Main {
: /**
: * @param args the command line arguments
: */
: public static void main(String[] args) {
: // TODO code application logic here
: String s="NewClass";
: try{
: Class A=Class.forName(s);
: System.out.println("List of methods in class "+ s);
: Method [] m=A.getMethods();
: for(int i=0;i<m.length;i++){
: System.out.println(m[i].getName());
: //印出NewClass裡面所有的method,要執行的話請去查invoke...
: }
: Object o=A.newInstance();
: //這裡就會產生一個NewClass的instance,就會印出他creator裡面的東西
: }catch(Exception e){e.printStackTrace();}
: }
: }
: //NewClass.java
: public class NewClass {
: public NewClass(){
: System.out.println("Hello World in NewClass");
: }
: public String methodA(){
: return "Hello World";
: }
: }
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.127.126.90
推
05/24 00:49, , 1F
05/24 00:49, 1F
討論串 (同標題文章)
以下文章回應了本文:
完整討論串 (本文為第 2 之 7 篇):