1. 程式人生 > >JVM 類載入器_2

JVM 類載入器_2

名稱空間深度解析

直接先上例子

package com.ssy.jvm.classloader;

import java.lang.reflect.Method;

public class MyTest21 {
    public static void main(String[] args) throws Exception {
        MyFirstClassLoader loader1 = new MyFirstClassLoader("loader1");
        MyFirstClassLoader loader2 = new MyFirstClassLoader
("loader2"); loader1.setPath("/Users/ddcc/Desktop"); loader2.setPath("/Users/ddcc/Desktop"); Class<?> clazz1 = loader1.loadClass("com.ssy.jvm.classloader.MyPerson"); Class<?> clazz2 = loader2.loadClass("com.ssy.jvm.classloader.MyPerson"); System.out.println
(clazz1 == clazz2); Object object1 = clazz1.newInstance(); Object object2 = clazz2.newInstance(); Method method = clazz1.getMethod("setMyPerson", Object.class); method.invoke(object1, object2); } }
package com.ssy.jvm.classloader;

public class MyPerson {
    private
MyPerson myPerson; public void setMyPerson(Object myPerson) { this.myPerson = (MyPerson) myPerson; } }

我們先將classpath中的MyPerson.class檔案保留

結果:

true

解析:

    經過上一節類載入器的講解,我們知道,類載入的過程是通過雙親委託機制來完成的。loader1和loader2都會交由它的父載入器–系統類載入器 去進行載入,而很明顯,系統類載入器可以載入MyPerson類。當loader1交由系統類載入器載入後,loader2再交由系統類載入器載入時,發現這個類已經被載入了,那麼會直接返回這個類的Class物件,所以結果為True。

我們現在將classpath中的MyPerson.class刪除,在Desktop上放這個檔案。

結果

findClass invoked: com.ssy.jvm.classloader.MyPerson
class loader name: loader1
findClass invoked: com.ssy.jvm.classloader.MyPerson
class loader name: loader2
false
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.ssy.jvm.classloader.MyTest21.main(MyTest21.java:22)
Caused by: java.lang.ClassCastException: com.ssy.jvm.classloader.MyPerson cannot be cast to com.ssy.jvm.classloader.MyPerson
	at com.ssy.jvm.classloader.MyPerson.setMyPerson(MyPerson.java:7)
	... 5 more

分析

    這個結果就非常好玩了。首先打印出false,其次,丟擲了異常。我們分別來解釋。     loader1和loader2是沒有直接或間接父子關係的兩個載入器。所以它們在各自的名稱空間內。

同一個名稱空間內的類是相互可見的 子載入器的名稱空間包含父載入器的名稱空間,因此子載入器載入的類能看到父載入器所載入的類 父載入器所載入的類看不到子載入器所載入的類。 如果兩個載入器之間沒有直接或者間接的父子關係,那麼相互不可見

    所以loader1載入的Class物件和loader2載入的Class物件是相互不可見的。由此,它們new出來的物件也是相互不可見的。當用反射呼叫方法將loader2載入的Class物件所對應的類的例項傳入時,轉換為loader1載入的Class物件所對應的類中,就會丟擲類轉換異常

    單獨看java.lang.ClassCastException: com.ssy.jvm.classloader.MyPerson cannot be cast to com.ssy.jvm.classloader.MyPerson這個異常的時候,真的是不知所云,哈哈哈。。