關於Java中類的那些事

類與對象

類中主要包括五種結構,下面進行對這五種結構進行詳細的介紹。前端

1. 面向對象與面向過程

  • 面向過程:強調的是功能行爲,以函數爲最小單位,考慮怎麼作。
  • 面向對象:強調具有了功能的對象,以類/對象爲最小單位,考慮誰來作。--惟物主義(物質決定意識)

​ 舉例對比:把大象裝進冰箱。java

2. 類與對象的關係

類:對一類事物的描述,是抽象的、概念上的定義 對象:是實際存在的該類事物的每一個個體,於是也稱爲實例(instance)面試

面向對象程序設計的重點是類的設計 設計類,就是設計類的成員。數據庫

兩者的關係:對象,是由類new出來的,派生出來的。後端

3. 面向對象思想實現的規則

  1. 建立類,設計類的成員數組

  2. 建立類的對象網絡

  3. 經過「對象.屬性」或「對象.方法」調用對象的結構dom

補充:幾個概念的使用說明ide

  • 屬性 = 成員變量 = field = 域、字段
  • 方法 = 成員方法 = 函數 = method
  • 建立類的對象 = 類的實例化 = 實例化類

4. 對象的建立與對象的內存解析

典型代碼:函數

Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//沒有新建立一個對象,共用一個堆空間中的對象實體。
/*說明:
*若是建立了一個類的多個對象,則每一個對象都獨立的擁有一套類的屬性。(非static的)
*意味着:若是咱們修改一個對象的屬性a,則不影響另一個對象屬性a的值。
*/

內存解析:

image-20200404210954848

5. JVM內存結構

編譯完源程序之後,生成一個或多個字節碼文件。 咱們使用JVM中的類的加載器和解釋器對生成的字節碼文件進行解釋運行。意味着,須要將字節碼文件對應的類加載到內存中,涉及到內存解析。

《JVM規範》

虛擬機棧,即爲平時提到的棧結構。咱們將局部變量存儲在棧結構中 堆,咱們將new出來的結構(好比:數組、對象)加載在對空間中。

補充:對象的屬性(非static的)加載在堆空間中。 方法區:類的加載信息、常量池、靜態域

6. 匿名對象:

咱們建立的對象,沒顯式的賦給一個變量名。即爲匿名對象 特色:匿名對象只能調用一次。 舉例:

new Phone().sendEmail();
new Phone().playGame();
		
new Phone().price = 1999;
new Phone().showPrice();//0.0

應用場景:

PhoneMall mall = new PhoneMall();

//匿名對象的使用
mall.show(new Phone());
其中,
class PhoneMall{
	public void show(Phone phone){
		phone.sendEmail();
		phone.playGame();
	}
	
}

7. "萬事萬物皆對象"

  1. 在Java語言範疇中,咱們都將功能、結構等封裝到類中,經過類的實例化,來調用具體的功能結構
  • Scanner,String等
  • 文件:File
  • 網絡資源:URL
  1. 涉及到Java語言與前端Html、後端的數據庫交互時,先後端的結構在Java層面交互時,都體現爲類、對象。

類的結構之一:屬性

對比:屬性 vs 局部變量

1. 相同點:

1.1 定義變量的格式:數據類型 變量名 = 變量值

1.2 先聲明,後使用

1.3 變量都其對應的做用域

2. 不一樣點:

2.1 在類中聲明的位置的不一樣

  • 屬性:直接定義在類的一對{}內
  • 局部變量:聲明在方法內、方法形參、代碼塊內、構造器形參、構造器內部的變量。

2.2 關於權限修飾符的不一樣

  • 屬性:能夠在聲明屬性時,指明其權限,使用權限修飾符。
  • 經常使用的權限修飾符:private、public、缺省、protected  --->封裝性
  • 目前,聲明屬性時,使用缺省就能夠。
  • 局部變量:不可使用權限修飾符。

2.3 默認初始化值的狀況:

  • 屬性:類的屬性,根據其類型,都默認初始化值。
  • 整型(byte、short、int、long:0)
  • 浮點型(float、double:0.0)
  • 字符型(char:0  (或'\u0000'))
  • 布爾型(boolean:false)
  • 引用數據類型(類、數組、接口:null)

  • 局部變量:沒默認初始化值。

    • 意味着,咱們在調用局部變量以前,必定要顯式賦值。
    • 特別地:形參在調用時,咱們賦值便可。

2.4 在內存中加載的位置:

  • 屬性:加載到堆空間中   (非static)
  • 局部變量:加載到棧空間

補充:回顧變量的分類: 方式一:按照數據類型:

