view plaincopy to clipboardprint? package classloader; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ButtonTest { public static void main(String[] args) { ButtonFrame frame = new ButtonFrame(); frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } /** A frame with a button panel */ class ButtonFrame extends JFrame { public ButtonFrame() { setTitle("ButtonTest"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add panel to frame ButtonPanel panel = new ButtonPanel(); add(panel); } public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; } /** A panel with three buttons. */ class ButtonPanel extends JPanel { public ButtonPanel() { // create buttons JButton yellowButton = new JButton("Yellow"); JButton blueButton = new JButton("Blue"); JButton redButton = new JButton("Red"); // add buttons to panel add(yellowButton); add(blueButton); add(redButton); // create button actions ColorAction yellowAction = new ColorAction(Color.YELLOW); ColorAction blueAction = new ColorAction(Color.BLUE); ColorAction redAction = new ColorAction(Color.RED); // associate actions with buttons yellowButton.addActionListener(yellowAction); blueButton.addActionListener(blueAction); redButton.addActionListener(redAction); } /** An action listener that sets the panel's background color. */ private class ColorAction implements ActionListener { public ColorAction(Color c) { backgroundColor = c; } public void actionPerformed(ActionEvent event) { setBackground(backgroundColor); } private Color backgroundColor; } } package classloader; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ButtonTest { public static void main(String[] args) { ButtonFrame frame = new ButtonFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } /** A frame with a button panel */ class ButtonFrame extends JFrame { public ButtonFrame() { setTitle("ButtonTest"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add panel to frame ButtonPanel panel = new ButtonPanel(); add(panel); } public static final int DEFAULT_WIDTH = 300; public static final int DEFAULT_HEIGHT = 200; } /** A panel with three buttons. */ class ButtonPanel extends JPanel { public ButtonPanel() { // create buttons JButton yellowButton = new JButton("Yellow"); JButton blueButton = new JButton("Blue"); JButton redButton = new JButton("Red"); // add buttons to panel add(yellowButton); add(blueButton); add(redButton); // create button actions ColorAction yellowAction = new ColorAction(Color.YELLOW); ColorAction blueAction = new ColorAction(Color.BLUE); ColorAction redAction = new ColorAction(Color.RED); // associate actions with buttons yellowButton.addActionListener(yellowAction); blueButton.addActionListener(blueAction); redButton.addActionListener(redAction); } /** An action listener that sets the panel's background color. */ private class ColorAction implements ActionListener { public ColorAction(Color c) { backgroundColor = c; } public void actionPerformed(ActionEvent event) { setBackground(backgroundColor); } private Color backgroundColor; } }
注意:虛擬機只加載執行一個程序所需要的類文件.舉個例子,比如執行MyProgram.class,虛擬機運行的步驟如下: 1,虛擬機有一個加載類文件的機制,比如,從硬盤讀取文件或者就網絡獲得;虛擬機用這個機制加載MyProgram的類文件 2,如果MyProgram有一個實例變量或者是超類,那么實例變量和超類的類文件也被加載. (加載一個類所依賴的所有類的過程叫做resolving the class-->自己理解吧) 3,然后虛擬機執行MyProgram的main方法(因為是靜態方法,所以不需要new MyProgram的實例) 4,如果main 方法或者main方法調用的方法需要其他的類的話,這些類也被加載.
類加載機制不是僅僅用一個類加載器,任何一個java程序至少有以下三個類加載器(為了不影響大家的理解,這里我就不翻譯這三個類加載器的名稱了) The bootstrap class loader:加載系統類(有代表性的,jdk的rt.jar里的類),他是虛擬機的必要組成部分,并且一般是用C實現的. 也有類加載器對象(就是指具體的一個類加載器)不關聯bootstrap class loader,比如String.class.getClassLoader()返回null.
The extension class loader:加載jre/lib/ext目錄下的class,你可以把你的jar文件放到這個目錄,extension class loader 將會加載到jar里面的類,即使你不設置classpath.(一些人建議使用這個機制以讓你不受classpath的煩擾,不過注意以下的警告)
The system class loader (有時也叫應用程序加載器):加載應用程序類. 他主要加載classpath目錄和jar/zip文件里的class,通過設置CLASSPATH環境變量或者是運行java的時候用[-classpath]選項指定classpath
在SUN的java實現里,the extension and system class loaders都是用java實現的,他們都是URLClassLoader類的實例.
警告:如果你把jar文件放到jre/lib/ext目錄下,并且你的jar文件中的類需要加載一個不是system or extension的類的話, 你將遇到麻煩.擴展類加載器不使用類路徑.如果你想把類放到jre/lib/ext下進行管理的話,請牢記這一點. ==>怎么理解這一點:也就是說如果你把自己的x.jar放到jre/lib/ext下的話,如果你自己的x.jar里的class要用到不在 x.jar里也不在jre/lib/ext的類的話,會導致類加載不了.不難想象吧,因為你x.jar里的類是由extension class loader 加載的,他不會加載classpath路徑下的類.
警告:把jar文件放到jre/lib/ext目錄下,還有第二個缺陷:有時侯,程序員忘記了他很久以前放在這個目錄下的類文件. 當class loader似乎忽略了類路徑(其實沒有,因為類加載總是先讓父的類加載器加載類,只有父的類加載器加載不了的話 才由自己來加載,"extension class loader是system class loader的父,因此..."), 而加載了放在擴展目錄下的遺忘已久的類的時候,他們就會迷惑不解.
class loader有父子關系,bootstrap class loader以外的每一個class loader都有一個父的類加載器. 類加載器會給父的加載器一個機會加載任何給定的類,如果父加載器加載失敗的話自身才去加載. 舉個例子,當系統class loader被要求加載一個系統類的時候(比如,java.util.ArrayList), 那么,首先需要extension class loader加載,而extension class loader又先讓bootstrap class loader, 最終由bootstrap class loader查找并且加載了rt.jar,其他任何類加載器不需要再搜索.
這種情況下.庫類需要搜索應用程序類加載器(代碼如下): Thread t = Thread.currentThread(); ClassLoader loader = t.getContextClassLoader(); Class cl = loader.loadClass(className);
Using Class Loaders as Namespaces 任何一個java程序員都知道包名是用來消除名字沖突的.在標準類庫里有兩個叫Date的類(java.util.Date and java.sql.Date). 簡單的名字(這里指的是你在程序里直接寫Date)只是程序員方便,并且需要包含import語句.在一個運行的程序中, 所有的class都包含他們的包名.
這也許讓你吃驚,然而,在同一個虛擬機里面你可以有兩個類名和包名都相同的類.一個類是通過他的全名和類加載器來標識的. This technique is useful for loading code from multiple sources.比如,瀏覽器為每個web頁面使用單獨的 applet class loader.這允許虛擬機分開來自不同web頁面的類,不管他們是怎么命名的.
Writing Your Own Class Loader The loadClass method of the ClassLoader superclass takes care of the delegation to the parent and calls findClass only if the class hasn't already been loaded and if the parent class loader was unable to load the class. 定義自己的類加載器只需要繼承ClassLoader類并且重寫findClass(String className)方法. ClassLoader父類的loadClass方法負責授權給父的類加載器 并且只有在還沒有加載并且父的類加載器不能加載的時候 才調用findClass方法.