當前位置:首頁 » 編程語言 » java類的載入過程

java類的載入過程

發布時間: 2023-05-22 12:30:48

『壹』 java解釋器如何載入類

類載入次序:1、靜態代碼塊或者靜態方法->2、main方法調用到的方法
對象載入次序:1、靜態代碼塊或者靜態方法->2、非靜態代碼塊或者非靜態方法->3、對象的構造方法。
但是有一段代碼沒有辦法解釋。代碼忘了,過段時間丟上來
個人感覺應該好像不大對勁,我覺得應該是:
類裝載時,1、靜態代碼塊或者靜態方法被調用
然後是程序的運行,main調用到的方法會被執行,如果是新建一個對象,則
2、非靜態代碼塊或者非靜態方法->3、對象的構造方法順序執行。

===============================================

首先我們要分析類載入原理,java中默認有三種類載入器:引導類載入器,擴展類載入器,系統類載入器(也叫應用類載入器)引導類載入器負責載入jdk中的系鉛塵肆統類,這種類載入器都是用c語言實現的,在java程序中沒有辦法獲得這個類載入器,對於java程序是一個概念而已,基本上不用考慮它的存在,像String,Integer這樣的類都是由引導類載入器載入器的.
擴展類載入器負責載入標准擴展類,一般使用java實現,這是一個真正的java類載入器,負責載入jre/lib/ext中的類,和普通的類載入器一樣,其實這個類載入器對我們來說也不是很重要,我們可以通過java程序獲得這個類載入器。
系統類載入器,載入第一個應用類的載入器(其實這個定義並不準確,下面你將會看到),也就是執行java MainClass 時載入MainClass的載入器,這個載入器使用java實現,使用的很廣泛,負責載入classpath中指定的類。

類載入器之間有一定的關系(父子關系),我們可以認為擴展類載入器的父載入器是引導類載入器(當然不這樣認為也是可以的,因為引導類載入器表現在java中就是一個null),不過系統類載入器的父載入器一定是擴展類載入器,類載入器在載入類的時候會先給父載入器一個機會,只有父載入器無法載入時才會自己去載入。

我們無法獲得引導類載入器,因為它是使用c實現的,而且使用引導類載入器載入的類通過getClassLoader方法返回的是null.所以無兄戚法直接操作引導類載入器,但是我們可以根據Class.getClassLoader方法是否為null判斷這個類是不是引導類載入器載入的,可以通過下面的方法獲得引導類載入器載入的類路徑(每個jar包或者文件夾對應了一個URL);
sun.misc.Launcher.getBootstrapClassPath().getURLs()
你可以直接在你的main函數中輸出就可以了
System.out.println(java.util.Arrays.asList(sun.misc.Launcher.getBootstrapClassPath().getURLs()).toString());
得到的結果是:
[file:/槐轎C:/Program%20Files/Java/j2re1.4.2_10/lib/rt.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/lib/i18n.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/lib/sunrsasign.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/lib/jsse.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/lib/jce.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/lib/charsets.jar,
file:/C:/Program%20Files/Java/j2re1.4.2_10/classes]

其實我們是可以指定引導類載入器的類路徑的,java提供了一個-Xbootclasspath參數,不過這個參數不是標准參數。
java -Xbootclasspath: 運行時指定引導類載入器的載入路徑(jar文件或者目錄)
java -Xbootclasspath/p:和上面的相同,不過把這個路徑放到原來的路徑前面
java -Xbootclasspath/a:這個就是在原引導類路徑後面添加類路徑。
上面我們有提過載入第一個應用類未必就是系統載入器。
如果我把這個應用類的路徑放到引導類路徑中,它將會被引導類載入器載入,大致這樣
java -Xbootclasspath/a:myjar.jar MainClass
如果MainClass在myjar.jar中,那麼這個類將會被引導類載入器載入。
如果希望看詳情,使用-verbose參數,為了看的更清楚,使用重定向,大致為(windows下):
java -verbose -Xbootclasspath/a:myjar.jar MainClass -> C:\out.txt
通過這個參數我們可以實現自己的系統類,比如替換掉java.lang.Object的實現,自己可以擴展
一些方法,不過這樣做似乎沒有好處,因為那就不是標准了。

