1. 程式人生 > 其它 >類與物件(Java)

類與物件(Java)

類與物件

類(class)和物件(object)是兩種以計算機為載體的計算機語言的合稱。 物件是對客觀事物的抽象,類是對物件的抽象。 類是一種抽象的資料型別。 它們的關係是,物件是類的例項,類是物件的模板。


物件:

1、新建一個物件

class Student {
	int score, id;
}
//直接建立
Student a = new Student();//新建一個Student物件空間,a指向這個空間,a又叫做物件引用/物件名
//先宣告再建立
Student a;
a = new Student();
a.id = 1;
a.score = 100;

2、成員變數,int, double這些,也可以叫做屬性/欄位

成員變數可以是基本資料型別也可以是引用型別,如String

屬性不賦值,會有預設值,機制和陣列一樣

3、訪問修飾符:public,預設,protected,private

4、類是引用資料型別


方法過載:

特點:

只需要引數列表不同即可, 可以重名,返回型別無要求。


可變引數:

概念:

java允許講一個類中多個同名但引數個數不同的寫法封裝成一個方法,用可變引數實現。

當引數資料型別都相同,且有多個的時候可以用可變引數來優化寫法

基本語法:

基本修飾符  返回型別  方法名(其他資料型別,資料型別... 形參名){

}

例:

class test {
	public int getsum (int... n) {
		int res = 0;
		for (int i = 0; i < n.length; i ++) {
			res += n[i];
		}
		return res;
	}
}

細節:

1、可變引數的實慘個數可以是0個或任意多個

2、可變引數的實慘本質是陣列

3、可變引數的實慘可以是陣列

4、可變引數和普通引數放在形參列表時必須放在最後一個

5、一個形參列表只能出現一個可變引數


作用域:

全域性變數/屬性 可以被本類使用,或者其它類使用(通過物件的呼叫)

區域性變數:只能在本類中對應的方法中使用

修飾符:

全域性變數/屬性可以加修飾符

區域性變數不可以


構造器/構造方法

主要作用:

完成對新物件的初始化

特點:

1、方法名與類名相同

2、無返回值,也不能寫void

3、建立物件時,系統會自動呼叫該類的構造器完成對物件的初始化

4、語法規則和成員方法一樣

5、構造器可以過載,即多個構造器,形參列表不同

//例
class Yra {
	public static void main(String args[]) {
    	Person p1 = new Person("Tom", 18);	
	}    
}

class Person {
    String name;
    int age;
    public Person(String pname, int page) { //構造器初始化成員變數
        name = pname;
        age = page;
    }
}

PS:

1、如果沒有定義構造器,系統會給類建立一個預設構造器;如果定義了就覆蓋了預設構造器,且不能再使用,除非顯式的定義一下,xxx () {}

//預設構造器
xxx() {

}

正如新建物件的時候 xxx a = new xxx();

這個後面的xxx()就是呼叫了預設構造器

技巧:

我們用javac xxx 編譯好了xxx程式後,會新建一個xxx.class檔案,java xxx指令可以用當前系統的直譯器來執行程式,同時我們也可以改用javap xxx.class指令來反編譯這個檔案,我們就能得到被反編譯後能看得懂的類的程式碼,.class可以省略

格式:javap < options > < classes >

-c 反彙編,-p 顯示所有類和成員 ......


this關鍵字

解釋:

在建立完一個物件後,Java虛擬機器會給每個物件分配this,代表當前物件(相當於存了當前物件的地址,指向當前物件)

通過輸出this的hashCode()和this所在物件的hashCode(),兩者是一樣的

補:

hashcode()可以返回該物件的雜湊碼值(一般是通過將該物件的內部地址轉換成一個整數來實現的)

細節:

1、this關鍵字可以用來訪問本類的屬性、方法、構造器

2、this用於區分當前類的屬性與區域性變數

3訪問成員方法的語法:

this.方法名(引數列表)

4、訪問構造器的語法:(只能在構造器中使用,即只能在構造器中訪問另一個構造器)

this(引數列表)

PS:如果要訪問其他構造器,必須把這條語句放在該構造器的第一條語句

例:

public class Yra {
	public static void main(String[] args) {
		T a = new T();
	}
}
class T {
	public T() {
		//呼叫了下面這個構造器,形參列表要對應,同時要放在該構造器第一個語句
		this("Java", 18);
		...
	}
	public T(String s, int n) {}
}

5、this不能在類定義的外部使用,只能在類定義的方法中使用


包:

包可以將類打包,更好的管理類

1、區分相同名的類

2、控制訪問範圍

包基本語法:

package xxx.yyy //用來聲明當前類所在的包,需要放在類的最上面,一個類中最多隻有一個。

package是打包關鍵字,xxx.yyy是包名

可以用import xxx.yyy.類名引入類,這樣可以直接用類名,否則需要前面加上包名

package xxx.yyy;
import xxx.yyy.wuhu;

...

wuhu a = new wuhu()
-------------------------或者

package xxx.yyy;
xxx.yyy.wuhu a = new xxx.yyy.wuhu();

import xxx.yyy.可以將xxx.yyy包下的所有類/工具匯入

