java heap space 解决方法_Java静态方法/变量,非静态方法/变量的区别,今天一并帮你解决
靜態(tài)/非靜態(tài) 方法/變量的寫法
大家應(yīng)該都明白靜態(tài)方法/字段比普通方法/字段的寫法要多一個static關(guān)鍵字,簡單寫下他們的寫法吧,了解的可以直接略過
class Test{ // 靜態(tài)變量 public static int id = 1; // 普通變量 public int usualId = 2; // 靜態(tài)常量 public static final int finalNextId = 3; // 靜態(tài)方法 public static void A(){ // 靜態(tài)方法只能訪問靜態(tài)字段,不能訪問非靜態(tài)字段 System.out.println("this is static function A!"); } // 普通方法 public void B(){ // 普通方法可以訪問靜態(tài)字段和非靜態(tài)字段 System.out.println("this is usual function B!"); }}靜態(tài)變量
靜態(tài)變量(帶有static關(guān)鍵字的字段)是屬于類的,所有該類的對象共用該字段;非靜態(tài)變量(普通字段)是屬于類的對象的,每一個該類的對象都有自己的非靜態(tài)字段,他們互不影響。
class Test{ // 靜態(tài)變量 public static int id = 1; // 普通變量 public int usualId = 2;}class TestA{ // 對于靜態(tài)字段,不實例化類(即創(chuàng)建對象)就可使用 Test.id; // 對于普通字段,Test.usualId 就會報錯 // 對于普通字段,需要先實例化類 Test test = new Test(); test.usualId; // 不會報錯}靜態(tài)方法
靜態(tài)方法與普通方法的區(qū)別,與靜態(tài)字段與普通字段的區(qū)別類似靜態(tài)方法是不在對象上執(zhí)行的方法,在調(diào)用靜態(tài)方法時,不需要實例化該類而調(diào)用普通方法必須實例化該類。
class Test{ // 靜態(tài)方法 public static void A(){ // 靜態(tài)方法只能訪問靜態(tài)字段,不能訪問非靜態(tài)字段 System.out.println("this is static function A!"); } // 普通方法 public void B(){ // 普通方法可以訪問靜態(tài)字段和非靜態(tài)字段 System.out.println("this is usual function B!"); }}class TestA{ // 對于靜態(tài)方法,不實例化類(即創(chuàng)建對象)就可調(diào)用 Test.A(); // 對于普通字段,Test.B()就會報錯 // 對于普通方法,需要先實例化類 Test test = new Test(); test.B(); // 不會報錯}可以了解下Java中類的生命周期,就能知道為什么訪問靜態(tài)方法/字段不需要實例化類而訪問非靜態(tài)的方法/字段需要實例化類靜態(tài)字段/方法在類的連接階段就存在了,幾乎可以理解為類存在,靜態(tài)字段/方法就存在;非靜態(tài)字段/方法在類初始化后(new 類名)才會存在,也就是對象存在后,非靜態(tài)字段/方法才會存在。
類的生命周期
此部分幾乎搬運了“三級小野怪”的文章,參考鏈接:https://blog.csdn.net/zhengzhb/article/details/7517213
當(dāng)我們編寫一個Java源文件后,經(jīng)過編譯會生成一個后綴名為class的文件,這種文件叫做字節(jié)碼文件,只有這種字節(jié)碼文件才能夠在Java虛擬機中運行,Java類的聲明周期就是指一個class文件從加載到卸載的全過程。
一個Java類的完整的生命周期會經(jīng)歷加載,連接,初始化,使用,卸載五個階段,當(dāng)然也有在加載或者連接之后沒有被初始化就直接被使用的情況。
jvm中的幾個重要的內(nèi)存區(qū)域
方法區(qū):專門用來存放已經(jīng)加載的類信息,常量,靜態(tài)變量以及方法代碼的內(nèi)存區(qū)域常量池:是方法區(qū)的一部分,主要用來存放常量和類中的符號引用等信息;堆區(qū):存放類的對象實例棧區(qū):也叫Java虛擬機棧,由一個個的棧幀組成的后進先出的棧式結(jié)構(gòu),存放方法運行時產(chǎn)生的局部變量,方法出口等信息。當(dāng)調(diào)用一個方法時,虛擬機棧就會創(chuàng)建一個棧幀存放這些數(shù)據(jù),當(dāng)方法調(diào)用完成時,棧幀消失,如果方法調(diào)用了其他方法,則繼續(xù)在棧頂創(chuàng)建新的棧幀。
加載
在加載階段,Java虛擬機會找到需要加載的類,并把類信息放到j(luò)vm的方法區(qū)中,然后堆中實例化。是類的生命周期中的第一個階段,加載階段之后是連接階段,但是有時連接階段并不會等加載階段完成之后才開始,而是交叉進行,可能一個類只加載了一部分之后,連接階段就已經(jīng)開始了。但是兩個階段總的開始時間和完成時間總是固定的:加載階段總在連接階段之前開始,連接階段總是在加載階段完成之后完成。
連接
連接階段主要任務(wù)是做一些加載后的驗證工作以及一些初始化前的準(zhǔn)備工作
驗證:當(dāng)一個類被加載會后,驗證類是否合法,比如這個類的變量與方法是不是有重復(fù),數(shù)據(jù)類型是否有效等,目的是保證加載的類能夠被jvm所運行。準(zhǔn)備:為類的靜態(tài)變量分配內(nèi)存并設(shè)為jvm默認的初始值,非靜態(tài)變量則不分配內(nèi)存。需要注意的是,這時候靜態(tài)變量的初值是jvm默認的初始值而不是我們在程序中設(shè)定的初值。jvm默認的初值是這樣的:1.基本類型(int、long、short、char、byte、boolean、float、double)的默認值為0。2.引用類型的默認值為null。3.常量的默認值為我們程序中設(shè)定的值,比如我們在程序中定義final static int a = 100,則準(zhǔn)備階段中a的初值就是100。解析
初始化
如果一個類被直接引用就會觸發(fā)類的初始化,直接引用的情況有:
通過new關(guān)鍵字實例化對象,讀取或設(shè)置類的靜態(tài)變量,調(diào)用類的靜態(tài)方法通過反射執(zhí)行以上三種行為初始化子類的時候,會觸發(fā)父類的初始化作為程序入口直接運行時(也就是直接調(diào)用main方法)除了以上四種情況,其他使用類的方法叫做被動引用,被動引用不會觸發(fā)類的初始化主動引用代碼示例
class InitClass{ static { System.out.println("初始化InitClass") } public static String a = null; public static void method(){}}class SubInitClass extends InitClass{}public class Test1{ public static void main(){ // 主動引用引起類的初始化:new 對象、讀取或者是類的靜態(tài)變量,調(diào)用類的靜態(tài)方法 new InitClass(); InitClass.a = ""; String a = InitClass.a; InitClass.method(); // 主動引用引起類的初始化,通過反射實例化對象,讀取或設(shè)置類的靜態(tài)變量,調(diào)用類的靜態(tài)方法 Class cls = InitClass.class; cls.newInstance(); Field f = cls.getDeclaredField("a"); f.get(null); f.set(null,"s"); Method md = cls.getDeclaredMethod("method"); md.invoke(null, null); // 主動引用引起類的初始化,實例化子類 new SubInitClass(); }}初始化過程:按照順序自上而下運行類中的變量賦值語句和靜態(tài)語句,如果有父類,則首先按照順序運行父類中的變量賦值語句和靜態(tài)語句。在初始化階段,只會初始化與類相關(guān)的靜態(tài)賦值語句和靜態(tài)語句,也就是有static關(guān)鍵字修飾的信息,而沒有static修飾的賦值語句和執(zhí)行語句在實例化對象時才會運行
使用類的使用包括主動引用和被動引用,主動引用上面說過了,下面主要說下被動引用
引用父類的靜態(tài)字段,只會引起父類的初始化,而不會引起子類的初始化;定義類數(shù)組,不會引起類的初始化;引用類的常量,不會引起類的初始化。被動引用代碼示例
class InitClass{ static{ System.out.println("初始化InitClass"); } public static String a = null; public final static String b = "b"; public static void method(){}}class SubInitClass extends InitClass{ static { System.out.println("初始化SubInitClass"); }}public class Test4 { public static void main(String[] args) throws Exception{ // String a = SubInitClass.a;// 引用父類的靜態(tài)字段,只會引起父類初始化,而不會引起子類的初始化 // String b = InitClass.b;// 使用類的常量不會引起類的初始化 SubInitClass[] sc = new SubInitClass[10];// 定義類數(shù)組不會引起類的初始化 }}卸載
如果滿足下面的情況,類就會被卸載:
該類所有的實例都已經(jīng)被回收,也就是java堆中不存在該類的任何實例。加載該類的ClassLoader已經(jīng)被回收。該類對應(yīng)的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
原文鏈接:https://blog.51cto.com/14801695/2493438
總結(jié)
以上是生活随笔為你收集整理的java heap space 解决方法_Java静态方法/变量,非静态方法/变量的区别,今天一并帮你解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 耳机不分主从是什么意思_强悍的配置,百元
- 下一篇: python购物车程序-Python编写