我們最關心的還是系統類載入器,一般都認為系統類載入器是載入應用程序第一個類的載入器,
也就是java MainClass命令中載入MainClass的類載入器,這種說法雖然不是很嚴謹,但基本上還是可以這樣認為的,因為我們很少會改變引導類載入器和擴展類載入器的默認行為。應該說系統類載入器負責載入classpath路徑中的而且沒有被擴展類載入器載入的類(當然也包括引導類載入器載入的)。如果classpath中有這個類,但是這個類也在擴展類載入器的類路徑,那麼系統類載入器將沒有機會載入它。
我們很少改變擴展類載入器的行為,所以一般你自己定義的類都是系統類載入器載入器的。

獲得系統類載入器非常簡單,假設MyClass是你定義的一個類
MyClass.class.getClassLoader()返回的就是系統類載入器,當然這種方法無法保證絕對正確,我們可以使用更簡單而且一定正確的方式:
ClassLoader.getSystemClassLoader()獲得系統類載入器。我們知道ClassLoader是一個抽象類,所以系統類載入器肯定是ClassLoader的一個子類實現。我們來看看它是什麼
ClassLoader.getSystemClassLoader().getClass();
結果是class sun.misc.Lancher$AppClassLoader
可以看出這是sun的一個實現,從名字可以看出是一個內部類,目前我也沒有看到這個源代碼,似乎還不是很清晰:
我們在看看它的父類是什麼:
ClassLoader.getSystemClassLoader().getClass().getSuperclass();
結果是:class java.net.URLClassLoader
這個是j2se的標准類,它的父類是SecureClassLoader,而SecureClassLoader是繼承ClassLoader的。
現在整個關系應該很清楚,我們會看到幾乎所有的ClassLoader實現都是繼承URLClassLoader的。
因為系統類載入器是非常重要的,而且是我們可以直接控制的,所以我們後面還會介紹,不過先來看一下擴展類
載入器以及它們之間的關系。

擴展類載入器似乎是一個不起眼的角色,它負責載入java的標准擴展(jre/lib/ext目錄下的所有jar),它其實就是一個普通的載入器,看得見摸得著的。
首先的問題是怎麼知道擴展類載入器在哪裡?
的確沒有直接途徑獲得擴展類載入器,但是我們知道它是系統類載入器的父載入器,我們已經很容易的獲得系統類載入器了,所以我們可以間接的獲得擴展類載入器:
ClassLoader.getSystemClassLoader().getParent().getClass();
其實是通過系統類載入器間接的獲得了擴展類載入器,看看是什麼東西:
結果是:class sun.misc.Launcher$ExtClassLoader
這個類和系統類載入器一樣是一個內部類,而且定義在同一個類中。
同樣看看它的父類是什麼:
ClassLoader.getSystemClassLoader().getParent().getClass().getSuperclass();
可以看出結果也是class java.net.URLClassLoader
擴展類載入jre/lib/ext目錄下的所有類,包括jar,目錄下的所有類(目錄名不一定要classes).
現在可以回答上面的問題了,你寫一個HelloWorld,放到jre/lib/ext/下的某個目錄
比如 jre/lib/ext/myclass/HelloWorld.class
然後在你classpath也設置一份到這個類的路徑,結果執行java HelloWorld時,這個類是被擴展類載入器載入器的,可以這樣證明
public static void main(String[] args){
System.out.println("loaded by"+HelloWorld.class.getClassLoader().getClass());
System.out.println("Hello World");
}
結果可以得到class sun.misc.Launcher$ExtClassLoader
當然如果你把jre/lib/ext下myclass這個目錄刪除,仍然可以運行,但是這樣結果是
class sun.misc.Lancher$AppClassLoader
如果你不知道這個過程的話,假設在你擴展類路徑下有一份classpath中的拷貝,或者是比較低的版本,當你使用新的版本時會發現沒有起作用,知道這個過程你就不會覺得奇怪了。另外就是兩個不同的類載入器是可以載入一個同名的類的,也就是說雖然擴展類載入器載入了某個類,系統類載入器是可以載入自己的版本的,
但是現有的實現都沒有這樣做,ClassLoader中的方法是會請求父類載入器先載入的,如果你自己定義類載入器完全可以修改這種默認行為,甚至可以讓他沒有父載入器。

