java类初始化顺序_《To Be a Better Javaer》-- Java 基础篇 vol.2:面向对象
Java是面向?qū)ο蟮母呒?jí)編程語言,面向?qū)ο蟮奶卣魅缦?#xff1a;
- 面向?qū)ο缶哂谐橄蟆⒎庋b、繼承、多態(tài)等特性;
- 面向?qū)ο罂梢詫?fù)雜的業(yè)務(wù)邏輯簡(jiǎn)單化,增強(qiáng)代碼復(fù)用性;
- 面向?qū)ο笫且环N常見的思想,比較符合人們的思考習(xí)慣。
面向過程和面向?qū)ο笫鞘裁?#xff1f;
二者的區(qū)別
對(duì)象 & 類
在大多面向?qū)ο蟮恼Z言都使用 class 定義類,類就是對(duì)一系列對(duì)象的抽象,類好比是快遞的外包裝,類里面的內(nèi)容就表示這個(gè)對(duì)象的定義;例如:
class Javaer{}這樣,就聲明了一個(gè)名字為 Javaer 的類,在 Java 中,可以通過 new 來創(chuàng)建這個(gè)對(duì)象:
Javaer javaer = new Javaer();在 Java 中,類的命名要遵守駝峰命名法,
駱駝式命名法(Camel-Case)又稱駝峰式命名法,是電腦程式編寫時(shí)的一套命名規(guī)則(慣例)。正如它的名稱 CamelCase 所表示的那樣,是指混合使用大小寫字母來構(gòu)成變量和函數(shù)的名字。程序員們?yōu)榱俗约旱拇a能更容易的在同行之間交流,所以多采取統(tǒng)一的可讀性比較好的命名方式。創(chuàng)建對(duì)象
在使用 Java 過程中,都是和對(duì)象打交道,Java 中的一切都可以看作是對(duì)象,但盡管如此,我們操作對(duì)象,卻是對(duì)對(duì)象的引用:
Door key;如上代碼中創(chuàng)建的只是引用,并非一個(gè)對(duì)象;如果要想正確的創(chuàng)建一個(gè)對(duì)象并且不在編譯的過程中出錯(cuò),那么就需要在創(chuàng)建對(duì)象引用時(shí)同時(shí)把一個(gè)對(duì)象賦給它。
Door key = new Door();在 Java 中,一旦創(chuàng)建了一個(gè)引用,就希望它能與一個(gè)新的對(duì)象進(jìn)行關(guān)聯(lián),通常使用 new 操作符來實(shí)現(xiàn)這一目的。
屬性和方法
對(duì)于一個(gè)類,最基本的要素就是要有屬性和方法;
屬性又被稱為字段:
Class Door {int a;Key key; }方法就是函數(shù),方法的基本組成包括 方法名稱、參數(shù)、返回值和方法體
public int get(){return 1; }在上面的示例中,get 是方法名稱,() 內(nèi)是方法接收的參數(shù)、return 后面的是方法的返回值(如果是 void 方法,則不需要返回值),{} 里的是方法體。
構(gòu)造方法
Java 中有一種特殊的構(gòu)造方法,又被叫做構(gòu)造器或者構(gòu)造函數(shù)。構(gòu)造方法就是在創(chuàng)建對(duì)象的時(shí)候保證每個(gè)對(duì)象都被初始化。構(gòu)造方法只在創(chuàng)建對(duì)象的時(shí)候調(diào)用一次,它沒有參數(shù)類型和返回值,它的名稱要和類名保持一致,并且構(gòu)造方法可以有多個(gè)。
Class Door{int number;String color;public Door(){}public Door(int number){}public Door(String color){}public Door(int number,String color){} }上述代碼中定義了一個(gè) Door 類,但是卻沒有參數(shù)類型和返回值,而且有多個(gè)同名的 Door() 方法,每個(gè)方法的參數(shù)列表也不同,其實(shí)這是面向?qū)ο筇卣?-多態(tài)的體現(xiàn),后文會(huì)介紹。定義好構(gòu)造方法后,我們就能創(chuàng)建一個(gè) Door 對(duì)象了。
class creatDoor{public static void main(String[] args) {Door door1 = new Door();Door door2 = new Door(1);Door door3 = new Door("yellow");Door door4 = new Door(1,"yellow");} }如果類中沒有定義任何構(gòu)造方法,那么 JVM 會(huì)為你自動(dòng)生成一個(gè)構(gòu)造方法,如下
class Door {int number;String color;}class createDoor {public static void main(String[] args) {Door door1 = new Door();} }默認(rèn)的構(gòu)造方法也被稱為默認(rèn)構(gòu)造器或者無參構(gòu)造器。
這里需要注意一點(diǎn)的是,即使 JVM 會(huì)為你默認(rèn)添加一個(gè)無參的構(gòu)造器,但是如果你手動(dòng)定義了任何一個(gè)構(gòu)造方法,JVM 就不再為你提供默認(rèn)的構(gòu)造器,你必須手動(dòng)指定,否則會(huì)出現(xiàn)編譯錯(cuò)誤。
方法重載
重載在 Java 中是一個(gè)很重要的概念,它是類名的不同表現(xiàn)形式,上文提到的構(gòu)造函數(shù),是重載的一種,另外一種重載就是方法的重載。
public class Door {int number;String color;public Door(){}public Door(int number){}public int getDoor(int number){return 1;}public String getDoor(String color){return "color";}}如上所示,有 Door 的構(gòu)造函數(shù)的重載,也有 getDoor 方法的重載。
如果有幾個(gè)相同的方法名字,Java 如何知道你調(diào)用的是哪個(gè)方法呢?
每個(gè)重載的方法都有獨(dú)一無二的參數(shù)列表。其中包括參數(shù)的類型、順序、參數(shù)數(shù)量等,滿足一種一個(gè)因素就構(gòu)成了重載的必要條件:
- 方法名稱必須相同。
- 參數(shù)列表必須不同(個(gè)數(shù)不同、或類型不同、參數(shù)類型排列順序不同等)。
- 方法的返回類型可以相同也可以不相同。
- 僅僅返回類型不同不足以成為方法的重載。
- 重載是發(fā)生在編譯時(shí)的,因?yàn)榫幾g器可以根據(jù)參數(shù)的類型來選擇使用哪個(gè)方法。
方法的重寫
方法重寫的描述是對(duì)子類和父類之間的。
而重載是發(fā)生同一個(gè)類中的。
class Food {public void eat(){System.out.printl('eat food');} }class Fruit extends Food{@Overridepublic void eat(){System.out.printl('eat fruit');} }上述代碼中,就含有重寫的范例,子類 Fruit 中的方法和父類 Food 的方法相同
所以重寫的標(biāo)準(zhǔn)是:
- 重寫的方法必須要和父類保持一致,包括返回值類型,方法名,參數(shù)列表 也都一樣。
- 重寫的方法可以使用 @Override 注解來標(biāo)識(shí)
- 子類中重寫方法的訪問權(quán)限不能低于父類中方法的訪問權(quán)限。
初始化
我們?cè)趧?chuàng)建一個(gè)對(duì)象,使用 new 創(chuàng)建對(duì)象的時(shí)候,實(shí)際上是調(diào)用了這個(gè)對(duì)象無參數(shù)的構(gòu)造方法進(jìn)行的初始化。這個(gè)無參數(shù)的構(gòu)造函數(shù)可以隱藏,由 JVM 自動(dòng)添加。也就是說,構(gòu)造函數(shù)能夠確保類的初始化。
class Door{public Door(){} }成員初始化
成員初始化有兩種形式
其他數(shù)據(jù)類型,如 String ,其初始值默認(rèn)為 null
構(gòu)造器初始化
構(gòu)造器可以用來對(duì)某些方法和某些動(dòng)作進(jìn)行初始化,從而確定初始值:
public class Number{int n;public Number(){n = 11;} }利用構(gòu)造函數(shù),能夠把 n 的值初始化為 11。
初始化順序
- 靜態(tài)屬性:static 開頭定義的屬性
- 靜態(tài)方法塊: static {} 包起來的代碼塊
- 普通屬性: 非 static 定義的屬性
- 普通方法塊: {} 包起來的代碼塊
- 構(gòu)造函數(shù): 類名相同的方法
- 方法: 普通方法
要驗(yàn)證初始化的順序,最好的方法就是寫代碼實(shí)踐得到
public class TheOrder {// 靜態(tài)屬性private static String staticField = getStaticField();// 靜態(tài)方法塊static {System.out.println(staticField);System.out.println("靜態(tài)方法塊初始化");}// 普通屬性private String field = getField();// 普通方法塊{System.out.println(field);}// 構(gòu)造函數(shù)public TheOrder() {System.out.println("構(gòu)造函數(shù)初始化");}public static String getStaticField() {String statiFiled = "Static Field Initial";return statiFiled;}public static String getField() {String filed = "Field Initial";return filed;}// 主函數(shù)public static void main(String[] argc) {new TheOrder();} }最終輸出結(jié)果為
Static Field Initial 靜態(tài)方法塊初始化 Field Initial 構(gòu)造函數(shù)初始化那么初始化順序就是:
this 和 super
this 和 super 都是 Java 中的關(guān)鍵字
this
this 這個(gè)關(guān)鍵字只能用在方法的方法體內(nèi)。當(dāng)一個(gè)對(duì)象創(chuàng)建后,JVM 就會(huì)給這個(gè)對(duì)象分配引用自己的指針,這個(gè)指針的名字就叫做 this 。
this 表示的當(dāng)前的對(duì)象,可以用來調(diào)用方法、屬性以及對(duì)象本身。
public class Test{private int number;private String username;private String password;private int x = 100;public Test(int n){number = n;//這個(gè)可以寫為this.number = n;}public Test(int i, String username, String password){//成員變量和參數(shù)同名,成員變量被屏蔽,用"this.成員變量"的方式訪問成員變量.this.username = username;this.password = password;}//默認(rèn)不帶參數(shù)的構(gòu)造方法public Test(){this(0, "未知", "空");//通過this調(diào)用另外一個(gè)構(gòu)造方法. }public Test(String name){this(1, name, "空");/** 通過this調(diào)用另外一個(gè)構(gòu)造方法. 雖然上面的兩種構(gòu)造方法都是編譯通過的。但是并沒有實(shí)際的意義。一般我們會(huì)在參數(shù)多的構(gòu)造函數(shù)里面去用this調(diào)用參數(shù)少的構(gòu)造函數(shù)(并且只能放在方法體里面的第一行)。* 示例里面的這種構(gòu)造方法就相當(dāng)于給了三個(gè)參數(shù)(其中兩個(gè)參數(shù)已經(jīng)定了,另一個(gè)參數(shù)在這個(gè)構(gòu)造方法傳入)。 */}public Test(int i, String username){this(i, username, null);//通過this調(diào)用另外一個(gè)構(gòu)造方法. }}this 使用方法總結(jié)
super
面向?qū)ο笕筇匦?/h2>封裝
封裝在 Java 中又稱訪問控制權(quán)限,訪問控制權(quán)限其實(shí)最核心就是一點(diǎn):只對(duì)需要的類可見。
Java 中成員的訪問權(quán)限共有四種,分別是 public、protected、default、private,它們的可見性如下
繼承
繼承是所有 OOP 語言和 Java 語言不可缺少的組成部分。
繼承是 Java 面對(duì)對(duì)象編程技術(shù)的一塊基石,是面對(duì)對(duì)象的三大特征之一,也是實(shí)現(xiàn)軟件復(fù)用的重要手段,繼承可以理解為一個(gè)對(duì)象從另一個(gè)對(duì)象獲取屬性的過程。
當(dāng)我們準(zhǔn)備編寫一個(gè)類時(shí),發(fā)現(xiàn)某個(gè)類已有我們所需要的成員變量和方法,假如我們想復(fù)用這個(gè)類的成員變量和方法,即在所編寫類中不用聲明成員變量就相當(dāng)于有了這個(gè)成員變量,不用定義方法就相當(dāng)于有了這個(gè)方法,那么我們可以將編寫的類聲明為這個(gè)類的子類即繼承。
源類,基類,超類或者父類都是一個(gè)概念導(dǎo)出類,繼承類,子類也都是同一個(gè)概念繼承中最常使用的兩個(gè)關(guān)鍵字是 extends 和 implements 。
這兩個(gè)關(guān)鍵字的使用決定了一個(gè)對(duì)象和另一個(gè)對(duì)象是否是 IS-A (是一個(gè))關(guān)系。
通過使用這兩個(gè)關(guān)鍵字,我們能實(shí)現(xiàn)一個(gè)對(duì)象獲取另一個(gè)對(duì)象的屬性。
所有 Java 的類均是由 java.lang.Object 類繼承而來的,所以 Object 是所有類的祖先類,而除了 Object 外,所有類必須有一個(gè)父類。
繼承的語法
class Father{private int i;protected int j;public void func(){} }class Son extend Father{public int k;public void func(){} }注意:如類聲明語句中沒有extends子句,則該類為java.lang包中的Object的子類。這就說明了java中的代碼其實(shí)都有一個(gè)繼承的關(guān)系,只不過是繼承Object這個(gè)java中最根本的父類。
繼承的特點(diǎn)
多態(tài)
多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個(gè)接口,使用不同的實(shí)例而執(zhí)行不同操作。
多態(tài)性是面向?qū)ο缶幊痰挠忠粋€(gè)重要特征,它是指在父類中定義的屬性和方法被子類繼承之后,可以具有不同的數(shù)據(jù)類型或表現(xiàn)出不同的行為,這使得同一個(gè)屬性或方法在父類及其各個(gè)子類中具有不同的含義。 對(duì)面向?qū)ο髞碚f,多態(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)。其中編譯時(shí)多態(tài)是靜態(tài)的,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來區(qū)分不同的方法。通過編譯之后會(huì)變成兩個(gè)不同的方法,在運(yùn)行時(shí)談不上多態(tài)。而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的,它是通過動(dòng)態(tài)綁定來實(shí)現(xiàn)的,也就是大家通常所說的多態(tài)性。e.g. 彩色打印機(jī)和黑白打印機(jī)都是打印機(jī),但是他們打印出來的東西顏色不一樣。這就是多態(tài)
多態(tài)實(shí)現(xiàn)的條件
多態(tài)的優(yōu)點(diǎn)
接口和抽象類
接口
接口(英文:Interface),在 Java 編程語言中是一個(gè)抽象類型,是抽象方法的集合,接口通常以 interface 來聲明。一個(gè)類通過繼承接口的方式,從而來繼承接口的抽象方法。
接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對(duì)象的屬性和方法。接口則包含類要實(shí)現(xiàn)的方法。除非實(shí)現(xiàn)接口的類是抽象類,否則該類要定義接口中的所有方法。
接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。
接口和類相似點(diǎn):
- 一個(gè)接口可以有多個(gè)方法。
- 接口文件保存在.java結(jié)尾的文件中,文件名使用接口名。
- 接口的字節(jié)碼文件保存在.class結(jié)尾的文件中。
- 接口相應(yīng)的字節(jié)碼文件必須在與包名稱相匹配的目錄結(jié)構(gòu)中。
接口和類的區(qū)別:
- 接口不能用于實(shí)例化對(duì)象。
- 接口沒有構(gòu)造方法。
- 接口中所有的方法必須是抽象方法。
- 接口不能包含成員變量,除了static和final變量。
- 接口不是被類繼承了,而是要被類實(shí)現(xiàn)。
- 接口支持多重繼承。
接口的聲明
[可見度] interface 接口名稱 [extends 其他類名]{// 聲明變量// 抽象方法 }范例:
public interface TestInterface{public void eat();public void drink(); }接口的實(shí)現(xiàn)
類實(shí)現(xiàn)接口的時(shí)候,類要實(shí)現(xiàn)接口中所有的方法。否則,類必須聲明為抽象的類。
范例:
public class Test implements TestInterface{public void eat(){System.out.println("吃東西");}public void drink(){System.out,println("喝水");}public static void main(String args[]){Test t = new Test();t.eat();t.drink();} }在實(shí)現(xiàn)接口的時(shí)候,要注意:
- 一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)接口。
- 一個(gè)類只能繼承一個(gè)類,但是能實(shí)現(xiàn)多個(gè)接口。
- 一個(gè)接口能繼承另一個(gè)接口,這和類之間的繼承比較相似。
抽象類
一個(gè)類中沒有包含足夠的信息來描繪一個(gè)具體的對(duì)象,這樣的類就是抽象類。抽象類除了不能實(shí)例化對(duì)象之外,類的其它功能依然存在,成員變量、成員方法和構(gòu)造方法的訪問方式和普通類一樣。
由于抽象類不能實(shí)例化對(duì)象,所以抽象類必須被繼承,才能被使用。也是因?yàn)檫@個(gè)原因,通常在設(shè)計(jì)階段決定要不要設(shè)計(jì)抽象類。
父類包含了子類集合的常見的方法,但是由于父類本身是抽象的,所以不能使用這些方法。
在 Java 中用 abstract class 來定義抽象類。
public interface Test {void ColorTest();}abstract class WhiteDog implements Dog{public void ColorTest(){System.out.println("Color is white");}abstract void MMiniTest(); }在抽象類中,具有如下特征
- 如果一個(gè)類中有抽象方法,那么這個(gè)類一定是抽象類,也就是說,使用關(guān)鍵字 abstract 修飾的方法一定是抽象方法,具有抽象方法的類一定是抽象類。實(shí)現(xiàn)類方法中只有方法具體的實(shí)現(xiàn)。
- 抽象類中不一定只有抽象方法,抽象類中也可以有具體的方法,你可以自己去選擇是否實(shí)現(xiàn)這些方法。
- 抽象類中的約束不像接口那么嚴(yán)格,你可以在抽象類中定義 構(gòu)造方法、抽象方法、普通屬性、方法、靜態(tài)屬性和靜態(tài)方法
- 抽象類和接口一樣不能被實(shí)例化,實(shí)例化只能實(shí)例化具體的類
總結(jié)
以上是生活随笔為你收集整理的java类初始化顺序_《To Be a Better Javaer》-- Java 基础篇 vol.2:面向对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: crowd counting_[crow
- 下一篇: 针眼是什么引起的(针眼是什么)