命名規則:

只包含數字、字母、下劃線、小圓點,但不能數字開頭,不能是關鍵字或保留字

命名規範:

一般是小寫字母+小圓點

com.公司名.專案名.業務模組


訪問修飾符:

1、public: 對外公開

2、protected:對子類合同一個包中的類公開

3、預設級別的:沒有修飾符號,向同一個包的類公開

4、私有級別:用private修飾,只有類本身可以訪問,不對外公開。

同一個類:都能訪問

同一個包:public, protected, 預設 可以訪問, private不能訪問

不同包:只有public能訪問

無論是否同一個包,那麼子類可以訪問protected的父類。

預設則只有在同一包時,子類可以訪問父類

PS:

1、修飾符可以修飾屬性,成員方法以及類

2、只有預設和public能修飾類

3、成員方法的訪問規則和屬於完全一樣

封裝(encapsulation):

概念:

把抽象出來的資料[屬性]和對資料的操作[方法]封裝在一起,資料被保護在內部,程式的其他部分只有通過被授權的操作[方法],才能對資料進行操作。

封裝的理解和好處:

1、隱藏實現細節、方法(連線資料庫)

2、可以對資料進行驗證,保證安全合理

封裝的實現步驟:

1、將屬性私有化private

2、提供一個公共public的set方法,用於對屬性判斷並賦值

public void setXxx(型別 引數名) {
	//加入資料驗證的業務邏輯
	屬性 = 引數名;
}

3、提供一個公共的get方法,用於獲取屬性的值

public 資料型別 getXxx() { //許可權判斷, Xxx某個屬性
	return xx;
}

set函式和get函式的快捷鍵:alt + insert,選擇setter 和 getter

set方法與構造器:

可以將set方法寫在構造器內,這樣依然可以達到驗證保護的效果

xxx (String name, int age) {
	this.setName(name);
	this.setAge(age);
}

繼承:

繼承基本介紹:

繼承可以解決程式碼複用。當多個類存在相同的屬性和方法時,可以從這些類中抽象出父類,在父類中定義這些相同的屬性和方法,所有子類則不需要重新定義,只需要通過extends來宣告繼承父類即可

大致示意圖:

基本語法:

class 子類 extends 父類 {
	...
}

(1)子類會自動擁有父類定義的屬性和方法

(2)父類又叫超類,基類

(3)子類又叫派生類

好處:

1、程式碼複用性提高 2、程式碼擴充套件性和維護性提高了

細節:

1、子類繼承了所有的屬性和方法,但是私有private屬 性和方法不能再子類直接訪問,要通過父類提供的公共的方法去訪問

2、子類必須呼叫父類的構造器,完成父類的初始化

3、當建立子類物件時,不管使用子類的哪個構造器,預設情況下都會先去呼叫父類的無參構造器。如果父類沒有無參構造器(有有參構造器,無有參構造器就會有預設的無參構造器),則子類中的構造器中需要加上super(),去指定使用父類的哪個構造器完成對父類的初始化工作,否則編譯不會通過。

4、如果希望指定呼叫父類的某個構造器,則顯式的呼叫一下:super(),呼叫無參構造器可以不寫(不加super()預設呼叫無參構造器,如果無就會編譯不通過)。

5、super()在使用時,需要放在子類構造器第一行,super只能在構造器中使用

6、由於super()和this()都必須放在第一行,所以不能共同存在於同一個構造器中

7、Java所有類都是Object類的子類,Object是所有類的基類

8、父類構造器的呼叫不限於直接父類,將一直往上追溯直到Object類(頂級父類)

9、子類最多隻能繼承一個父類(直接繼承),即Java中是單繼承機制

10、不能濫用繼承,子類和父類間必須滿足is - a的邏輯關係

繼承機制:

1、返回資訊時,會先看子類是否有該屬性且可以訪問,如果有就返回,否則就看父類...直至Object類

PS:找的過程中只要遇到有,但不能訪問(如private)就會報錯,不會再向上訪問。

super關鍵字:

概念:

super代表父類的引用,用於訪問父類的屬性、方法、構造器

注意點:

1、訪問父類的屬性,但不能訪問父類的private屬性

語法:super.屬性名

2、訪問父類的方法,不能訪問父類的private方法

語法:super.方法名(引數列表)

3、訪問父類的構造器,只能放在構造器的第一句,且只能有一句

語法:super(引數列表)

細節

1、呼叫父類構造器,能讓分工更明確,父類屬性由父類初始化,子類屬性由子類初始化

2、當子類中有和父類中的成員重名是時,為了訪問父類的成員,必須通過super。如果沒有重名,使用super、this、直接訪問,效果一樣

[訪問規則]:

先找本類,若有則呼叫,否則尋找父類的,如果找到了,並且可以訪問就呼叫,否則繼續訪問父類的父類。

找到了但不能訪問,則報錯

沒有找到,則提示方法不存在

方法cal()
cal();
this.cal();
super.cal();
三者區別在於super.cal()是直接查詢父類

3、super的訪問不限於直接父類,如果爺爺類和本類中有同名的成員,也可以使用super去訪問爺爺類的成員;如果多個基類中都有同名的成員,使用super訪問遵循就近原則。

