Java總結——類與對象

基本數據類型與對象

????????Java是面向對象的語言,所以光有基本數據類型是不夠的萍肆,對象才是主角≌陀欤基本數據類型的存在塘揣,一方面是向計算機本身物理結構的妥協,另一方面是為了構造對象宿崭。
????????編程語言所面對的問題和事物是復雜的亲铡,多維度的,需要用一個組合體來囊括方方面面,各個角度奖蔓。比如描述一個人赞草,他有姓名,年齡吆鹤,性別厨疙,住址,身高疑务,體重等等沾凄,這么多信息,不是哪個基本數據類型可以表示的知允∪鲶埃可以理解為,每個基本數據類型都是一維的廊镜,只有把他們組合起來牙肝,才能表示多維的事物。
????????基本數據類型嗤朴,說穿了其實就兩類:數字和文字配椭。除了char類型表示文字,其他的類型可以視為數字雹姊。在人類的自然語言中股缸,其實描述事物不外乎也就兩個手段:文字和數字——文字描述“質”,數字描述“量”吱雏。
????????對象則可以包含二者,它是現實中的事物在計算機中的映射敦姻。但是對象可以映射的不僅僅是具體事物,還可以是抽象的事物歧杏,比如一個查詢镰惦。只要這個事物可以被描述,或者可度量犬绒。對象在計算機中代表了世界的一切旺入,當編程語言可以在計算機中描述一切時,就可以模擬它們的運行凯力。

類與對象

????????類與對象的關系茵瘾,就是基本數據類型與其值之間的關系,比如

int a = 5咐鹤;

????????變量a的類型是int拗秘,值是5。類型代表一類事物祈惶,int代表著整數雕旨,5只是整數中的一個而已扮匠,還有很多其他的整數值。類奸腺,是新創(chuàng)造出來的類型餐禁,也代表一類事物。一個該類型的對象突照,也只是類型中所有值中的一個而已帮非。同一類型的對象之間,他們的屬性個數和名稱必然一樣讹蘑,但是每個屬性的值可能不一樣末盔。屬性的個數及名稱決定了“質”,而屬性的具體值決定了“量”座慰,也可以稱為狀態(tài)陨舱。
????????從衍生的角度看,創(chuàng)建了類版仔,然后由這個模板批量制造對象游盲;從歸納的角度,存在一批相似的對象蛮粮,然后將其抽象成了類益缎,代表這批對象公共的、共同的特征然想。

語法

????????類主要由兩部分構成:屬性和方法莺奔。屬性代表著狀態(tài),即這個類是什么变泄;而方法代表行為令哟,即這個類能做什么。還是先舉例:

class Apple {
    float weight;
    void grow() {
        weight += 1.0;
    }
}

????????Apple類只有一個屬性weight妨蛹,表示重量屏富;只有一個方法grow,表示生長蛙卤。創(chuàng)建Apple的對象后狠半,可以通過點號運算符訪問屬性和方法:訪問屬性可以獲取該屬性的值;訪問方法可以改變或者獲取相應的屬性值——大部分方法都是在操縱某些屬性表窘,當然也不全是典予。

構造方法與創(chuàng)建對象

????????有了類之后要如何創(chuàng)建對象呢甜滨?對于基本類型可以這樣:

int a = 4乐严;

????????但是對于復合類型,并沒有像4這樣的字面值可供使用衣摩,于是Java提供了new + 構造方法的方式來創(chuàng)建對象昂验,如下:

Apple a = new Apple();

????????很像對普通方法的調用捂敌,除了必須用new關鍵字來配合。那么構造方法哪兒來的呢既琴?類中定義的:

class Apple {
    int weight;
    Apple() {
        weight = 10;
        System.out.println(“weight:” + weight);
    }
}

????????除了不能有返回值以外占婉,其他地方似乎沒有區(qū)別,不過構造方法的名稱必須和類名保持一致甫恩。構造方法主要是用來初始化屬性值的逆济,這樣可以讓對象在創(chuàng)建時就擁有指定的狀態(tài),當然也可以在其中做一些其他的工作磺箕,跟普通方法一樣奖慌。有了構造方法之后,創(chuàng)建對象時松靡,必須按照構造方法指定的方式來創(chuàng)建對象简僧。上面的構造方法沒帶參數,所以給weight屬性賦了一個固定值雕欺;但實際上構造方法可以帶參數岛马,用調用構造方法時傳入的值來初始化各個屬性,這樣在創(chuàng)建對象時就可以指定任意的狀態(tài)屠列。