這里給出一個方法如何獲得擴展類載入器載入的路徑:
String path=System.getProperty("java.ext.dirs");
File dir=new File(path);
if(!dir.exists()||!dir.isDirectory()){
return Collections.EMPTY_LIST;
}
File[] jars=dir.listFiles();
URL[] urls=new URL[jars.length];
for(int i=0;i<jars.length;i++){
urls[i]=sun.misc.URLClassPath.pathToURLs(jars[i].getAbsolutePath())[0];
}
return Arrays.asList(urls);

對於擴展類載入器我們基本上不會去關心,也很少把你自己的jar放到擴展路徑,大部分情況下我們都感覺不到它的存在,當然如果你一定要放到這個目錄下,一定要知道這個過程,它會優先於classpath中的類。

現在我們應該很清楚知道某個類是哪個載入器載入的,並且知道為什麼是它載入的,如果要在運行時獲得某個類的類載入器,直接使用Class的getClassLoader()方法就可以了。

用戶定義的類一般都是系統類載入器載入的,我們很少直接使用類載入器載入類,我們甚至很少自己載入類。
因為類在使用時會被自動載入,我們用到某個類時該類會被自動載入,比如new A()會導致類A自動被載入,不過這種載入只發生一次。
我們也可以使用系統類載入器手動載入類,ClassLoader提供了這個介面
ClassLoader.getSystemClassLoader().loadClass("classFullName");
這就很明確的指定了使用系統類載入器載入指定的類,但是如果該類能夠被擴展類載入器載入,系統類載入器還是不會有機會的。
我們最常用的還是使用Class.forName載入使用的類,這種方式沒有指定某個特定的ClassLoader,會使用調用類的ClassLoader。
也就是說調用這個方法的類的類載入器將會用於載入這個類。比如在類A中使用Class.forName載入類B,那麼載入類A的類載入器將會用於載入類B,這樣兩個類的類載入器是同一個。

最後討論一下如何獲得某個類載入器載入了哪些類,這個似乎有一定的使用價值,可以看出哪些類被載入了。其實這個也不是很難,因為ClassLoader中有一個classes成員變數就是用來保存類載入器載入的類列表,而且有一個方法
void addClass(Class c) { classes.addElement(c);}
這個方法被JVM調用。
我們只要利用反射獲得classes這個值就可以了,不過classes聲明為private的,我們需要修改它的訪問許可權(沒有安全管理器時很容易做到)
classes = ClassLoader.class.getDeclaredField("classes");
classes.setAccessible(true);
List ret=(List) classes.get(cl); //classes是一個Vector
可惜的是對於引導類載入器沒有辦法獲得載入的類,因為它是c實現的,在java中很難控制

『貳』 java類載入問題。不要告訴我結果,我問的是為什麼會是這樣的結果,載入順序是什麼

載入類、 靜態成員變數初始化、 靜態代碼塊、非靜態成員變數初始化、 構造方法;
首先 載入類的時候先載入類的靜態成員變數. 因為靜態變數依賴類,不依賴對象,先載入
public static int k = 0;
public static T t1 = new T("t1"); 載入到這一行的時候就會new一個對象出來,並執行public int j = print("j"); 因為j是成員變數,依賴對象.
所以在對象初始化的時候才載入. 然後載入非靜態的構造塊 構造方法. t2靜態變數同理.
t1 t2載入的時候,i n 並未初始化.因為靜態變數i , n 在靜態變數t1,t2後,所以i, n 就為0開始.
public static int i = print("i"); 載入到靜態變數i時,執行print方法.
當所有靜態變數載入完成後,載入靜態塊.
類的載入和對象的初始化是不一樣的.

『叄』 java中反射實例類裝載的步驟及簡要闡述

java反射和類裝載

反射機制:

Person p=new Person();
這是什麼?當然是實例化一個對象了.可是這種實例化對象的方法存在一個問題,那就是必須要知道類名才可以實例化它的對象,這樣我們在應用方面就會受到限制.那麼有沒有這樣一種方式,讓我們不知道這個類的類名就可以實例化它的對象呢?Thank Goodness!幸虧我們用的是java, java就提供了這樣的機制.