與this比較:

方法重寫/覆蓋(override)

概念:

方法覆蓋(重寫)就是子類有一個方法,和父類的某個方法的名稱、返回型別、引數一樣,那麼我們就說子類的這個方法覆蓋了父類的那個方法。

細節:

1、子類方法的引數、方法名稱,要和父類方法的引數、方法名稱完全一樣

2、子類方法的返回型別和父類方法的返回型別一樣,或者是父類返回型別的子類。

例:父類返回型別是Object,子類方法返回型別是String

3、子類方法不能縮小父類方法的訪問許可權,擴大可以

public > protected > 預設 > private


多型:

介紹:

方法或物件具有多種形態。是面向物件的第三大特徵,多型是建立在封裝和繼承之上的

1、方法的多型的體現:

方法重寫、過載

2、物件的多型:

(1)一個物件的編譯型別和執行型別可以不一致

例:

Animal animal = new Dog(); 【animal編譯型別是Animal,執行型別是Dog】

animal = new Cat(); 【animal的執行型別變成了Cat,編譯型別仍然是Animal

(2)編譯型別在定義物件時,就確定了,不能改變

(3)執行型別是可以變化的

(4)編譯型別看定義時 = 號的左邊,執行型別看 = 號的右邊

(5)查詢屬性時總是先看其編譯型別,即屬性不具備多型

3、細節:

前提:兩個物件存在繼承關係

向上轉型

1、本質:父類的引用指向了子類的物件

2、語法:父類型別 引用名 = new 子類型別();

3、 特點:可以呼叫父類的所有成員,不能呼叫子類中特有成員(哪怕執行型別是該子類,但編譯型別是父類的話也不能呼叫該子類的特有成員)

4、呼叫方法時,先從執行型別開始找,然後向上就近原則尋找方法。

向下轉型

1、語法:子類型別 引用名 = (子類型別)父類引用

2、 只能強轉父類的引用,不能強轉父類的物件

3、要求父類的引用必須指向的是當前目標型別的物件(該引用的執行型別必須是目標型別)

4、當向下轉型後,可以呼叫子類型別中的所有成員 ,否則不可以

屬性沒有重寫之說,屬性的值看編譯的型別

判斷一條語句是向上轉型還是向下可以看等號右邊的變數從什麼型別變到什麼型別,往父類變了就是向上,否則向下

4、instanceof

aa instanceof AA

判斷aa的執行型別是否是AA型別或者AA型別的子型別

是則返回true,否則false

4、Java的動態繫結機制

1、當呼叫物件方法的時候,該方法會和該物件的記憶體地址/執行型別繫結

(在用a去呼叫某一個函式時,會一直從a的執行型別開始找,哪怕在A類裡呼叫一個A類與A的子類都有的方法,這時候也會先從a的執行型別開始找,不會直接呼叫A類的該方法)

2、當呼叫物件屬性時,沒有動態繫結機制,哪裡宣告,哪裡使用

(呼叫屬性時則不同,在A類裡呼叫一個A類和A的子類都有的屬性,會直接呼叫A類的屬性)

5、多型陣列

多型陣列中如果要呼叫各個元素的型別的特定方法,可以加上判斷

if (a[i] instanceof A) {
	A的特定方法
} else if(a[i] instanceof B) {
    B的特定方法
}

Object類

一、equals方法

1、== 和 equals的區別

==:

即可以判斷基本類 型(值是否相等),又可以判斷引用型別(判斷地址是否相等,即是否指向同一個物件)

equals:

是Object類中的方法,只能判斷引用型別。Object的equals預設判斷的是地址是否相等,子類裡往往重寫該方法,用於判斷內容是否相等,例如Integer類,String類

String a = new String("wuhu");
String b = new String("wuhu");
System.out.print(a == b); // false 判斷是否指向同一個物件
System.out.print(a.equals(b)); // true  重寫為判斷值是否相等

二、hashCode方法

1、提高具有雜湊結構的容器的效率 HashSet、HashMap等

2、兩個引用,如果指向的是同一個物件則雜湊值肯定一樣

3、兩個引用,如果指向的是不同物件,則雜湊值不一樣

4、雜湊值主要根據地址號來的,但不能完全相互等價

三、toString方法

1、預設返回:全類名(包名+類名)+ @ + 雜湊值的十六進位制

2、重寫toString方法,輸出物件屬性時可以使用快捷鍵alt + insert --> toString

3、直接輸出一個物件時,toString會被預設呼叫

四、finalize

1、當物件被回收時,系統會自動呼叫該物件的finalize方法(沒有則會呼叫Object類的)。子類可以重寫該方法,做一些釋放資源的操作(比如資料庫連線,或者開啟檔案…)。

2、什麼時候被回收:當某個物件沒有任何引用時,則jvm就認為這個物件是一個垃圾物件,就會使用垃圾回收機制來銷燬該物件,在銷燬該物件前,會先呼叫finalize方法

3、垃圾回收機制的呼叫,是由系統來決定,也可以通過System.gc()主動觸發垃圾回收機制