class Apple {
    int weight;
    Apple(int w) {
        weight = w;
    }
}

Apple a = new Apple(2);

????????那么如果不在類中定義構造方法啦逆,是不是就無法創(chuàng)建對象了呢?理論上是這樣的脸哀,如果最后編譯成的類class文件中不含有構造方法蹦浦,那么這個類就無法創(chuàng)建對象了。但是撞蜂,從源代碼到class文件有個編譯的過程盲镶,所以編譯器是可以在其中做一些手腳,比如檢查是否存在構造方法蝌诡,沒有的話就自動幫你寫一個默認的構造方法溉贿。所謂默認的構造方法,其實是就是空參且沒有方法體的構造方法浦旱。但是如果存在構造方法宇色,就不管了。比如上例颁湖,類中有且只有一個Apple(int w)方法宣蠕,那么下面的代碼將會報錯:

Apple a = new Apple();

????????因為此時的class文件中沒有了空參的構造方法。所以甥捺,如果要使用空參的構造方法來創(chuàng)建對象抢蚀,要么不在類中寫任何構造方法,讓編譯器替你做镰禾;要么手寫一個空參的構造方法——無論類中有沒有其他重載的帶參數的構造方法皿曲。

方法重載

????????Java提供了方法重載機制唱逢,即:一個類中可以存在同名的方法,只要它們的方法簽名不同屋休。所謂方法簽名包括了方法名稱和方法參數列表坞古,不包含返回值;參數列表包括參數的個數劫樟、類型和排序痪枫,不包含參數名稱。如下:

void grow(int叠艳,float听怕,int);
int grow(float虑绵, int尿瞭, int);
float grow(int翅睛,float)声搁;
void grow(int, long)捕发;

????????以上四個方法是可以共存于一個類中的疏旨,它們僅僅是名字一樣。當然第二種重載的方式是不推薦的扎酷,它們僅僅是參數排序不同檐涝,個數和類型都是一樣的,這樣及其容易引起混淆法挨。所以谁榜,重載中的“重”,僅僅指的是名字凡纳。老實說窃植,不太理解為啥要搞這么個重載機制,多個方法共用一個名字能帶來什么好處荐糜?我絞盡腦汁想到了兩個理由:

  1. 起名字確實是個費力的活兒巷怜,如果經常玩游戲或者生孩子你會懂的。暴氏。延塑。。
  2. 如果需要重載的方法是構造方法答渔。

????????單說第二條关带,為什么需要多個不同的構造方法?理想狀態(tài)下研儒,只需要一個全參數的構造方法即可豫缨,足夠初始化類的所有屬性。但是有些情況下我們想忽略其中的一些屬性端朵,即只傳部分參數好芭,其他的保持默認值即可。這樣以來冲呢,每次調用全參數的構造方法就會麻煩又啰嗦舍败。由于創(chuàng)建對象時只能按照構造方法規(guī)定的方式來,所以我們需要另外一個構造方法敬拓;而構造方法又必須和類名保持一致邻薯,于是我們需要多個同名且參數列表不同構造方法。這時只能引入重載機制乘凸,將方法簽名(方法名加上參數列表)作為每個方法的唯一標識(被jvm識別)厕诡,也就是方法可以重名了,重名的方法不會引起混淆营勤,如下:

class Apple {
    int weight;
    Apple(int w) {
        weight = w;
    }
    
    Apple() { }
}

????????看起來灵嫌,重載機制是為了使多個構造方法并存而發(fā)明的。雖然對普通方法也是有效葛作,但更像是無心插柳寿羞。

this關鍵字

????????我將this理解為一個占位符,代表將來的赂蠢、尚未創(chuàng)建出來的對象本身绪穆。因為在寫代碼時,寫的是類本身虱岂,是個模版玖院,而非具體的對象。在創(chuàng)建對象時第岖,操作系統(tǒng)會為每個對象開辟存儲空間司恳,但僅僅是用來存放具體的屬性值,存儲空間的大小按照類中定義的屬性分配绍傲,空間不能共享扔傅,因為每個對象的狀態(tài)不同;但是方法卻可以共享烫饼,因為方法的邏輯是通用的猎塞,沒必要為每個對象單獨存儲一份方法代碼,于是方法的代碼存儲在公共的空間中——也就是類本身的空間杠纵。于是荠耽,對象需要存儲空間,也需要存儲空間比藻,但它們存儲的內容不一樣:類的空間主要存儲方法铝量,而對象的空間主要存儲屬性倘屹。
以grow方法為例:

void grow() {
    weight += 1.0;
}

????????grow方法要對weight屬性操作,注意這是類中的代碼慢叨,是公共的纽匙,不是某個對象特有的。那么如何保證賦值給了正確的對象拍谐?畢竟Apple類會有很多個對象烛缔。所以就需要一個對象的指針,來保證方法是對正確的對象操作的轩拨,這個指針践瓷,就是this。上面提到方法是通過對象來調用的:

apple.grow();

????????這看起來像是apple對象單獨存儲了一份grow方法的代碼亡蓉,grow方法屬于這個對象晕翠。但其實方法是公共的,對象的存儲空間中并沒有方法代碼砍濒,通過對象來調用方法似乎有點說不通崖面。實際上,這只是為了向grow方法傳遞apple對象的地址(或者叫指針)而已梯影,編譯器會將這行代碼編譯成類似下面的代碼(注意這里只是為了理解本質巫员,編譯器可能不是這么做的,但道理相通):

grow(apple);

????????等等甲棍,類中的grow方法是空參的简识,這里強行插入一個Apple類型的參數合適嗎?當然不合適感猛!但是grow方法只是表面上空參七扰,實際上它長這樣:

void grow(Apple this);

????????這樣就說得通了。類中的所有方法(構造方法應該不在此列)都有一個隱式的參數陪白,而且排在第一位颈走,就是this。它可能實現為一個普通的屬性變量咱士,類型就是當前類立由,創(chuàng)建對象時會自動將這個變量賦值為當前對象的地址。構造方法應該是沒有這個隱式參數的序厉,畢竟調用構造方法時對象還不沒創(chuàng)建出來锐膜,沒辦法給構造方法傳參——語法上構造方法也不能在對象上調用。this指針是隱式的弛房,編譯器和jvm會自動處理道盏,我們直接拿來用就可以了。在類中聲明方法時也沒有必要把它顯式寫進參數列表(不合法);在方法中調用另一個方法時荷逞,也沒有必要在被調用方法名前面加上”this.”(雖然合法)媒咳,只是知道調用方法時有這么個機制就行。說完隱式种远,那么顯式的this怎么用涩澡?用來干嘛?

  1. 類中引用屬性院促,防止重名
class Apple {
    int weight;
    Apple (int weight) {
        this.weight = weight;
    }
}

????????當方法尤其是構造方法的參數中有與屬性同名的參數,且在方法體中操作了同名的屬性(這種情況是怎么發(fā)生的呢斧抱?)常拓,則需要在屬性前面飲用this關鍵字,防止混淆辉浦。雖然寫代碼時對象還沒創(chuàng)建出來弄抬,但是當jvm執(zhí)行到這段代碼時,this已經被賦值——相當與提前占位了宪郊。this在構造方法中使用也是合法的掂恕,這意味著執(zhí)行構造方法的方法體時,對象已經創(chuàng)建出來了弛槐,構造方法的方法體只是在初始化對象的屬性懊亡。

  1. 構造方法之間相互調用
class Apple {
    int weight;
    Apple(int weight) {
        this.weight = weight;
    }
    
    Apple() {
        this(4.5);
    }
}

????????普通的重載方法之間可以直接調用,但是構造方法卻不可以乎串,像這樣是會報錯的:

Apple() {
    Apple(4.5);
}

????????這時只能用this( )來代替對構造方法的調用店枣。還需要注意的是,this()的調用只能發(fā)生在構造方法內叹誉,普通方法內部不能調用鸯两;而且必須是方法體的第一條語句。如下的語句會報錯:

Apple() {
    int a = 9;
    this(4.5);
}

????????上面三個規(guī)則是為什么呢长豁?

初始化

????????對象的初始化指的是其屬性被賦值的過程钧唐。這個過程有三個節(jié)點:第一個是對象剛被分配空間時,這個節(jié)點可以形象的理解為“清零”匠襟,即將這塊內存區(qū)域以前使用的痕跡抹去钝侠,換成屬性對應類型的默認值,比如int類型賦值0酸舍,引用類型賦值null机错。這個賦值過程是jvm自動執(zhí)行的,無需人工干預父腕。這個特點是Java語言的一大賣點弱匪,C++就不會做這種“多余”的動作。這么做的好處是更安全,對象的初始化狀態(tài)不是一堆亂起八糟的“前任”值萧诫,而是經過清理的斥难。
????????需要注意的是,這個清理動作只發(fā)生在對象創(chuàng)建的時刻帘饶,或者說只對屬性變量有效哑诊;對于局部變量,也就是方法體內臨時定義的變量及刻,jvm不會有這個動作镀裤,所以必須手動初始化——給變量賦值,否則無法通過編譯缴饭。(這又是為啥呢暑劝?一個猜測是對象的初始化發(fā)生在堆上,jvm可以干預屬性變量的賦值颗搂;而局部變量在棧上担猛,jvm干預不了)
第二個節(jié)點就是在聲明變量的同時賦值,如下:

class Apple {
    int weight = 3;
}

????????這樣的屬性值是寫死的丢氢,或者說硬編碼的傅联,缺乏靈活性:每個new出來的對象,其weight屬性都是3疚察。當然某些情況下需要這樣做蒸走。
????????第三個節(jié)點就是構造方法了,在構造方法內給屬性賦值貌嫡,可以是固定值载碌,類似于第二個節(jié)點;也可以是參數值衅枫,更靈活嫁艇。
????????至此,初始化過程就結束了弦撩,構造方法是最后的機會步咪。再往后對屬性值的改變就不屬于初始化了,比如各種setter方法益楼。有啥子區(qū)別嗎猾漫?我反正沒看出來。Spring給對象的屬性賦值時感凤,基本靠的是setter方法悯周,當然構造方法也是可以的。

static關鍵字

????????上面提到類的存儲空間中主要保存了方法代碼陪竿,而屬性保存在對象的存儲空間中禽翼,這兩個存儲空間是分開的。而實際上類的存儲空間中也可以保存屬性值,只要將屬性用static關鍵字修飾闰挡。
????????static代表靜態(tài)的锐墙,Java引入這個機制是為向所謂的“全局變量”妥協。被static修飾的變量长酗,可以被每個該類的對象訪問溪北,可以看成是共享的;由于存儲在類空間夺脾,所以可以直接通過類名訪問之拨,如下:

class Apple {
    static String name = “apple”;
}

????????然后就可以這樣訪問了:

Apple.name;

????????從實現的角度,static變量跟對象無關咧叭,它存放在類空間蚀乔;但是從語義的角度,static變量用來表達所有對象都共有的屬性佳簸,比如上例中的name屬性乙墙,每個Apple對象或許weight屬性不同颖变,但是name都是一致的生均。一旦name發(fā)生了變化,所有對象的這個屬性也會跟著變化腥刹;從這個角度理解马胧,static變量的確是全局的。
????????static還可以用來修飾方法衔峰,表示這個方法跟具體對象無關佩脊,不必再通過對象名來訪問了(當然,static方法不會有隱式的this指針)垫卤。static方法表示那些可以直接可以直接以類名來訪問的方法威彰,畢竟創(chuàng)建對象是需要花費時間和空間的。static方法當然也可以通過對象來訪問穴肘,只是需要先創(chuàng)建一個對象歇盼,不如直接使用類名省事。
????????static還有一個重要用途是static塊评抚,當然它還是跟對象無關(static跟對象絕緣)豹缀,而是表示在加載類的時候需要做的事,如下:

class Apple {
    static {
        System.out.println(“init”);
    }
}

????????類加載是發(fā)生在創(chuàng)建對象之前的慨代。與此對應邢笙,也可以創(chuàng)建沒有static修飾的塊,表示在創(chuàng)建對象時要做的事侍匙,如下:

class Apple {
    {
        System.out.println(“init”);
    }
}

????????可以手動驗證下是否在構造方法執(zhí)行之前氮惯。

main方法

????????先思考一個問題:java的代碼是如何運轉起來的晴氨?類中的確定義了很多變量和方法,問題是誰來調用它們呢鬼悠?總不會自動執(zhí)行吧扩劝?你會說是在另一個類中被調用的,可另一個類又是被誰調用的铛纬?這樣調用來調用去厌均,最終的調用者是誰?是某個固定的類嗎告唆?這些問題的其實可以歸結為:java程序執(zhí)行的起點在哪兒棺弊?
????????在C或著C++中,都會有一個main函數擒悬,操作系統(tǒng)以這個函數為入口模她,順序執(zhí)行其中的代碼。Java也提供了這樣的機制——main方法懂牧,舉個例子:

public static void main(String[] args) {
    Apple apple = new Apple(4);
    apple.grow(4);
    System.out.println(apple.weight);
}