1).java程序在運行時可以獲得任何一個類的位元組碼信息,包括類的修飾符(public,static等),基類(超類,父類),實現的介面,欄位和方法等信息.
2).java程序在運行時可以根據位元組碼信息來創建該類的實例對象,改變對象的欄位內容和調用對象方法.
這樣的機制就叫反射技術.可以想像光學中的反射,就像我們照鏡子,鏡子中又出現一個自己(比喻可能不太恰當,但是足以表達清楚意思了).反射技術提供了一種通用的動態連接程序組件的方法,不必要把程序所需要的目標類硬編碼到源程序中,從而使得我們可以創建靈活的程序.

反射的實現步驟( 不問不需要答) ,

1、獲取類的常用方式有三種: a) Class.forName("包名.類名"),最常用、推薦;b) 包名.類名.class 最簡捷;c) 對象.getClass 的方式獲得。

2、對象的實例化,上面已經獲取了類,只需要調用類的實例化方法,類.newInstance()便可。

3、獲取屬性和構造等,可以參考 JavaApi 的調用,類. getDeclaredFields,類. getConstructor(..)等。

Java的反射機制是通過反射API來實現的,它允許程序在運行過程中取得任何一個已知名稱的類的內部信息.反射API位於java.lang.reflect包中.主要包括以下幾類:
1).Constructor類:用來描述一個類的構造方法
2).Field類:用來描述一個類的成員變數
3).Method類:用來描述一個類的方法.
4).Modifer類:用來描述類內各元素的修飾符
5).Array:用來對數組進行操作.
Constructor,Field,Method這三個類都是JVM(虛擬機)在程序運行時創建的,用來表示載入類中相應的成員.這三個類都實現了java.lang.reflect.Member介面,Member介面定義了獲取類成員或構造方法等信息的方法.要使用這些反射API,必須先得到要操作的對象或類的Class類的實例.通過調用Class類的newInstance方法(只能調用類的默認構造方法)可以創建類的實例.這樣有局限性,我們可以先沖類的Class實例獲取類需要的構造方法,然後在利用反射來創建類的一個實例.

類載入機制:



類的載入機制可以分為載入-鏈接-初始化三個階段,鏈接又可以分為驗證、准備、解析三個過程。

載入:通過類的載入器查找並載入二進制位元組流的過程,在堆內存中的方法區生成 一個代表這個類的 java.lang.Class 對象,作為這個類的數據請求入口。(這里可以把上面類載入器載入文件的過程描述一下(參考版本一,不作重復))。

驗證:主要是對一些詞法、語法進行規范性校驗,避免對 JVM 本身安全造成危害; 比如對文件格式,位元組碼驗證,無數據驗證等。但驗證階段是非必須的,可以通過參數 設置來進行關閉,以提高載入的時效。

准備:對類變數分配內存,並且對類變數預初始化,初始化成數據類型的原始值, 比如 static int a=11,會被初始化成成 a=0;如果是 static double a =11,則會被初始化成 a=0.0; 而成員變數只會成實例化後的堆中初始化。

解析:把常量池中的符號引用轉換為直接引用的過程。

初始化:對類的靜態變數和靜態塊中的變數進行初始化。(上面的准備階段可以作為 預初始化,初始到變數類型的原值,但如果被 final 修飾會進行真正初始化)

上面載入、鏈接、初始化的各個階段並不是彼此獨立,而是交叉進行,這點很重要 。

***class.forName和 classloader的區別

Class.forName 和 ClassLoader 都是用來裝載類的,對於類的裝載一般為分三個階段載入、鏈接、編譯,它們裝載類的方式是有區別。

首先看一下 Class.forName(..),forName(..)方法有一個重載方法 forName(className,boolean,ClassLoader),它有三個參數,第一個參數是類的包路徑,第二個參數是 boolean

類型,為 true 地表示 Loading 時會進行初始化,第三個就是指定一個載入器;當你調用class.forName(..)時,默認調用的是有三個參數的重載方法,第二個參數默認傳入 true,第三個參數默認使用的是當前類載入時用的載入器。

ClassLoader.loadClass()也有一個重載方法,從源碼中可以看出它默認調的是它的重載 方法 loadClass(name, false),當第二參數為 false 時,說明類載入時不會被鏈接。這也是兩者之間最大區別,前者在載入的時候已經初始化,後者在載入的時候還沒有鏈接。如果你需要在載入時初始化一些東西,就要用 Class.forName 了,比如我們常用的驅動載入, 實際上它的注冊動作就是在載入時的一個靜態塊中完成的。所以它不能被 ClassLoader 載入代替。

『肆』 JVM之class載入過程