方式二:按照在類中聲明的位置:

類的結構之二:方法

方法:描述類應該具的功能。

好比:Math類:sqrt()\random() ...

  • Scanner類:nextXxx() ...
  • Arrays類:sort() \ binarySearch() \ toString() \ equals() \ ...

1.舉例:

public void eat(){}
 public void sleep(int hour){}
 public String getName(){}
 public String getNation(String nation){}

2.方法的聲明:

權限修飾符 返回值類型 方法名(形參列表){

方法體

}

注意:static、final、abstract 等關鍵字修飾的方法,後面再聊。

3.說明:

3.1 關於權限修飾符:默認方法的權限修飾符先都使用public

Java規定的4種權限修飾符:private、public、缺省、protected -->封裝性

3.2 返回值類型: 返回值 vs 沒返回值

3.2.1 若是方法返回值,則必須在方法聲明時,指定返回值的類型。同時,方法中,須要使用

  • return關鍵字來返回指定類型的變量或常量:「return 數據」。

  • 若是方法沒返回值,則方法聲明時,使用void來表示。一般,沒返回值的方法中,就不須要

  • 使用return.可是,若是使用的話,只能「return;」表示結束此方法的意思。

3.2.2 咱們定義方法該不應返回值?

① 題目要求

② 憑經驗:具體問題具體分析

3.3 方法名:屬於標識符,遵循標識符的規則和規範,「見名知意」

3.4 形參列表: 方法能夠聲明0個,1個,或多個形參。

3.4.1 格式:數據類型1 形參1,數據類型2 形參2,...

3.4.2 咱們定義方法時,該不應定義形參?

① 題目要求

② 憑經驗:具體問題具體分析

3.5 方法體:方法功能的體現。

4.方法的使用中,能夠調用當前類的屬性或方法

  • 特殊的:方法A中又調用了方法A:遞歸方法。
  • 方法中,不能夠定義方法。

return關鍵字

1.使用範圍:使用在方法體中 2.做用:

​ ① 結束方法

​ ② 針對於返回值類型的方法,使用"return 數據"方法返回所要的數據。 3.注意點:return關鍵字後面不能夠聲明執行語句。

方法的重載

1.重載的概念

定義:在同一個類中,容許存在一個以上的同名方法,只要它們的參數個數或者參數類型不一樣便可。

總結:"兩同一不一樣":

  • 相同:同一個類、相同方法名
  • 參數列表不一樣:參數個數不一樣,參數類型不一樣

2.構成重載的實例:

舉例一:Arrays類中重載的sort() / binarySearch();PrintStream中的println()
舉例二:
//以下的4個方法構成了重載
	public void getSum(int i,int j){
		System.out.println("1");
	}
	
	public void getSum(double d1,double d2){
		System.out.println("2");
	}
	
	public void getSum(String s ,int i){
		System.out.println("3");
	}
	
	public void getSum(int i,String s){
		System.out.println("4");
	}

不構成重載的實例:

//以下的3個方法不能與上述4個方法構成重載
public int getSum(int i,int j){
	return 0;
}
	
public void getSum(int m,int n){
		
}
	
private void getSum(int i,int j){
	
}

3.如何判斷是否構成方法重載?

嚴格按照定義判斷:兩同一不一樣。 跟方法的權限修飾符、返回值類型、形參變量名、方法體都不要緊!

4.如何肯定類中某一個方法的調用:

①方法名 ---> ②參數列表

可變個數形參方法

1.使用說明

JDK 5.0新增的內容

JDK 5.0之前:採用數組形參來定義方法,傳入多個同一類型變量 public static void test(int a, String[ ]books);

JDK 5.0:採用可變個數形參來定義方法,傳入多個同一類型變量 public static void test(int a, String ... books);

具體使用:

2.1 可變個數形參的格式:數據類型 ... 變量名

2.2 當調用可變個數形參的方法時,傳入的參數個數能夠是:0個,1個,2個,。。。

2.3 可變個數形參的方法與本類中方法名相同,形參不一樣的方法之間構成重載

2.4 可變個數形參的方法與本類中方法名相同,形參類型也相同的數組之間不構成重載。換句話說,兩者不能共存。

2.5 可變個數形參在方法的形參中,必須聲明在末尾

2.6 可變個數形參在方法的形參中,最多隻能聲明一個可變形參。

2.舉例說明

public void show(int i){
		
}
	
public void show(String s){
	System.out.println("show(String)");
}
	
public void show(String ... strs){
	System.out.println("show(String ... strs)");
		
	for(int i = 0;i < strs.length;i++){
		System.out.println(strs[i]);
	}
}
	//不能與上一個方法同時存在
