public class Doctor {
public String name; //成員變量
public int age;
//無參構(gòu)造
public Doctor() {
super(); //訪問object類無參構(gòu)造,一個類代碼里沒指定父類虹蒋,默認繼承Object類
}
//帶參構(gòu)造,也可看作是構(gòu)造函數(shù)的重載
public Doctor(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void talk(){
int x = 8; //此處舉例x是局部變量,隨著方法進棧剃氧,不會默認初始化,必須手動賦值
...
}
}
構(gòu)造函數(shù):創(chuàng)建對象時調(diào)用的函數(shù)阻星,給對象初始化。成員變量默認初始化值如 int是0 String 是 null
代碼里提供了兩種構(gòu)造函數(shù)已添,帶參和不帶參妥箕,那么創(chuàng)建Doctor類有兩種方式(實際開發(fā)中可以根據(jù)需要創(chuàng)建構(gòu)造函數(shù)和new對象)
Doctor d1 = new Doctor();
Doctor d2 = new Doctor("Tom",30);
相應(yīng)的對成員變量賦值的話,第二種是創(chuàng)建對象時已經(jīng)賦值了更舞,第一種需要用到set方法畦幢,如 d1.setName("華佗")
此方法是沒有返回值的,方法里面的this就是哪個對象調(diào)用這個方法缆蝉,指的就是這個對象宇葱。相當(dāng)于new Doctor().setName("華佗")
傳參“華佗”賦值給new出來的Doctor d1的成員變量name,值賦給它
比如以后的方法中需要用到name的值刊头,可以通過get方法拿到String s = d1.getName();
返回前面d1的成員變量name的值
ps成員變量與局部區(qū)別:
1黍瞧、成員變量定義在類中,整個類中都可以訪問原杂;局部變量定義在函數(shù)印颤、語句、局部代碼塊中穿肄,只在所屬代碼塊中有效
2年局、成員變量存在于堆內(nèi)存的對象中;局部變量存在于棧內(nèi)存的方法中
3咸产、成員變量隨著對象的創(chuàng)建而存在矢否,對象的消失而消失;局部變量隨著所屬區(qū)域的執(zhí)行而存在脑溢,所屬區(qū)域的結(jié)束而釋放
4僵朗、成員變量有默認的初始化值;局部變量沒有默認初始化值,必須賦值衣迷,否則編譯報錯
創(chuàng)建對象的實例化過程中在內(nèi)存中的分配:
public static void main(String[]args){
Doctor d1=new Doctor(“華佗”,30);
}
1 程序運行時main函數(shù)先進棧畏鼓,對變量Doctor d1在棧中開辟空間,是引用變量
2 JVM讀取指定路徑下的Doctor.class文件壶谒,類加載器將Doctor類信息加載進方法區(qū)(有父類會先加載父類)
在這個類的方法區(qū)云矫,構(gòu)造方法Doctor()有相應(yīng)地址值
3 在堆中給對象開辟內(nèi)存空間,分配地址值汗菜,
在該內(nèi)存空間中對成員變量進行默認初始化让禀,構(gòu)造方法的引用標(biāo)記,指向方法區(qū)的構(gòu)造方法
4 調(diào)用構(gòu)造函數(shù)陨界,對新建的對象成員變量進行賦值“華佗” 30
5 初始化完畢后堆中地址值指向棧中的 d1
如果有直接父類巡揍,在第四步調(diào)用子類構(gòu)造函數(shù)時會先調(diào)用父類構(gòu)造函數(shù)進行初始化,父類初始化完畢后菌瘪,子類再進行顯示初始化
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Cat {
Cat(String s){
System.out.println(s);
}
}
class Father{
Cat c = new Cat("父親的貓");
public Father() {
System.out.println("父類");
}
}
class Son extends Father{
Cat cc = new Cat("兒子的貓");
public Son() {
System.out.println("子類");
}
}
構(gòu)造函數(shù)以外可以是代碼塊腮敌,他們在一個類里面,每次創(chuàng)建這個類的對象俏扩,調(diào)用構(gòu)造函數(shù)時糜工,都會先執(zhí)行代碼塊,無論代碼塊在構(gòu)造函數(shù)的上面還是下面录淡。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Cat {
Cat(){
System.out.println("Cat");
}
}
class Father{
public Father() {
System.out.println("父類");
}
{
Cat c = new Cat();
System.out.println("代碼塊在構(gòu)造函數(shù)下面也會先執(zhí)行");
}
}
class Son extends Father{
Cat cc = new Cat();
public Son() {
System.out.println("子類");
}
}
一個類中如果沒定義過構(gòu)造函數(shù)捌木,那么編譯后系統(tǒng)會給一個默認的空參數(shù)構(gòu)造函數(shù)。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{ //這里不寫無參/帶參構(gòu)造函數(shù)嫉戚,系統(tǒng)默認給無參構(gòu)造函數(shù)
}
class Son extends Father{
public Son() {
//super(); 在這里寫不寫都可以刨裆,不寫也會默認去調(diào)用父類無參構(gòu)造函數(shù)
System.out.println("子類無參訪問父類無參");
}
public Son(String s) {
super("子類帶參訪問父類帶參"); //報錯父類帶參構(gòu)造函數(shù)沒有被定義過
System.out.println("子類帶參不再訪問父類帶參");
}
}
如果一個類定義了有參構(gòu)造函數(shù),沒定義過無參構(gòu)造函數(shù)彬檀,后面new出來的對象想調(diào)用無參構(gòu)造函數(shù)帆啃,如new 類名()會報錯。
public class SuperTest {
public static void main(String[]args) {
Father f = new Father(); //比如創(chuàng)建對象無參窍帝,這里會報錯the constructor father() is undefined
}
}
class Father{
public Father(String s) {
System.out.println("父類帶參構(gòu)造");
}
}
因為有了有參構(gòu)造函數(shù)链瓦,編譯后系統(tǒng)將不會再給默認的空參數(shù)構(gòu)造函數(shù)。所以建議最好每次構(gòu)造函數(shù)給出無參構(gòu)造盯桦,無論有無帶參構(gòu)造函數(shù)慈俯,用到哪種可以調(diào)用哪種。也方便子類繼承無參構(gòu)造拥峦。
繼承中的構(gòu)造函數(shù):
如果子類構(gòu)造器沒有顯式地調(diào)用父類的構(gòu)造器贴膘,則將自動調(diào)用父類的默認無參構(gòu)造器。
如果父類沒有無參構(gòu)造器略号,有帶參構(gòu)造器刑峡,在子類的構(gòu)造器中又沒有顯式地調(diào)用父類的帶參構(gòu)造器洋闽,則java編譯器將報告錯誤。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父類帶參構(gòu)造");
}
}
class Son extends Father{
public Son() {
super(); //這一行編譯期會報錯突梦,父類無參構(gòu)造函數(shù)沒有被定義過
System.out.println("子類無參訪問父類帶參");
}
public Son(String s) {
super("子類帶參訪問父類帶參");
System.out.println("子類帶參不再訪問父類帶參");
}
}
父類只有帶參構(gòu)造诫舅,每個子類(帶參或無參)第一行必須訪問父類帶參。不寫的話默認調(diào)用父類空參宫患,而父類空參沒有創(chuàng)建刊懈,會報錯。
可通過兩種方式訪問娃闲,第一種如下都是super(帶參)
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父類帶參構(gòu)造");
}
}
class Son extends Father{
public Son() {
super("子類無參訪問父類帶參");
System.out.println("子類無參訪問父類帶參");
}
public Son(String s) {
super("子類帶參訪問父類帶參");
System.out.println("子類帶參不再訪問父類帶參");
}
}
第二種:一個子類A構(gòu)造訪問過了super(帶參)另一個子類B通過this(...)調(diào)其他子類A去訪問父類帶參虚汛,this語句只能放在構(gòu)造函數(shù)的第一行,因為初始化動作要先執(zhí)行皇帮。
public class SuperTest {
public static void main(String[]args) {
Son s = new Son();
}
}
class Father{
public Father(String s) {
System.out.println("父類帶參構(gòu)造");
}
}
class Son extends Father{
public Son() {
this("子類無參訪問另一個我?guī)⒆宇悂碓L問父類帶參");
System.out.println("子類無參訪問父類帶參");
}
public Son(String s) {
super("子類帶參訪問父類帶參");
System.out.println("子類帶參不再訪問父類帶參");
}
}