java虛擬機把描述類的數據從class文件載入到內存,並對數據進行 校驗/准備/解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這個過程被稱作虛擬機的類載入機制。

稱作虛擬機的類載入機制。

loading -> linking (verification -> preparation -> resolution)-> resolution)->initializing

loading: 把class文件load到內存中,採用雙親委派,主要是為了安全性

verification: 校驗class文件是否符合標准

preparation: 靜態變數分配內存並設初始值的階段(不包括實例變數)

resolution:把符號引用轉換為直接引用

initializing:靜態變數賦初始值

類載入的過程主要分為三個部分:載入、連接、初始化這三個階段。

類的載入指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個這個類的java.lang.Class對象,用來封裝類在方法區類的對象。主要步驟可以分為下面的三件事情:

載入階段完成後,虛擬機外部的 二進制位元組流就按照虛擬機所需的格式存儲在方法區之中,而且在Java堆中也創建一個java.lang.Class類的對象,這樣便可以通過該對象訪問方法區中的這些數據。

類的載入的最終產品是位於堆區中的Class對象。Class對象封裝了類在方法區內的數據結構,並且向Java程序員提供了訪問方法區內的數據結構的介面。載入類的方式有以下幾種:

2.載入器

JVM的類載入是通過ClassLoader及其子類來完成的,類的層次關系和載入順序可以由下圖來描述:

1.BootstrapClassLoader(啟動類載入器)

在連接裡面又可以被分成3個小階段,分別是:驗證,准備,解析

1.驗證(目的):

2.驗證內容:

驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的位元組流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。驗證階段大致會完成4個階段的檢驗動作:

驗證階段是非常重要的,但不是必須的,它對程序運行期沒有影響,如果所引用的類經過反復驗證,那麼可以考慮採用-Xverifynone參數來關閉大部分的類驗證措施,以縮短虛擬機類載入的時間。

3.准備:

在准備階段,為靜態變數的初值為jvm默認的初值,而不是我們在程序中設定的初值。jvm默認為靜態變數的初值是這樣的

4.解析:

這一階段的任務就是把常量池中的符號引用轉換為直接引用 什麼是符號引用,什麼是直接引用。

1.工作內容:

JVM負責主要對類變數(類變數就是static修改的變數)進行初始化這里主要對類變數(類變數就是static修改的變數)進行初始化,初始化主要有兩個方式:

2.初始化時機:

類初始化時機:只有當對類的主動使用的時候才會導致類的初始化,類的主動使用包括以下六種:

3.初始化順序:

如果有父類,則順序是:父類static方法/static變數賦值 –> 子類static方法/static變數賦值

三、結語:

上面介紹的就是類(class)的載入,包含它的載入、鏈接、初始化。
Android進階知識點,我最近整理了許多,裡面講解的非常詳細。取
https://docs.qq.com/doc/DUkNRVFFzTG96VHNiAndroid 技術進階手冊丶面試題綱丶核心筆記資料。

『伍』 關於java 類的載入過程,下面哪些描述是正確的

關於Java 類的載入過程,下面哪些描述是正確的(A C )
A、在Java 中,有四種類型的類載入器:BootStrapClassLoader、ExtClassLoader、AppClassLoader 以及用戶自定義的 ClassLoader。
B、使用 new 關鍵字創建類實例時,其實就顯示地包含了類的載入過程
C、在Java 中,類的實例化流程分為兩個部分:類的載入和類的實例化。類的載入又分
為顯式載入和隱式載入。
D、Class.forName 來載入類時,是通過ExtClassLoader進行載入的。

『陸』 java靜態資源(靜態方法,靜態屬性)是程序一運行就載入到jvm中,還是當被調用的時候才進行載入呢

java靜態資源(靜態方法,靜態屬性)是程序一運行就載入到jvm中的。

1、類中的靜態屬性會被加入到類對象(也可以叫做類的模板,是類的描述) 的構造器中,靜態方法也會被加入到類對象中。

2、當第一次使用類時,JVM會通過類載入器,載入類對象,從而初始化靜態屬性,並裝入類的方法,包括靜態方法和實例方法(方法不會被調用,只是載入,從這個意義上來說,靜態方法和實例方法是類似的)。嫌乎殲

3、當頃孝創建類的實例對象時,JVM會調用類的構造器,從而初始化類的屬性。