//	public void show(String[] strs){
//		
//	}
調用時:可變形參與數組相似
		test.show("hello");
		test.show("hello","world");
		test.show();
		
		test.show(new String[]{"AA","BB","CC"});

Java的值傳遞機制

1.針對方法內變量的賦值舉例:

System.out.println("***********基本數據類型:****************");
	int m = 10;
	int n = m;
		
System.out.println("m = " + m + ", n = " + n);
		
	n = 20;
		
System.out.println("m = " + m + ", n = " + n);
		
System.out.println("***********引用數據類型:****************");
		
	Order o1 = new Order();
	o1.orderId = 1001;
		
Order o2 = o1;//賦值之後,o1和o2的地址值相同,都指向了堆空間中同一個對象實體。
		
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
		
	o2.orderId = 1002;
		
System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);

規則: 若是變量是基本數據類型,此時賦值的是變量所保存的數據值。 若是變量是引用數據類型,此時賦值的是變量所保存的數據的地址值。

2.針對於方法的參數概念

形參:方法定義時,聲明的小括號內的參數 實參:方法調用時,實際傳遞給形參的數據

3. Java中參數傳遞機制:值傳遞機制

規則:

  • 若是參數是基本數據類型,此時實參賦給形參的是實參真實存儲的數據值。
  • 若是參數是引用數據類型,此時實參賦給形參的是實參存儲數據的地址值。

推廣:

  • 若是變量是基本數據類型,此時賦值的是變量所保存的數據值。
  • 若是變量是引用數據類型,此時賦值的是變量所保存的數據的地址值。

4.內存解析:

內存解析畫法要點:

1.內存結構:棧(局部變量)、堆(new出來的結構:對象(非static成員變量)、數組

2.變量:成員變量 vs 局部變量(方法內、方法形參、構造器內、構造器形參、代碼塊內)

舉例一

舉例二

遞歸方法

1.定義:

遞歸方法:一個方法體內調用它自身。

2.如何理解遞歸方法?

方法遞歸包含了一種隱式的循環,它會重複執行某段代碼,但這種重複執行無須循環控制。 遞歸必定要向已知方向遞歸,不然這種遞歸就變成了無窮遞歸,相似於死循環。

3.舉例:

// 例1:計算1-n之間所天然數的和
	public int getSum(int n) {// 3

		if (n == 1) {
			return 1;
		} else {
			return n + getSum(n - 1);
		}

	}

	// 例2:計算1-n之間所天然數的乘積:n!
	public int getSum1(int n) {

		if (n == 1) {
			return 1;
		} else {
			return n * getSum1(n - 1);
		}

	}
	
	//例3:已知一個數列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
	//其中n是大於0的整數,求f(10)的值。
	public int f(int n){
		if(n == 0){
			return 1;
		}else if(n == 1){
			return 4;
		}else{
//			return f(n + 2) - 2 * f(n + 1);
			return 2*f(n - 1) + f(n - 2);
		}
	}

	//例4:斐波那契數列
	
	//例5:漢諾塔問題
	
	//例6:快排

方法的重寫

1. 什麼是方法的重寫(override 或 overwrite)?

子類繼承父類之後,能夠對父類中同名同參數的方法,進行覆蓋操做.

2. 應用:

重寫之後,當建立子類對象之後,經過子類對象調用子父類中的同名同參數的方法時,實際執行的是子類重寫父類的方法。

3. 舉例:

class Circle{
public double findArea(){}//求面積
}
class Cylinder extends Circle{
public double findArea(){}//求表面積
}
**********************************************
class Account{
public boolean withdraw(double amt){}
}
class CheckAccount extends Account{
public boolean withdraw(double amt){}
}

4. 重寫的規則:

​ 方法的聲明:

權限修飾符  返回值類型  方法名(形參列表) throws 異常的類型{
 						//方法體
  						}

約定俗稱:子類中的叫重寫的方法,父類中的叫被重寫的方法

  1. 子類重寫的方法的方法名和形參列表與父類被重寫的方法的方法名和形參列表相同
  2. 子類重寫的方法的權限修飾符不小於父類被重寫的方法的權限修飾符

特殊狀況:子類不能重寫父類中聲明爲private權限的方法

  1. 返回值類型:
  • 父類被重寫的方法的返回值類型是void,則子類重寫的方法的返回值類型只能是void
  • 父類被重寫的方法的返回值類型是A類型,則子類重寫的方法的返回值類型能夠是A類或A類的子類
  • 父類被重寫的方法的返回值類型是基本數據類型(好比:double),則子類重寫的方法的返回值類型必須是相同的基本數據類型(必須也是double)
  1. 子類重寫的方法拋出的異常類型不大於父類被重寫的方法拋出的異常類型(具體放到異常處理時候講)

子類和父類中的同名同參數的方法要麼都聲明爲非static的(考慮重寫,要麼都聲明爲static的(不是重寫)。

開發中通常保持子父類一致

5.面試題:

區分方法的重寫和重載?

  1. 兩者的概念:
  • 方法的重寫:子類繼承父類之後,能夠對父類中同名同參數的方法,進行覆蓋操做.
  • 方法的重載:在同一個類中,容許存在一個以上的同名方法,只要它們的參數個數或者參數類型不一樣便可。
  1. 重載和重寫的具體規則:重載:兩同一不一樣,重寫
  2. 重載:不表現爲多態性。 重寫:表現爲多態性。
  3. 從編譯和運行的角度看:
  • 重載,是指容許存在多個同名方法,而這些方法的參數不一樣。編譯器根據方法不一樣的參數表,對同名方法的名稱作修飾。對於編譯器而言,這些同名方法就成了不一樣的方法。它們的調用地址在編譯期就綁定了。Java的重載是能夠包括父類和子類的,即子類能夠重載父類的同名不一樣參數的方法。
  • 因此:對於重載而言,在方法調用以前,編譯器就已經肯定了所要調用的方法,這稱爲「早綁定」或「靜態綁定」;
  • 而對於多態,只等到方法調用的那一刻,解釋運行器纔會肯定所要調用的具體方法,這稱爲「晚綁定」或「動態綁定」。

引用一句Bruce Eckel的話:「不要犯傻,若是它不是晚綁定,它就不是多態。」

類的結構之三:構造器

1. 構造器(或構造方法):Constructor

構造器的做用:(只要造對象就得用構造器)

  1. 建立對象

  2. 初始化對象的信息

2. 使用說明:

1.若是沒顯式的定義類的構造器的話,則系統默認提供一個空參的構造器

2.定義構造器的格式:權限修飾符 類名(形參列表){}

3.一個類中定義的多個構造器,彼此構成重載

4.一旦咱們顯式的定義了類的構造器以後,系統就再也不提供默認的空參構造器

5.一個類中,至少會有一個構造器

3. 舉例:

//構造器不等於方法
public Person(){
	System.out.println("Person().....");
}
	
public Person(String n){
	name = n;
		
}
	
public Person(String n,int a){
	name = n;
	age = a;
}

構造器默認權限和類的權限一致

屬性賦值順序

總結:屬性賦值的前後順序

① 默認初始化

② 顯式初始化

③ 構造器中初始化

④ 經過"對象.方法" 或 "對象.屬性"的方式,賦值

以上操做的前後順序:① - ② - ③ - ④

JavaBean的概念

所謂JavaBean,是指符合以下標準的Java類:

  • 類是公共的
  • 一個***無參***的公共的構造器
  • 屬性,且對應的get、set方法

類的結構之四:代碼塊

代碼塊(初始化塊)(重要性較屬性、方法、構造器差一些)

1. 代碼塊的做用:

用來初始化類、對象的信息

2. 分類:

代碼塊要是使用修飾符,只能使用static 分類:靜態代碼塊 vs 非靜態代碼塊

3. 靜態代碼塊 vs 非靜態代碼塊區別

靜態代碼塊:

  • 內部能夠輸出語句
  • 隨着類的加載而執行,並且只執行一次
  • 做用:初始化類的信息
  • 若是一個類中定義了多個靜態代碼塊,則按照聲明的前後順序執行
  • 靜態代碼塊的執行要優先於非靜態代碼塊的執行
  • 靜態代碼塊內只能調用靜態的屬性、靜態的方法,不能調用非靜態的結構

非靜態代碼塊:

  • 內部能夠輸出語句
  • 隨着對象的建立而執行
  • 每建立一個對象,就執行一次非靜態代碼塊
  • 做用:能夠在建立對象時,對對象的屬性等進行初始化
  • 若是一個類中定義了多個非靜態代碼塊,則按照聲明的前後順序執行
  • 非靜態代碼塊內能夠調用靜態的屬性、靜態的方法,或非靜態的屬性、非靜態的方法

注意:實例化子類對象時,涉及到父類、子類中靜態代碼塊、非靜態代碼塊、構造器的加載順序:由父及子,靜態先行。

舉例:

舉例一

class Root{
	static{
		System.out.println("Root的靜態初始化塊");
	}
	{
		System.out.println("Root的普通初始化塊");
	}
	public Root(){
		System.out.println("Root的無參數的構造器");
	}
}
class Mid extends Root{
	static{
		System.out.println("Mid的靜態初始化塊");
	}
	{
		System.out.println("Mid的普通初始化塊");
	}
	public Mid(){
		System.out.println("Mid的無參數的構造器");
	}
	public Mid(String msg){
		//經過this調用同一類中重載的構造器
		this();
		System.out.println("Mid的帶參數構造器,其參數值:"
			+ msg);
	}
}
class Leaf extends Mid{
	static{
		System.out.println("Leaf的靜態初始化塊");
	}
	{
		System.out.println("Leaf的普通初始化塊");
	}	
	public Leaf(){
		//經過super調用父類中有一個字符串參數的構造器
		super("調用父類構造器");
		System.out.println("Leaf的構造器");
	}
}
public class LeafTest{
	public static void main(String[] args){
		new Leaf(); 
		//new Leaf();
	}
}

舉例二

class Father {
	static {
		System.out.println("11111111111");
	}
	{
		System.out.println("22222222222");
	}

	public Father() {
		System.out.println("33333333333");

	}

}

public class Son extends Father {
	static {
		System.out.println("44444444444");
	}
	{
		System.out.println("55555555555");
	}
	public Son() {
		System.out.println("66666666666");
	}


	public static void main(String[] args) { // 由父及子 靜態先行
		System.out.println("77777777777");
		System.out.println("************************");
		new Son();
		System.out.println("************************");

		new Son();
		System.out.println("************************");
		new Father();
	}

}

屬性的賦值順序

①默認初始化

②顯式初始化/⑤在代碼塊中賦值

③構造器中初始化

④有了對象之後,能夠經過"對象.屬性"或"對象.方法"的方式,進行賦值

執行的前後順序:① - ② / ⑤ - ③ - ④

類的結構之五:內部類

類的第五個成員

1. 定義:

Java中容許將一個類A聲明在另外一個類B中,則類A就是內部類,類B稱爲外部類.

2. 內部類的分類:

成員內部類(靜態、非靜態 ) vs 局部內部類(方法內、代碼塊內、構造器內)

3. 成員內部類的理解:

一方面,做爲外部類的成員:

  • 調用外部類的結構
  • 能夠被static修飾
  • 能夠被4種不一樣的權限修飾

另外一方面,做爲一個類:

  • 類內能夠定義屬性、方法、構造器等

  • 能夠被final修飾,表示此類不能被繼承。言外之意,不使用final,就能夠被繼承

  • 能夠被abstract修飾

4. 成員內部類:

4.1如何建立成員內部類的對象?(靜態的,非靜態的)

//建立靜態的Dog內部類的實例(靜態的成員內部類):
Person.Dog dog = new Person.Dog();

//建立非靜態的Bird內部類的實例(非靜態的成員內部類):
//Person.Bird bird = new Person.Bird();//錯誤的
Person p = new Person();
Person.Bird bird = p.new Bird();

4.2如何在成員內部類中調用外部類的結構?

class Person{
	String name = "小明";
public void eat(){
}
//非靜態成員內部類
	class Bird{
		String name = "杜鵑";
		public void display(String name){
			System.out.println(name);//方法的形參
			System.out.println(this.name);//內部類的屬性
			System.out.println(Person.this.name);//外部類的屬性
		//Person.this.eat();
		}
	}
}

5.局部內部類的使用:

//返回一個實現了Comparable接口的類的對象
	public Comparable getComparable(){
		
		//建立一個實現了Comparable接口的類:局部內部類
		//方式一:
//		class MyComparable implements Comparable{
//
//			@Override
//			public int compareTo(Object o) {
//				return 0;
//			}
//			
//		}
//		
//		return new MyComparable();
		
		//方式二:
		return new Comparable(){

			@Override
			public int compareTo(Object o) {
				return 0;
			}
			
		};
		
	}

注意點: 在局部內部類的方法中(好比:show若是調用局部內部類所聲明的方法(好比:method)中的局部變量(好比:num)的話,要求此局部變量聲明爲final的。 緣由:局部內部類也會生成字節碼文件,在調用所屬類的局部變量時,由於是兩個類,因此不能修改所屬類的屬性,所以所屬類將屬性設置爲final的爲內部類調用提供一個副本,而內部類不能進行修改。 jdk 7及以前版本:要求此局部變量顯式的聲明爲final的 jdk 8及以後的版本:能夠省略final的聲明

總結:
成員內部類和局部內部類,在編譯之後,都會生成字節碼文件。
格式:成員內部類:外部類$內部類名.class
     局部內部類:外部類$數字 內部類名.class
相關文章
相關標籤/搜索