????????Java程序都是從這里啟動并執(zhí)行的侈净。與C/C++不同的是,Java程序是由jvm來執(zhí)行的僧凤,而不是直接由操作系統(tǒng)來執(zhí)行畜侦。說到底,Java是解釋型的語言躯保,由jvm一行行解釋執(zhí)行java編譯后的字節(jié)碼旋膳;C/C++則直接編譯成了二進制的系統(tǒng)指令,操作系統(tǒng)可以直接拿來執(zhí)行途事。Java語言不是自舉的验懊,它無法自己執(zhí)行自己,需要依賴外部力量——jvm一般是由C++編寫實現的尸变。jvm本身也是運行在操作系統(tǒng)中的程序义图,main方法是jvm程序與java程序之間的接口,像是約定好的暗號召烂,在命令行輸入以下命令:

java Apple

????????jvm啟動碱工,尋找并加載Apple類,檢查類中是否有入口——main方法骑晶,而不是別的其他方法痛垛,然后開始執(zhí)行其中的代碼。
????????所以桶蛔,java程序的啟動工作都放在這個方法里面匙头,比如創(chuàng)建一個對象并執(zhí)行其中某個方法。main方法與其他普通方法的唯一區(qū)別在于:它是唯一可以被jvm識別的方法仔雷。當然蹂析,main方法也可以被其他類調用舔示,此時它就是個普通靜態(tài)方法。
????????main方法可以出現在任何類中电抚,只要你想將它作為程序的起點和入口惕稻;但每個jvm進程每次只能啟動一個入口,如果項目中還有其他的類也有main方法蝙叛,那么需要再啟動一個jvm進程來執(zhí)行它——兩個進程之間是互不干擾的俺祠。


已開通個人博客,歡迎訪問~

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末借帘,一起剝皮案震驚了整個濱河市蜘渣,隨后出現的幾起案子,更是在濱河造成了極大的恐慌肺然,老刑警劉巖蔫缸,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異际起,居然都是意外死亡拾碌,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門街望,熙熙樓的掌柜王于貴愁眉苦臉地迎上來校翔,“玉大人,你說我怎么就攤上這事它匕≌谷冢” “怎么了窖认?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵豫柬,是天一觀的道長。 經常有香客問我扑浸,道長烧给,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任喝噪,我火速辦了婚禮础嫡,結果婚禮上,老公的妹妹穿的比我還像新娘酝惧。我一直安慰自己榴鼎,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布晚唇。 她就那樣靜靜地躺著巫财,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哩陕。 梳的紋絲不亂的頭發(fā)上平项,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天赫舒,我揣著相機與錄音,去河邊找鬼闽瓢。 笑死接癌,一個胖子當著我的面吹牛,可吹牛的內容都是我干的扣讼。 我是一名探鬼主播缺猛,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼椭符!你這毒婦竟也來了枯夜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤艰山,失蹤者是張志新(化名)和其女友劉穎湖雹,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體曙搬,經...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡摔吏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了纵装。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片征讲。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖橡娄,靈堂內的尸體忽然破棺而出诗箍,到底是詐尸還是另有隱情,我是刑警寧澤挽唉,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布滤祖,位于F島的核電站,受9級特大地震影響瓶籽,放射性物質發(fā)生泄漏匠童。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一塑顺、第九天 我趴在偏房一處隱蔽的房頂上張望汤求。 院中可真熱鬧,春花似錦严拒、人聲如沸扬绪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挤牛。三九已至,卻和暖如春巧骚,著一層夾襖步出監(jiān)牢的瞬間赊颠,已是汗流浹背格二。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竣蹦,地道東北人顶猜。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像痘括,于是被迫代替她去往敵國和親长窄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔纲菌,今天18年5月份再次想寫文章挠日,發(fā)現簡書還為我保存起的...
    Jenaral閱讀 2,733評論 2 9
  • 一:java概述:1,JDK:Java Development Kit翰舌,java的開發(fā)和運行環(huán)境嚣潜,java的開發(fā)工...
    ZaneInTheSun閱讀 2,629評論 0 11
  • 整理來自互聯網 1,JDK:Java Development Kit椅贱,java的開發(fā)和運行環(huán)境懂算,java的開發(fā)工具...
    Ncompass閱讀 1,534評論 0 6
  • 一:java概述: 1,JDK:Java Development Kit庇麦,java的開發(fā)和運行環(huán)境计技,java的開發(fā)...
    慕容小偉閱讀 1,766評論 0 10
  • 一、基礎知識:1山橄、JVM垮媒、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機...
    殺小賊閱讀 2,365評論 0 4