(6)java類的載入過程擴展閱讀:

JVM 類載入機制

JVM類載入機制分為五個部分:載入,驗證,准備,解析,初始化,下面我們就分別來看一下這五個過程。

1、載入

載入是類載入過程中的一個階段,這個階段會在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的入口。注意這里不一定非得要從一個Class文件獲取,這里既可以從ZIP包中讀取(比如從jar包和war包中讀取),也可以在運行時計算生成(動態代理),也可以由其它文件生成(比如將JSP文件轉換成對應的Class類)。

2、驗證

這一階段的主要目的是為了確保Class文件的位元組流中包含的信息是否符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。

3、准備

准備階段是正式為類變數分配內存並設置類變數的初始值階段,即在方法區中分配這些變數芹沖所使用的內存空間。

4、解析

解析階段是指虛擬機將常量池中的符號引用替換為直接引用的過程。符號引用就是class文件中的:

CONSTANT_Class_info

CONSTANT_Field_info

CONSTANT_Method_info

等類型的常量。

5、初始化

初始化階段是類載入最後一個階段,前面的類載入階段之後,除了在載入階段可以自定義類載入器以外,其它操作都由JVM主導。到了初始階段,才開始真正執行類中定義的Java程序代碼。初始化階段是執行類構造器<client>方法的過程。

『柒』 java運行的五個步驟

Java程序從源文件創建到程序運行要經過兩大步驟:1、源文件由編譯器編譯成位元組碼(ByteCode)
2、位元組碼由java虛擬機解釋運行。因為java程序既要編譯同時也要經過JVM的解釋運行,所以說Java被稱為半解釋語言( "semi-interpreted" language)。
下面通過以下這個java程序,來說明java程序從編譯到最後運行的整個流程。代碼如下:
//MainApp.java
public class MainApp {
public static void main(String[] args) {
Animal animal = new Animal("Puppy");
animal.printName();
}
}
//Animal.java
public class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void printName() {
System.out.println("Animal ["+name+"]");
}
}
第一步(編譯): 創建完源文件之後,程序會先被編譯為.class文件。Java編譯一個類時,如果這個類所依賴的類還沒有被編譯,編譯器就會先編譯這個被依賴的類,然後引用,否則直接引用,這個有點象make。如果java編譯器在指定目錄下找不到該類所其依賴的類的.class文件或者.java源文件的話,編譯器話報「cant find symbol」的錯誤。

編譯後的位元組碼文件格式主要分為兩部分:常量池和方法位元組碼。常量池記錄的是代碼出現過的所有token(類名,成員變數名等等)以及符號引用(方法引用,成員變數引用等等);方法位元組碼放的是類中各個方法的位元組碼。下面是MainApp.class通過反匯編的結果,我們可以清楚看到.class文件的結構:
第二步(運行):java類運行的過程大概可分為兩個過程:1、類的載入 2、類的執行。需要說明的是:JVM主要在程序第一次主動使用類的時候,才會去載入該類。也就是說,JVM並不是在一開始就把一個程序就所有的類都載入到內存中,而是到不得不用的時候才把它載入進來,而且只載入一次。
下面是程序運行的詳細步驟:
在編譯好java程序得到MainApp.class文件後,在命令行上敲java AppMain。系統就會啟動一個jvm進程,jvm進程從classpath路徑中找到一個名為AppMain.class的二進制文件,將MainApp的類信息載入到運行時數據區的方法區內,這個過程叫做MainApp類的載入。
然後JVM找到AppMain的主函數入口,開始執行main函數。
main函數的第一條命令是Animal animal = new Animal("Puppy");就是讓JVM創建一個Animal對象,但是這時候方法區中沒有Animal類的信息,所以JVM馬上載入Animal類,把Animal類的類型信息放到方法區中。
載入完Animal類之後,Java虛擬機做的第一件事情就是在堆區中為一個新的Animal實例分配內存, 然後調用構造函數初始化Animal實例,這個Animal實例持有著指向方法區的Animal類的類型信息(其中包含有方法表,java動態綁定的底層實現)的引用。
當使用animal.printName()的時候,JVM根據animal引用找到Animal對象,然後根據Animal對象持有的引用定位到方法區中Animal類的類型信息的方法表,獲得printName()函數的位元組碼的地址。
開始運行printName()函數。
特別說明:java類中所有public和protected的實例方法都採用動態綁定機制,所有私有方法、靜態方法、構造器及初始化方法都是採用靜態綁定機制。而使用動態綁定機制的時候會用到方法表,靜態綁定時並不會用到。

