<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
構造方法(也稱為構造器)是一個特殊的成員方法,其名字必須與類名相同,在建立物件時,由編譯器自動呼叫,並且在整個物件的生命週期內只呼叫一次。
構造方法的作用就是給物件中的成員進行初始化,並不負責給物件開闢空間。
public class Date { public int year; public int month; public int day; // 構造方法: // 名字與類名相同,沒有返回值型別,設定為void也不行 // 一般情況下使用public修飾 // 在建立物件時由編譯器自動呼叫,並且在物件的生命週期內只呼叫一次 public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; System.out.println("Date(int,int,int)方法被呼叫了"); } public void printDate() { System.out.println(year + "-" + month + "-" + day); } public static void main(String[] args) { // 此處建立了一個Date型別的物件,並沒有顯式呼叫構造方法 Date d = new Date(2021, 6, 9); // 輸出Date(int,int,int)方法被呼叫了 d.printDate(); // 2021-6-9 } }
1.名字必須與類名相同
2.沒有返回值型別,設定為void也不行
3.建立物件時由編譯器自動呼叫,並且在物件的生命週期內只呼叫一次
4.絕大多數情況下使用public來修飾,特殊場景下會被private修飾
5.構造方法可以過載(使用者根據自己的需求提供不同引數的構造方法); 下面兩個構造方法:名字相同,參數列不同,因此構成了方法過載
public class Date { public int year; public int month; public int day; // 無參構造方法 public Date(){ this.year = 1900; this.month = 1; this.day = 1; } // 帶有三個引數的構造方法 public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public void printDate(){ System.out.println(year + "-" + month + "-" + day); } public static void main(String[] args) { Date d = new Date(); d.printDate(); } }
6.如果使用者沒有顯式定義,編譯器會生成一份預設的構造方法,生成的預設構造方法一定是無參的; 一旦使用者定義,編譯器則不再生成;下面程式碼中,沒有定義任何構造方法,編譯器會預設生成一個不帶引數的構造方法。
public class Date { public int year; public int month; public int day; public void printDate(){ System.out.println(year + "-" + month + "-" + day); } public static void main(String[] args) { Date d = new Date(); d.printDate(); } }
7.構造方法中,可以通過this呼叫其他構造方法來簡化程式碼
【注意事項】
public class Date { public int year; public int month; public int day; // 無參構造方法--內部給各個成員賦值初始值,該部分功能與三個引數的構造方法重複 // 此處可以在無參構造方法中通過this呼叫帶有三個引數的構造方法 // 但是this(2022,8,16);必須是構造方法中第一條語句 public Date(){ //System.out.println(year); 註釋取消掉,編譯會失敗 this(2022, 8, 16); //this.year = 1900; //this.month = 1; //this.day = 1; } // 帶有三個引數的構造方法 public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } }
在繼承基礎上,子類物件構造時,需要先呼叫基礎類別構造方法,然後執行子類的構造方法。
在子類構造方法中,並沒有寫任何關於基礎類別構造的程式碼,但是在構造子類物件時,先執行基礎類別的構造方法,然後執行子類的構造方法,
原因在於:子類物件中成員是有兩部分組成的,基礎類別繼承下來的以及子類新增加的部分 。父類別和子類, 肯定是先有父再有子,所以在構造子類物件時候 ,子類構造方法中先要呼叫基礎類別的構造方法,將從基礎類別繼承下來的成員構造完整 ,然後再完成子類自己的構造,將子類自己新增加的成員初始化完整 。
【注意事項】
1.若父類別顯式定義無參或者預設的構造方法,在子類構造方法第一行預設有隱含的super()呼叫,即呼叫基礎類別構造方法
public class Base { public Base(){ System.out.println("Base()"); } } public class Derived extends Base{ public Derived(){ // super(); // 注意子類構造方法中預設會呼叫基礎類別的無參構造方法:super(), // 使用者沒有寫時,編譯器會自動新增,而且super()必須是子類構造方法中第一條語句, // 並且只能出現一次 System.out.println("Derived()"); } } public class Test { public static void main(String[] args) { Derived d = new Derived(); } }
2.如果父類別構造方法是帶有引數的,此時需要使用者為子類顯式定義構造方法,並在子類構造方法中選擇合適的父類別構造方法呼叫,否則編譯失敗。
public class Animal { public String name; public int age; public Animal(String name, int age) { this.name = name; this.age = age; System.out.println("Animal(String , int )"); } } public class Dog extends Animal{ //傻狗 是狗的屬性 public boolean silly; public Dog(String name,int age,boolean silly) { //1. 先幫助父類別部分初始化 必須放到第一行 super(name,age); this.silly = silly; System.out.println("Dog(String ,int ,boolean )"); } public static void main(String[] args) { Animal animal2 = new Dog("金毛",6,false); } }
3.在子類構造方法中,super(…)呼叫父類別構造時,必須是子類構造方法中第一條語句。
4.super(…)只能在子類構造方法中出現一次,由與this(…)呼叫時也要在第一條語句,所以super(…)不能和this(…)同時出現,也就是是說子類構造方法中不能使用this(…)
一段有坑的程式碼. 我們建立兩個類, B 是父類別, D 是子類. D 中重寫 func 方法. 並且在 B 的構造方法中呼叫 func
class B { public B() { // do nothing func(); } public void func() { System.out.println("B.func()"); } } class D extends B { private int num = 1; @Override public void func() { System.out.println("D.func() " + num); } } public class Main { public static void main(String[] args) { D d = new D(); } }
執行結果:
【結論】:
“用盡量簡單的方式使物件進入可工作狀態”, 儘量不要在構造器中呼叫方法(如果這個方法被子類重寫, 就會觸發動態繫結, 但是此時子類物件還沒構造完成), 可能會出現一些隱藏的但是又極難發現的問題.
在Java方法內部定義一個區域性變數時,使用者必須要將其賦值或者初始化,否則會編譯失敗;
但物件中的欄位(成員變數),使用者不需要將其初始化就可直接存取使用,這裡其原因在於new物件時,jvm會給出欄位的預設初始化。
下面是new物件是時,jvm層面執行的概述:
1.檢測物件對應的類是否載入了,如果沒有載入則載入
2.為物件分配記憶體空間
3.處理並行安全問題
比如:多個執行緒同時申請物件,JVM要保證給物件分配的空間不衝突
4.初始化所分配的空間
即:物件空間被申請好之後,物件中包含的成員已經設定好了初始值
資料型別 | 預設值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0 |
float | 0.0f |
double | 0.0 |
char | /u0000 |
boolean | false |
reference (參照型別) | null |
5.設定物件頭資訊(關於物件記憶體模型後面會介紹)
6.呼叫構造方法,給物件中各個成員賦值
在宣告成員變數時,就直接給出了初始值。
程式碼編譯完成後,編譯器會將所有給成員初始化的這些語句新增到各個構造方法中
public class Date { public int year = 1900; public int month = 1; public int day = 1; public Date(){ } public Date(int year, int month, int day) { } public static void main(String[] args) { Date d1 = new Date(2022,8,16); Date d2 = new Date(); } }
靜態部分(靜態變數、常數,靜態程式碼塊)
非靜態部分(範例變數、常數、範例程式碼塊)
當有物件建立時才會執行,按順序執行
最後執行構造方法,當有物件建立時才會執行
程式碼演示:
class Person { public String name; public int age; public Organ organ = new Organ(); public Person(String name, int age) { this.name = name; this.age = age; System.out.println("構造方法執行"); } { System.out.println("範例程式碼塊執行"); } static { System.out.println("靜態程式碼塊執行"); } } class Organ { //... public Organ() { System.out.println("範例變數::organ"); } } public class TestDemo { public static void main(String[] args) { Person person1 = new Person("xin",21); System.out.println("=============="); Person person2 = new Person("xinxin",20); } }
執行結果:
靜態部分(靜態變數、常數,靜態程式碼塊)
父類別非靜態部分(範例變數、常數、範例程式碼塊)和父類別構造方法
子類非靜態部分(範例變數、常數、範例程式碼塊)和子類構造方法
class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; System.out.println("Person:構造方法執行"); } { System.out.println("Person:範例程式碼塊執行"); } static { System.out.println("Person:靜態程式碼塊執行"); } } class Student extends Person{ public Student(String name,int age) { super(name,age); System.out.println("Student:構造方法執行"); } { System.out.println("Student:範例程式碼塊執行"); } static { System.out.println("Student:靜態程式碼塊執行"); } } public class TestDemo4 { public static void main(String[] args) { Student student1 = new Student("張三",19); System.out.println("==========================="); Student student2 = new Student("gaobo",20); } public static void main1(String[] args) { Person person1 = new Person("bit",10); System.out.println("============================"); Person person2 = new Person("gaobo",20); } }
執行結果:
到此這篇關於詳解Java的構造方法及類的初始化的文章就介紹到這了,更多相關Java初始化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45