Java对象初始化
自動初始化(默認值)
一個類的所有基本數(shù)據(jù)成員都會得到初始化,運行下面的例子可以查看這些默認值:
class Default{boolean t;char c;byte b;short s;int i;long l;float f;double d;public void show() {System.out.println("基本類型 初始化值\n"+"boolean<----->" + t +"\n" +"char<----->" + c +"\n" +"byte<----->" + b + "\n" +"short<----->" + s + "\n" +"int<----->" + i + "\n" +"long<----->" + l + "\n" +"float<----->" + f + "\n" +"double<----->" + d + "\n");} } public class InitValue {public static void main(String[] args) {Default d = new Default();d.show();} }【運行結果】:
基本類型 初始化值 boolean<----->false char<-----> byte<----->0 short<----->0 int<----->0 long<----->0 float<----->0.0 double<----->0.0其中,char類型的默認值為空(null)。
對于非基本數(shù)據(jù)類型而言,對象的句柄也會被初始化:
class Person {private String name;// setter } class Default {Person p;public void show() {System.out.println("Person<----->" + p);} } public class InitValue {public static void main(String[] args) {Default d = new Default();d.show();} }【運行結果】:
Person<----->null可見,句柄初始化值為null。這就是說,如果沒有為p指定初始化值就調用類似于p.setName的方法,就會出現(xiàn)異常。
規(guī)定初始化
如果需要自己為變量賦一個初始值,可以在定義變量的同時賦值。
class Default{boolean t = true;char c = 'A';byte b = 47;short s = 0xff;int i = 24;long l = 999;float f = 1.2f;double d = 1.732;public void show() {System.out.println("boolean<----->" + t +"\n" +"char<----->" + c +"\n" +"byte<----->" + b + "\n" +"short<----->" + s + "\n" +"int<----->" + i + "\n" +"long<----->" + l + "\n" +"float<----->" + f + "\n" +"double<----->" + d + "\n");} } public class InitValue {public static void main(String[] args) {Default d = new Default();d.show();} }甚至可以通過一個方法來進行初始化;
class Person {int i = set();//... }這些方法也可以使用自變量:
class Person {int i;int j = set(i);//... }構建器初始化
構建器進行初始化的優(yōu)點是可以在運行期決定初始化值。例如:
class Person {int age;Person() {age = 89;} }age首先會初始化為0,然后變成89。對于所有基本類型以及對象的句柄,這種情況都是成立的。
初始化順序
在一個類里,初始化的順序是由變量在類內的定義順序決定的。即使變量定義大量遍布于方法定義的中間,那么變量仍然會在調用任何方法(包括構造函數(shù))之前得到初始化。例如:
class Pet {Pet(int age) {System.out.println("Pet(" + age + ")");} }class Person {Pet t1 = new Pet(1);Person() {System.out.println("---Person()---");t3 = new Pet(33);}Pet t2 = new Pet(2);void show() {System.out.println("show----running");}Pet t3 = new Pet(3); }public class OrderOfInitialization {public static void main(String[] args) {Person p = new Person();p.show();} }【運行結果】:
Pet(1) Pet(2) Pet(3) ---Person()--- Pet(33) show----running上例中,雖然t1、t2、t3的定義遍布于類中,但是初始化的先后順序是由t1、t2、t3的定義順序決定的(自己動手調換t1、t2、t3看看結果),且初始化優(yōu)先于構建器執(zhí)行,當調用Person的構建器時,t3重新初始化。
靜態(tài)數(shù)據(jù)的初始化
如果數(shù)據(jù)是靜態(tài)的(static),同樣的過程也會執(zhí)行。若屬于基本類型,而且未對其進行初始化,就會自動獲得自己的標準基本類型初始值;若它是指向一個對象的句柄,除非創(chuàng)建一個對象同它連接起來,否則得到一個空值(null)。如果在定義時初始化,采取的方式與非靜態(tài)值是不同的,這是因為static只有一個存儲區(qū)域。例如:
class Bowl {Bowl(int marker) {System.out.println("Bowl(" + marker + ")");}void f(int marker) {System.out.println("f(" + marker + ")");} }class Table {static Bowl b1 = new Bowl(1);Table() {System.out.println("Table()");b2.f(1);}void f2(int marker) {System.out.println("f2(" + marker + ")");}static Bowl b2 = new Bowl(2); }class Cupboard {Bowl b3 = new Bowl(3);static Bowl b4 = new Bowl(4);Cupboard() {System.out.println("Cupboard()");b4.f(2);}void f3 (int marker) {System.out.println("f3(" + marker + ")");}static Bowl b5 = new Bowl(5); }public class StaticInitialization {public static void main(String[] args) {System.out.println("Creating new Cupboard() in main");new Cupboard();System.out.println("Creating new Cupboard() in main");new Cupboard();t2.f2(1);t3.f3(1);}static Table t2 = new Table();static Cupboard t3 = new Cupboard(); }【運行結果】:
Bowl(1) Bowl(2) Table() f(1) Bowl(4) Bowl(5) Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) f2(1) f3(1)靜態(tài)代碼塊
Java允許將其他static初始化工作劃分到類內一個特殊的代碼塊中,這種代碼塊的形式為static關鍵字,后面跟著一個方法主體,稱為靜態(tài)代碼塊。靜態(tài)代碼塊只有在第一次生成那個類的對象或首次訪問屬于那個類的static成員時執(zhí)行。例如:
class Person {Person(int age) {System.out.println("Person(" + age + ")");}void f(int age) {System.out.println("f(" + age + ")");} }class Persons {static Person p1;static Person p2;static {p1 = new Person(1);p2 = new Person(2);}Persons() {System.out.println("Persons()");} }public class ExplicitStatic {public static void main(String[] args) {System.out.println("Inside main()");Persons.p1.f(18);//1 }static Persons x = new Persons();//2static Persons y = new Persons();//2 }在標記為1的行內訪問static對象p1的時候,或在行1被注釋而行2未被注釋是,用于Persons的static初始化模塊就會運行。若1和2都被注釋掉,則用于Persons的靜態(tài)代碼塊不會執(zhí)行。
靜態(tài)屬性和靜態(tài)代碼塊執(zhí)行的先后順序
class Person {Person(int age) {System.out.println("Person("+age+")");} } class Persons {static Person p = new Person(2); // 1static {p = new Person(3);}static Person p = new Person(2); // 2 } public class CompStaticInit {public static void main(String[] args) {}static Persons x = new Persons(); }根據(jù)注釋1保留2,注釋2保留1的結果分析可知,靜態(tài)屬性和靜態(tài)代碼塊的執(zhí)行順序取決于編碼的順序。誰在前面就先執(zhí)行誰。
非靜態(tài)屬性的初始化
class Animal {Animal(int age) {System.out.println("Animal(" + age + ")");}void f(int age) {System.out.println("f(" + age + ")");} } public class NotStaticInit {Animal a1;Animal a2;{a1 = new Animal(1);a2 = new Animal(2);System.out.println("a1 & a2 initialized");}NotStaticInit() {System.out.println("NotStaticInit");}public static void main(String[] args) {System.out.println("Inside main()");NotStaticInit x = new NotStaticInit();} }類似于靜態(tài)代碼塊,匿名代碼塊與非靜態(tài)屬性的初始化順序取決于編碼順序。
繼承中的對象初始化過程
class Insect {int i = 1;int j;Insect() {prt("i = " + i + ", j = " + j);j = 2;}static int x1 = prt("static Insect.x1 initialized");static int prt(String s) {System.out.println(s);return 3;} }public class Beetle extends Insect {int k = prt("Beeklt.k initialized");Beetle() {prt("k = " + k);prt("j = " + j);}static int x2 = prt("static Bootle.x2 initialized");static int prt(String s) {System.out.println(s);return 4;}public static void main(String[] args) {prt("Beetle constructor");Beetle b = new Beetle();} }【運行結果】:
static Insect.x1 initialized static Bootle.x2 initialized Beetle constructor i = 1, j = 0 Beeklt.k initialized k = 4 j = 2對Beetle運行Java時,發(fā)生的第一件事情是裝載程序到外面找到那個類。在裝載過程中,裝載程序發(fā)現(xiàn)一個基礎類,所以隨之將其載入。無論是否生成基礎類的對象,這一過程都將執(zhí)行。如果基礎類含有另一個基礎類,則另一個基礎類隨即也會載入,以此類推。接下來就在根基礎類中執(zhí)行static初始化,再在下一個衍生類中執(zhí)行,以此類推。這是因為衍生類的初始化可能要依賴于對基礎類成員的初始化。
當類都裝載完畢,就能創(chuàng)建對象。首先,這個對象中的所有基本數(shù)據(jù)類型都會設置成為他們的默認值,對象句柄設為null。然后執(zhí)行基礎類的構建器。這種情況是自動完成的(衍生類的構造函數(shù)中默認調用了super(),也可以通過super指定基類的構建器)。基礎類構建器完成后,衍生類實例變量就會按本來的順序得到初始化,然后執(zhí)行構建器的剩余的主體部分。
總結對象創(chuàng)建的過程:
- 靜態(tài)只在類加載的時候執(zhí)行且只執(zhí)行一次;
- 非靜態(tài)只有在實例化的時候執(zhí)行,每次創(chuàng)建對象都執(zhí)行;
- 靜態(tài)在非靜態(tài)之前執(zhí)行,基類靜態(tài)優(yōu)先于衍生類靜態(tài)執(zhí)行;
- 靜態(tài)屬性和靜態(tài)代碼塊的執(zhí)行屬性取決于它們在類中的位置,誰在前先執(zhí)行誰;
- 非靜態(tài)屬性和構造塊的執(zhí)行順序取決于它們在類中的位置,誰在前執(zhí)行誰。
轉載于:https://www.cnblogs.com/xiaoxiaoyihan/p/4934839.html
總結
- 上一篇: Memcached 缓存个体,对象,泛型
- 下一篇: Unix中的I/O模型和Java NIO