『捌』 java 中靜態內部類欄位什麼時候初始化是在外部類載入的時候就初始化嗎

首先分析下名字:靜態內部類
靜態是static。靜態的方法或者參數是隨著類的載入而產生的(感覺應豎世該是JVM啟動時static屬性就載入了。)。這就是為什麼不用實例化類,就可以調用它的原因。
內部類:用內部類是因為內部類與所在外部類有一定的關系,兆亂往往只有該外部類調用此內部類。其他類不會調用。所以沒必要另寫一個類。外部類可以調用內部類。而內部類不能調用外部類的方法。
所以我族纖檔覺得
靜態內部類中的屬性,方法,是在外部類載入的時候初始化的。
希望對您有幫助。如果有問題請自行
谷歌
度娘.

『玖』 請描述一下JVM載入class文件的原理機制

原理:Java中的所有類,都需要由類載入器裝載到JVM中才能運行。類載入器本身也是一個類,而它的工作就是把class文件從硬碟讀取到內存中。

在寫程序的時候,我們幾乎不需要關心類的載入,因為這些都是隱式裝載的,除非我們有特殊的用法,像是反射,就需要顯式的載入所需要的類。

類裝載方式,有兩種 :

1、隱式裝載, 程序在運行過程中當碰到通過new 等方式生成對象時,隱式調用類裝載器載入對應的類到jvm中。

2、顯式裝載, 通過class.forname()等方法,顯式載入需要的類

Java類的載入是動態的,它並不會一次性將所有類全部載入後再運行,而是保證程序運行的基礎類(像是基類)完全載入到jvm中,至於其他類,則在需要的時候才載入。這當然就是為了節省內存開銷。

(9)java類的載入過程擴展閱讀:

Java的類載入器有三個,對應Java的三種類:

