java基礎(chǔ)篇——面向?qū)ο?/font>
作者:xcbeyond
瘋狂源自夢(mèng)想,技術(shù)成就輝煌!微信公眾號(hào):《程序猿技術(shù)大咖》號(hào)主,專注后端開發(fā)多年,擁有豐富的研發(fā)經(jīng)驗(yàn),樂于技術(shù)輸出、分享,現(xiàn)階段從事微服務(wù)架構(gòu)項(xiàng)目的研發(fā)工作,涉及架構(gòu)設(shè)計(jì)、技術(shù)選型、業(yè)務(wù)研發(fā)等工作。對(duì)于Java、微服務(wù)、數(shù)據(jù)庫、Docker有深入了解,并有大量的調(diào)優(yōu)經(jīng)驗(yàn)。
引言:
面向?qū)ο蟮乃枷胝荍ava學(xué)習(xí)的核心部分,要是沒有搞懂面向?qū)ο?,那么就稱不上學(xué)過Java,因此,搞懂面向?qū)ο笫侵陵P(guān)重要的。對(duì)于初學(xué)者而言,首次接觸面向?qū)ο髸r(shí),總感覺怪怪的,不知道究竟在干什么(我剛開始接觸也是這種感覺,漸漸的就找到感覺了),這其實(shí)都是正?,F(xiàn)象的,不然怎么有人說他是很抽象的啊。面向?qū)ο?,簡單的理解就是把一切事物按照它自己本有存在的特征、屬性通過自然組織語言組織起來,然后再用編程語言來實(shí)現(xiàn)。例如:人(類)本該就分有性別(男、女)、年齡、姓名等屬性特征,然對(duì)于每一個(gè)而言,他們往往具體不同的這些屬性特征值,于是就從“人”(類)這個(gè)類別中具體出來了每個(gè)人,即:類的實(shí)例化得到了對(duì)象。就可以對(duì)象他們進(jìn)行相應(yīng)的操作了。
面向?qū)ο?OO):
按照東西的特征和自然組織形式, 進(jìn)行軟件開發(fā)過程的組織, 是一個(gè)開發(fā)過程的方法論。
學(xué)習(xí)面向?qū)ο?
- 學(xué)習(xí)如何用OO語法描述事物的特征和自然組織形式.
- 學(xué)習(xí)面向?qū)ο笏季S的前提是樸素的哲學(xué)邏輯.
如: 多態(tài), 抽象概念的具體實(shí)現(xiàn)是多態(tài)的,
如:美女是多態(tài)的!
一、類(Class):
它是一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),是把一類相似或相關(guān)聯(lián)數(shù)據(jù)的相關(guān)操作封裝在一起的一個(gè)集合。
1、類是用來描述一個(gè)領(lǐng)域模型中的具體概念(名詞)的。
2、領(lǐng)域模型: 一個(gè)應(yīng)用軟件業(yè)務(wù)范疇, 也叫業(yè)務(wù)模型.
3、屬性: 描述具體概念(事物)的特征.
如:<圖書館管理系統(tǒng)>中的概念: 書 Book
書的特征: 書號(hào), 書名, 編號(hào), 作者, 價(jià)格...
Java中類的寫法(語法)如下:
修飾詞 class 類名{
修飾詞 類型 屬性;
修飾符 返回值類型 方法名 {
// 方法體(實(shí)現(xiàn)類的相關(guān)操作)
}
}
如:
public class Book{
int id;
String name;
String[] authors;
String isbn;
double price;
}
二、對(duì)象:
1、 對(duì)象是類的具體實(shí)例!
比 如,書Book這個(gè)類,它只是代表了一類,你卻不知道它到底是什么書,但你只知道它擁有哪些特點(diǎn)屬性,即書名、書號(hào)、作者、書價(jià)等(類屬性)信息,為了對(duì)書Book這個(gè)類具體化,就引出了“對(duì)象”的概念,因此,對(duì)象就是類的具體實(shí)例。如:《山楂樹之戀》是一本書,《和空姐同居的日子》是一本書,他們屬于Book類的兩個(gè)不同的對(duì)象。
對(duì)象的創(chuàng)建是通過“new”運(yùn)算符進(jìn)行實(shí)例化的,即:
Book book = new Book();//book:引用 new Book():對(duì)象
看到這里,你或許還是一頭霧水,請(qǐng)不必?fù)?dān)心,先暫時(shí)記住就行了,隨后你就會(huì)徹底明白了。new Book()它是真正的在內(nèi)存中(準(zhǔn)確的說是在“堆”內(nèi)存中)創(chuàng)建了一個(gè)Book類的對(duì)象,此時(shí)在“?!敝袆?chuàng)建了一個(gè)Book類型(類也屬于一種數(shù)據(jù)類型,一種引用類型中的“類類型”)的引用變量book,最終將變量book的地址指向了new Book()創(chuàng)建的對(duì)象。<這里地址指向關(guān)系,是隱含存在的一種指針,可以這么理解,僅供理解而已。但java卻是不存在指針的哦!> 。關(guān)于“堆”、“棧”可以參考《java核心內(nèi)容——分配管理》了解。
引用:是指向具體對(duì)象的句柄,相當(dāng)于自然語言的代詞。
1> 代詞本身不是對(duì)象,代詞引用了一個(gè)具體對(duì)象。
2> 在特殊情況下引用(代詞)可能指空。
3> 經(jīng)常簡單的敘述事物時(shí)候,不嚴(yán)格區(qū)別引用與對(duì)象。
如:
Book book = new Book();//book:引用 new Book():對(duì)象
book.name = "月子";
book.authors = new String[]{"白云","黑土"};
book = null;//book引用null
4>引用是null時(shí)候,訪問屬性或方法時(shí)候會(huì)出現(xiàn): 空指針異常
如:
book = null;
System.out.println(book.name);//異常
2、構(gòu)造器(構(gòu)造方法):
在上面語句Book book = new Book()中,或許對(duì)用new Book()創(chuàng)建對(duì)象時(shí),并不知道其真正的含義,其中Book()就是一個(gè)Book類的一個(gè)構(gòu)造器(特殊的方法),用它來對(duì)對(duì)象的屬性進(jìn)行初始化。
構(gòu)造器的使用:
1>、聲明在類內(nèi)部, 方法名與類名一致的方法叫構(gòu)造方法, 構(gòu)造方法不能聲明返回值類型。
2>、構(gòu)造方法可以包含參數(shù), 參數(shù)一般是創(chuàng)建對(duì)象實(shí)例,必須依賴的條件(前提條件)。
如:
public Book(int id,String name,String isbn) {
this.id = id;
this.name = name;
this.isbn = isbn;
}
3>、構(gòu)造方法經(jīng)常會(huì)重載
方法重載:方法的重新書寫,即重載
- 方法名一樣
- 方法參數(shù)不一樣
默認(rèn)構(gòu)造器:
對(duì)于每一個(gè)類都會(huì)存在一個(gè)構(gòu)造器的,只是有些是使用的默認(rèn)構(gòu)造器而已,沒有顯式的顯示出來。
1>、如果類沒有聲明任何構(gòu)造器,Javac自動(dòng)提供一個(gè)默認(rèn)構(gòu)造器, 無參數(shù)默認(rèn)構(gòu)造器。
2>、如果提供構(gòu)造器聲明, Javac將不再提供默認(rèn)構(gòu) 造器。
如:(這個(gè)程序只是為了說明默認(rèn)構(gòu)造器而已,沒有其他實(shí)際價(jià)值)
/**
* 默認(rèn)構(gòu)造器的演示
* @author xcbeyond
*
*/
public class ConstructorDemo {
public static void main(String[] args) {
Foo foo = new Foo();
//Goo goo = new Goo();//錯(cuò)誤,沒有參數(shù)的構(gòu)造器
//System.out.println(foo.a+","+goo.a);
//A 、編譯錯(cuò)誤 B、 1,0 C、 1,1 D、
}
}
class Foo {//沒有顯式的顯示構(gòu)造器,即使用默認(rèn)構(gòu)造器(無參構(gòu)造器)
int a = 1;
}
class Goo{//沒有無參構(gòu)造器了
int a ;
public Goo(int a) {//默認(rèn)無參構(gòu)造器被重載成為了一個(gè)有參構(gòu)造器
this.a = a;
}
}
new運(yùn)算: 創(chuàng)建對(duì)象實(shí)例,如: Book book = new Book();
1、根據(jù)類的屬性在堆中分配對(duì)象空間。
2、根據(jù)參數(shù)類型調(diào)用構(gòu)造器。
3、new運(yùn)算返回對(duì)象的引用地址。
對(duì)象的創(chuàng)建過程:
1、根據(jù)類的屬性在堆中分配對(duì)象空間,并且自動(dòng)初始化。
2、根據(jù)參數(shù)類型調(diào)用構(gòu)造器。
this:
最大的作用就是讓類中一個(gè)方法訪問該類的另一個(gè)方法或?qū)傩浴his可以代表任何對(duì)象。
- this 是對(duì)當(dāng)前對(duì)象的引用, 是當(dāng)前對(duì)象本身。
- 可以使用this明確的訪問當(dāng)前對(duì)象的屬性或者方法。
- this() 是調(diào)用本類的其他構(gòu)造器, 可以使用構(gòu)造器的重用, 簡化代碼的實(shí)現(xiàn).
- this() 必須寫在構(gòu)造器的第一行!
如:public Book(int id ,String name) {
//System.out.print(id);//錯(cuò) ,this()必須寫在第一行
this(id,name,null);
}
public Book(int id,String name,String isbn) {
this.id = id;
this.name = name;
this.isbn = isbn;
}
java方法參數(shù)的傳遞規(guī)則:
參數(shù)傳遞方式只有一種:值傳遞。值傳遞就是將實(shí)際參數(shù)值得副本(復(fù)制品)傳入方法內(nèi),而參數(shù)本身不會(huì)受到任何影響。
1、基本類型就是其中值的復(fù)制, 引用類型是引用值(地址)的復(fù)制。
2、 變量的值:
- 基本類型的值是其本身
- 引用變量的值是一個(gè)地址值,是被引用對(duì)象的首地址
3、為了避免引用參數(shù)傳遞的副作用, 建議一切結(jié)果使用返回值帶回。
如:
/**
* Java方法參數(shù)傳遞規(guī)則:基于值的傳遞,是變量值的復(fù)制
* 為了避免引用方法參數(shù)傳遞的副作用,建議一切結(jié)果使用返回值返回
* @author xcbeyond
*/
public class ParamaterDemo {
public static void main(String[] args) {
Koo koo = new Koo();
int a = 1;
update(a);
update(koo);
System.out.println("a="+a+",koo.a="+koo.a);//a=1,koo.a=2
int b = update2(a);
int c = update2(koo);
System.out.println("b="+b+",c="+c);//2,3
}
public static void update(int a ) {
a++;
}
public static void update(Koo koo) {
koo.a++;
}
public static int update2(int a ) {
a++;
return a;
}
public static int update2(Koo koo) {
koo.a++;
return koo.a;
}
}
class Koo {
int a = 1;
}
3、繼承:
考慮到程序的實(shí)時(shí)擴(kuò)展(添加新的屬性、方法等操作),更好的進(jìn)行維護(hù),于是引入“繼承”這個(gè)概念。它是在原有類的基礎(chǔ)上添加或修改(重寫)新的屬性和方法。子類繼承了父類的所有方法和屬性。
用來表達(dá)類型概念上具體化,Java繼承用extends 關(guān)鍵字。子類是父類的具體化,父類是子類的泛化(概念抽象化)
1>、子類繼承父類的屬性和方法
2>、構(gòu)造器不能繼承!
3>、實(shí)例化子類,會(huì)遞歸分配所有父類的空間
4>、子類默認(rèn)調(diào)用父類的無參數(shù)構(gòu)造器
繼承特點(diǎn):
1>、子類繼承父類的屬性和方法
2>、構(gòu)造器不能繼承
3>、創(chuàng)建子類實(shí)例,會(huì)遞歸分配所有父類的空間
4>、子類默認(rèn)調(diào)用父類的無參數(shù)構(gòu)造器
5>、子類可以覆蓋(重寫)父類的方法,修改父類行為
6>、JAVA只能單一繼承
繼承中的語法現(xiàn)象:
1>, 父類可以引用子類的實(shí)例,父類的實(shí)現(xiàn)是多態(tài)的。
2>, 子類可以覆蓋父類的方法,修改父類的行為。
- 方法覆蓋:子類覆蓋了父類“相同方法簽名”的方法。
- 方法的覆蓋是由方法動(dòng)態(tài)綁定實(shí)現(xiàn)的,就是java虛擬機(jī)運(yùn)行時(shí)候確定執(zhí)行那個(gè)方法,java最終執(zhí)行子類的方法。
關(guān)于繼承中的構(gòu)造器:
1> 、子類遞歸調(diào)用父類構(gòu)造器。
2> 、默認(rèn)調(diào)用父類無參數(shù)構(gòu)造器!
3> 、如果父類沒有無參數(shù)構(gòu)造器,就必須在子類中明確指定調(diào)用父類的有參數(shù)構(gòu)造器!
4> 、使用super()調(diào)用父類構(gòu)造器,必須寫在子類構(gòu)造器第一行。
5> 、編程建議:所有的類都提供無參數(shù)構(gòu)造器!減少繼承時(shí)候的麻煩。
如:
/**
* 子類構(gòu)造器一定調(diào)用父類的構(gòu)造器!
* @author xcbeyond
*
*/
public class ConstructorDemo {
public static void main(String[] args) {
Goo goo = new Goo();
System.out.println(goo.a);//5
}
}
class Foo extends Object {//任何類都繼承Object類(超類)
int a = 1;
public Foo(int a) {
super();//Object類的構(gòu)造器
this.a = a;
}
public void Foo() {//構(gòu)造方法沒有返回類型值,這里并不是構(gòu)造方法,而是一個(gè)一般的方法而已!
}
}
//class Goo extends Foo{} //錯(cuò) , 父類沒有無參數(shù)構(gòu)造器
class Goo extends Foo{
public Goo() {
//System.out.println();//super()必須放在構(gòu)造器的第一行
super(5);//明確調(diào)用父類由參數(shù)構(gòu)造器
}
}
對(duì)象的實(shí)例化過程
1>、 檢查類是否加載,如果沒有加載就加載這個(gè)類
- 如果有父類,要加載所有父類
- 懶惰式加載,如果第一次用到就加載,只加載一次
- 通過CLASSPATH指定的路徑尋找類文件
- 加載以后是一個(gè)對(duì)象,類型是Class
2>、在內(nèi)存堆中分配對(duì)象空間
遞歸分配所以父類屬性空間,然后分別子類的空間,屬性默認(rèn)自動(dòng)初始化,自動(dòng)初始化為“0”值:null,0,false,\u0000
3>、執(zhí)行屬性的賦值
4>、遞歸調(diào)用父類構(gòu)造器。(默認(rèn)調(diào)用父類無參數(shù)構(gòu)造器!)
5>、調(diào)用本類構(gòu)造器
訪問控制:
訪問控制修飾詞:public protected default private
- 聲明屬性和方法盡可能私有,這樣才能做到盡可能封裝
- 提供適當(dāng)?shù)膶傩栽L問方法,適當(dāng)?shù)拈_放屬性的訪問
- 不建議使用非公有類。就是說所有類都應(yīng)該是公有的,并且一個(gè)源文件一個(gè)類
屬性是靜態(tài)綁定到變量類型。
方法是動(dòng)態(tài)綁定,由最終對(duì)象的方法決定。
如:
/**
* 屬性是靜態(tài)綁定到變量類型
* 方法是動(dòng)態(tài)綁定,有最終對(duì)象的方法決定
* @author xcbeyond
*
*/
public class FiledAccessDemo {
public static void main(String[] args) {
Goo goo = new Goo();
Foo foo = goo;
System.out.println(goo.a+","+goo.getA());//2,2
System.out.println(foo.a+","+foo.getA());//1,2
}
}
class Foo {
int a = 1;
public int getA() {
return a;
}
}
class Goo extends Foo {
int a = 2;
public int getA() {
return a; //retrun super.a;
}
}