剛纔在網上看到一篇關於java初始化、垃圾回收機制和內存分配機制的文章,感受不錯,就拿來轉發了,之後有空能夠再看看,應該會有新的認識和新的收穫。
文章: java
2.1初始化順序:
- public class Parent
- {
- static Tipout TIP = new Tipout("父類 static 成員 TIP 初始化");
- Tipout tip = new Tipout("父類 成員 tip 初始化");
-
- public Parent()
- {
- System.out.println("父類 構造函數 調用");
- }
- }
-
- class Sub extends Parent
- {
- static Tipout SUB_TIP = new Tipout("子類 static 成員 SUB_TIP 初始化");
- Tipout subTip = new Tipout("子類 成員 subTip 初始化");
-
- public Sub()
- {
- System.out.println("子類 構造函數 調用");
- }
- }
-
- class Tipout
- {
- public Tipout(String s)
- {
- System.out.println(s);
- }
- }
執行結果:
父類 static 成員 TIP 初始化
子類 static 成員 SUB_TIP 初始化
父類 成員 tip 初始化
父類 構造函數 調用
子類 成員 subTip 初始化
子類 構造函數 調用
由此能夠總結出java初始化的順序:
->全部靜態成員初始化(父類->子類)
-->父類初始化(普通成員->構造函數)
--->子類初始化(普通成員-->構造函數)
!static成員初始化順序只和類定義中的順序有關。
調用靜態數據和靜態方法時,這個類中的全部靜態成員都會被初始化(非static成員不會被初始化),前提是他們從未被初始化過。
測試代碼:
- public class Parent
- {
- public static Tipout TIP = new Tipout("父類 static 成員 TIP 初始化");
- static
- {
- System.out.println("父類 static 代碼塊");
- }
- Tipout tip = new Tipout("父類 成員 tip 初始化");
-
- public Parent()
- {
- System.out.println("父類 構造函數 調用");
- }
-
- public static void outMsg(){
- System.out.println("父類 static 函數 調用");
- }
- }
在Main()中調用:Parent.TIP.toString();
結果:
![](http://static.javashuo.com/static/loading.gif)
2.2垃圾回收
java中並不須要清除對象,也不存在C++中的析構函數,java的垃圾回收機制會自動釋放無用的變量。
一個對象,能夠有一個或多個引用變量指向它。當一個對象再也不有任何一個引用變量指向它時,這個對象能夠被垃圾回收機制回收了。
可是,並非對象被拋棄後立即被回收的。JVM進程作空間回收有較大的系統開銷。若是每當某應用進程丟棄一個對象,就當即回收它的空間,
勢必會使整個系統的運轉效率很是低下。
!不能操縱垃圾回收
使對象值爲null,或者調用System.gc()
JVM接受這個消息後,並非當即作垃圾回收,而只是對幾個垃圾回收算法作了加權,使垃圾回收操做容易發生,或提前發生,或回收較多而已。
!垃圾回收器的運行時間是不固定的,清理工做的實際運行時間也是不能預知的。
2.3內存分配機制
2.3.1Java 把內存劃分紅兩種:
1.棧內存,
基本類型的變量和對象的引用變量(存取速度比堆要快,僅次於寄存器)
2.堆內存。
堆內存用來存放由 new 建立的對象和數組。
!類跟數組同樣,都是屬於引用類型,引用類型就是指一堆對內存能夠同時被多個棧內存指向。
java中主要存在4塊內存空間:
棧內存空間:保存全部的對象名稱(更準確地說是保存了引用的堆內存空間的地址)
堆內存空間:保存每一個對象的具體屬性內容。
全局數據區:保存static類型的屬性。
全局代碼區:保存全部的方法定義。
2.3.2 String緩衝池
緩衝池是java爲了節省內存空間,會在內存中建立一個專門爲String設計的緩衝池,用來保存已經存在的字符串,
若是2個字符串是同樣的,則使用池中的字符串,再也不建立新的對象
用下邊的代碼測試:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
結果爲true,說明str1和str2指向同一個對象
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new則在堆中建立了2個對象
2.4應該注意的問題:
1.使用如下方式建立字符串
String str = "hello";
上面這種方式會建立一個"hello"字符串,並且JVM的字符緩存池還會緩存這個字符串。
String str = new String("hello");
此時程序除建立字符串外,str所引用的String對象底層還包含一個char[]數組,這個char[]數組依次存放了h,e,l,l,o
2.儘可能減小對變量的重複計算
- for(int i=0;i<list.size();i++)
應該改成
- for(int i=0,len=list.size();i<len;i++)
而且在循環中應該避免使用複雜的表達式,在循環中,循環條件會被反覆計算,若是不使用複雜表達式,而使循環條件值不變的話,程序將會運行的更快。
3.避免在循環體中聲明建立對象
- for (int i = 0; i < 10000; i++) {
- Object obj = new Object();
- }
雖然性能上差異不大,但這樣的代碼會浪費棧內存空間,上邊提到過引用變量會存放在棧內存,這樣會在內存中產生大量的對象引用。
應該寫成下邊的: 算法
- Object obj;
- for (int i = 0; i < 10000; i++) {
- obj = new Object();
- }