Bootstrap Loader :啟動類載入器,是虛擬機自身的一部分。負責將存放在lib目錄中的類庫載入到虛擬機中。其無法被Java程序直接引用。負責載入系統類 (指的是內置類,像是String,對應於C#中的System類和C/C++標准庫中的類)。

ExtClassLoader :負責載入擴展類(就是繼承類和實現類)。

AppClassLoader :負責載入用戶類路徑(ClassPath)上所指定的類庫(程序員自定義的類)。

JVM中類的載入是由類載入器(ClassLoader)和它的子類來實現行察的,Java中的類載入器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。

由於Java的跨沒帶擾平台性,經過編譯的Java源程序並不是一個可執行程序,而是一個或多個類文件。當Java程序需要使用某個類時,JVM會確保這個類已經被載入、連接(驗證、准備和解析)和枯旦初始化。

類的載入是指把類的.class文件中的數據讀入到內存中,通常是創建一個位元組數組讀入.class文件,然後產生與所載入類對應的Class對象。載入完成後,Class對象還不完整,所以此時的類還不可用。

當類被載入後就進入連接階段,這一階段包括

驗證:為了確保Class文件的位元組流中包含的信息符合當前虛擬機的要求,並且不會危害虛擬機自身的安全。

『拾』 北大青鳥java培訓:創建新對象的兩種方式

隨著互聯網編程開發技術的發展,編程開發語言已經由面向程序發展成為了面向對象的編程。
今天,我們就從兩個方面來了解一下,java編程語言中如何創建新對象的。
java在new一個對象的時候,會先查看對象所屬的類有沒有被載入到內存,如果沒有的話,就會先通過類的全限定名來載入。
載入並初始化類完成後,再進行對象的創建工作。
我們先假設是一次使用該類,這樣的話new一個對象就可以分為兩個過程:載入並初始化類和創建對象。
一、類載入過程(一次使用該類)java是使用雙親委派模型來進行類的載入的,所以在描述類載入過程前,我們先看一下它的工作過程:雙親委託模型的工作過程是:如果一個類載入器(ClassLoader)收到了類載入的請求,它先不會自己去嘗試載入這個類,而是把這個請求委託給父類載入器去完成,每一個層次的類載入器都是如此,因此所有的載入請求終都應該傳送到頂層的啟動類載入器中,只有當父類加搏源載器反饋自己無法完成這個載入請求(它的搜索范圍中沒有找到所需要載入的類)時,子載入器才會嘗試自己去載入。
使用雙親委託機制的基襲態好處是:能夠有效確保一個類的全局性,當程序中出現多個限定名相同的類時,類載入器在執行載入時,始終只會載入其中的某一個類。
1、載入由類載入器負責根據一個類的全限定名來讀取此類的二進制位元組流到JVM內部,並存儲在運行時內存區的方法區,然後將其轉換為一個與目標類型對應的java.lang.Class對象實例2、驗證格式驗證:驗證是否符合class文件規范語義驗證:檢查一個被標記為final的類型是否包含子類;檢查一個類中的final方法是否被子類進行重寫;確保父類和子類之間沒有不兼容的一些方法聲明(比如方法簽名相同,但方法的返回值不同)操作驗證:在操作數棧中的數據必須進行正確的操作,對常量池中的各種符號引用執行驗證(通常在解析階段執行,檢查是否可以通過符號引用中描述的全限定名定位到指定類型上,以及類成員信息的訪問修飾符是否允許訪問等)3、准備為類中的所有靜態變數分配內存空間,並為其設置一個初始值(由於還沒有產生對象,實例變數不在此操作范圍內)被final修飾的static變數(常量),會直接賦值;4、解析將常量池中的符號引用轉為直接引用(得到類或者欄位、方法在禪廳內存中的指針或者偏移量,以便直接調用該方法),這個可以在初始化之後再執行。
解析需要靜態綁定的內容。
//所有不會被重寫的方法和域都會被靜態綁定以上2、3、4三個階段又合稱為鏈接階段,鏈接階段要做的是將載入到JVM中的二進制位元組流的類數據信息合並到JVM的運行時狀態中。
5、初始化(先父後子)4.1為靜態變數賦值4.2執行static代碼塊注意:static代碼塊只有jvm能夠調用如果是多線程需要同時初始化一個類,僅僅只能允許其中一個線程對其執行初始化操作,其餘線程必須等待,只有在活動線程執行完對類的初始化操作之後,才會通知正在等待的其他線程。
因為子類存在對父類的依賴,所以類的載入順序是先載入父類後載入子類,初始化也一樣。
不過,父類初始化時,子類靜態變數的值也有有的,是默認值。
終,方法區會存儲當前類類信息,包括類的靜態變數、類初始化代碼(定義靜態變數時的賦值語句和靜態初始化代碼塊)、實例變數定義、實例初始化代碼(定義實例變數時的賦值語句實例代碼塊和構造方法)和實例方法,還有父類的類信息引用。
二、創建對象1、在堆區分配對象需要的內存分配的內存包括本類和父類的所有實例變數,但不包括任何靜態變數2、對所有實例變數賦默認值將方法區內對實例變數的定義拷貝一份到堆區,然後賦默認值3、執行實例初始化代碼初始化順序是先初始化父類再初始化子類,初始化時先執行實例代碼塊然後是構造方法4、如果有類似於Childc=newChild()形式的c引用的話,在棧區定義Child類型引用變數c,然後將堆區對象的地址賦值給它需要注意的是,福建IT培訓http://www.kmbdqn.cn/發現每個子類對象持有父類對象的引用,可在內部通過super關鍵字來調用父類對象,但在外部不可訪問

熱點內容
sql語句等於怎麼寫 發布:2024-05-07 18:05:46 瀏覽:816
我的世界電腦版第三方伺服器大全 發布:2024-05-07 18:00:46 瀏覽:627
主伺服器的ip地址 發布:2024-05-07 17:58:50 瀏覽:546
組伺服器打電腦游戲 發布:2024-05-07 17:46:19 瀏覽:866
java的文件路徑 發布:2024-05-07 16:55:29 瀏覽:293
雲表伺服器安裝導致電腦崩潰 發布:2024-05-07 15:58:35 瀏覽:524
ftp是什麼檢測器 發布:2024-05-07 15:37:59 瀏覽:403
重慶電信伺服器租用教學雲主機 發布:2024-05-07 15:28:05 瀏覽:73
python聲明對象 發布:2024-05-07 15:28:03 瀏覽:128
存儲過程的應用場景 發布:2024-05-07 15:12:16 瀏覽:613