1. 程式人生 > 其它 >JAVA 面向物件·基礎語法3

JAVA 面向物件·基礎語法3

學過c++的同學肯定都知道PC暫存器,它其實就是指令地址,和組合語言中的IP暫存器差不多。

PC暫存器:儲存JAVA虛擬機器正在執行的位元組碼指令(.class檔案)的地址。

JAVA虛擬機器棧:儲存棧幀

堆:儲存GC(垃圾回收器)所管理的各種物件(一個程式中new出來的所有物件)。

方法區:儲存每一個類的結構資訊(比如構造方法和普通方法)。

this:是一個指向當前物件的引用。

*********this的本質是一個隱藏的 位置最靠前的方法引數。(隱藏引數)

*********只能在構造方法中使用this去引用其他構造方法。

包的本質其實就是資料夾。

在JAVA中,任何新建的類都會預設為繼承JAVA的基類—Object(它的包名為 Java.lang.object)。

子類的構造方法必須先呼叫父類的構造方法,在執行後面的程式碼。

方法簽名=方法名+引數型別

重寫與過載——Super

在JAVA 中,重寫需要注意以下幾個方面:

1.子類的返回型別一定要小於或等於父類的的返回型別

Super:訪問父類中定義的成員變數,可以呼叫父類中定義的方法(包括構造方法)。

******************JAVA 的硬性規定:子類的構造方法必須先呼叫父類的構造方法,再執行後面的程式碼。

Java中的覆蓋指的是例項方法。

封裝

1.成員變數private化,提供public的setter,getter

Static類

1.被static修飾:成員變數,類變數,靜態變數,靜態欄位

(在程式執行的過程中,只佔用一份固定的記憶體,一般儲存在方法區)

2.沒有被static修飾:例項變數

(每個例項內部都有一份記憶體,儲存在堆空間)

3.被static修飾的方法:類方法,靜態方法

—方法內部是不可以使用this關鍵字的

—可以直接訪問類變數,類方法

—不可以直接使用例項變數,例項方法

—可以通過例項,類訪問

4.沒有被static修飾的方法:例項方法(只能通過例項呼叫,不能通過類名呼叫)

*************(例項內部必有this)

初始化塊·靜態初始化塊

每建立一次例項時,初始化塊就會去執行一次,而靜態初始化塊與例項是不掛鉤的

*******************手動為例項變數賦上初始值:

1.在宣告中

2.在構造方法中

3.在初始化塊中

public class Person{
     public int age;
     //初始化塊
     {
         age = 10;
     }
}

//編譯器會將初始化塊複製到每個構造方法的頭部(每建立一個例項物件,就會執行一次程式碼塊)

*******************手動為類變數賦上初始值:

1.在聲名中

2.在靜態初始化塊中

public class Person{
    public static int count;
    //靜態初始化塊
    static{
        count = 10;
    }
}

//當一個類被第一次主動使用時,JVM會自動對類進行初始化

//當一個類被進行初始化時會執行靜態初始程式碼塊

以上程式碼執行結果如圖

一段程式碼中可以有多個初始化塊和靜態初始化塊,按照在原始碼中出現的順序被執行

單例模式

構造一個單例模式(餓漢式單例模式):

public class Rocket{
    //私有的靜態的例項變數
    private static Rocket instance = new Rocket();
    //首先不能讓外界訪問你的構造方法,即構造方法私有化(就不能隨便去建立物件)
    private Rocket() {
    //其次 提供一個公共的靜態的方法,返回唯一的那個例項
        public static Rocket getInstance(){
            return instance;
        }
    }
}

構造一個單例模式(懶漢式單例模式):

public class Rocket{
	private static Rocket instance = null;
	private Rocket() {
		if(instance==null){
			instance = new Rocket();
		}
		return instance;
	}
}

//有執行緒安全問題

Final類

子類物件的內部不僅有自己的成員變數,還有父類的所有成員變數。

被final修飾的類:不能被繼承。

被final修飾的方法:不能被重寫。

被final修飾的變數:只能進行1次賦值。

凡是static final修飾的變數都採用大寫字母,若有多個單詞中間需用下劃線連線。

被static final修飾的可以看作一個常量。//也叫做編譯時常量(compile—time constant)。

//巨集替換:

巨集

1.預處理:主要任務包括刪除註釋、插入被#include進來的檔案內容、定義和替換由#define 定義的符號以及確定程式碼部分內容是否根據條件編譯(#if )來進行編譯。

2.巨集定義:⑴巨集常量:用#define來定義一個符號常量

​ ⑵巨集語句:定義一條或多條語句

​ ⑶巨集函式:用巨集來定義函式,因為巨集定義也可以帶引數

​ ⑷其他:#undef 是用來撤銷巨集定義的

靜態匯入

用一段程式碼實現靜態匯入:

import static com.mj.other.Test.*;

經典使用場景:圓周率PI的使用。

import static java.lang.Math.PI;
//import static java.lang.Math.*;
public class Main{
    public static void main(String args[]){
        //max(a,b);
        System.out.println(" 2 * PI * 10");
    }
}

但是過度使用靜態匯入,會產生歧義,讓讀者不明白這些到底是在哪個類中定義的。

巢狀類 Nested Class

巢狀類:定義在另一個類中的類,分為靜態巢狀類(被static修飾)和非靜態巢狀類(沒有static修飾)。//***非靜態巢狀類也叫內部類

外部類:在巢狀類外層的類。

頂級類:最外層的外部類。

內部類:跟例項變數,例項方法一樣,內部類與外部類的例項相關聯。

​ 必須先建立外部類例項,在呼叫外部類例項去建立內部類例項。(記得導包)

​ 如下圖 內部類不可以定義任何static成員。(除非是編譯時常量——即被static final修飾)

​ 內部類可以直接訪問外部類中的所有成員,即使該成員被聲名為private。

​ 外部類可以直接訪問內部類的任何成員變數和方法,即使該成員被聲名為private。

package www;
//內部類舉例(公司名字,公司解僱,員工名字,序號,顯示員工資訊)
public class Company {
	private String name;
	public Company(String name) {
		this.name =name;
	}
	public void Fire(Employee e) {
		System.out.println(name+"fire"+e.number);
	}
	public class Employee{
		private int number;
		public Employee(int number) {
			this.number = number;
		}
		public void show() {
			System.out.println(name+":"+number);
		}
	}
}

內部類細節:當外部類和內部類中都出現了相同的變數名,若想在內部類中呼叫外部類的那個變數,應表示為:

public class OuterClass{
    private int x = 1;
	class InnerClass{
		private int x = 2;
		System.out.println(OterClass.this.x);
	}
}

靜態巢狀類 Static Nested Class

靜態巢狀類:在行為上相當於頂級類,只是定義的程式碼寫到了另一個類中。(可以理解為:借另一個類的的空間去放一下程式碼)

(與一般頂級類相比)靜態巢狀類的特殊許可權:可以直接訪問外部類裡除了例項變數和例項方法的其他成員,即使該成員被聲名為private。

*************若靜態巢狀類想要訪問外部類中的例項變數和例項方法,則必須先要new一個物件,通過物件呼叫例項變數和方法。

什麼情況下使用巢狀類?

1.如果類A只用在類C內部,可以考慮將類A巢狀在類C內部。

2.封裝性更好,程式包更加簡化

3.增強可讀性,維護性

4.如果類A經常訪問類C中的非公共成員,可以考慮將類A巢狀在類C內部。

5.也可以根據需要將類A隱藏起來,不對外暴露

6.如果類A要經常訪問類C中的非公共的例項成員,則設計成內部巢狀類,否則設計為靜態巢狀類。

7.如果只有例項A才能建立例項C,那麼可以把C作為A的一個內部類來使用

區域性類 Local Class

區域性類:定義在程式碼塊中的類(可定義在方法中,for迴圈中,if語句中)。

1.區域性類不能定義除了編譯時常量以外的任何static成員

2.區域性類只能訪問 final類或者 有效final類 (只進行一次賦值)的區域性變數

3.從Java 8 開始,凡是沒有進行第二次賦值的區域性變數就被稱為 有效final 。

4.區域性類可以直接訪問外部類中的所有成員,即使該成員被聲名為private。

5.區域性類只有定義在例項相關的程式碼塊中,才能直接訪問外部類中的例項成員(例項變數,方法)

抽象類

1.抽象方法

抽象方法:被abstract修飾的方法。

注意事項:1.只有方法宣告,沒有方法實現(引數列表後沒有大括號,而是分號)

​ 2.不能是private許可權(因為定義抽象方法的目的是讓子類去實現)

​ 3.*************只能是例項方法,不能是類方法

​ 4.只能定義在抽象類和介面中

抽象類:

1.是為了給別人繼承的,所以不能使用final 修飾,也不能例項化,子類必須實現抽象父類中的所有的構造方法

**********************抽象類不能建立例項物件

2.抽象類其實可以理解為在原來的普通類基礎上增加了一個新的功能——構造抽象方法

介面 Interface

API:應用程式設計介面,提供給開發者一組呼叫的功能。

而Java中的介面,是一系列方法宣告的集合。(抽象方法)

implements 是類使用介面時的關鍵字。

介面可以定義抽象方法,常量,巢狀型別,預設方法,靜態方法

上述可以定義的內容都含有隱式public,所以在寫此段程式碼時可以省略不寫

介面中的常量可以省去static final ,介面中是不能出現成員變數的。

介面中不能自定義構造方法,不能例項化,不能定義(靜態)程式碼塊。

介面名稱可以在任何使用型別的地方使用,可以理解為介面也是一種型別。如果一個類實現的多個介面中有相同的抽象方法,那麼只需要實現此方法一次。

介面一般是放一些行為,能力的程式碼塊,而繼承是代表你屬於哪一類

在接口裡寫的方法都是抽象方法.

抽象類與介面的對比

抽象類

1.繼承:

class  A  extendS  D{}//A是D

2.何時選擇抽象類?

⑴在緊密相關的類之間共享程式碼

⑵除public以外的訪問許可權

⑶需要建立例項變數和非final類的靜態變數

介面:

1.實現:

A  implements  D{              //A會D中的所有行為
    
}

2.何時選擇介面?

⑴不相關的類實現相同的方法

⑵只是定義行為,不關心是誰具體實現了這個行為

⑶想實現型別的多重繼承

介面的升級問題

預設方法

1.用default修飾預設方法,並且此方法能夠具體實現

2.預設方法只能是例項方法

3.重新宣告預設方法,將預設方法宣告為抽象方法(此類必須是抽象類)

4.如果父類的非抽象方法與介面的預設方法相同時,最終呼叫父類的方法

5.可以通過super關鍵字來呼叫介面的預設方法(……忘了……{{{(>_<)}}})

靜態方法

1.介面中的定義的靜態方法只能通過介面名呼叫,不能被繼承

使用介面的好處

客戶端→伺服器→業務解析→業務層→DAO層

1.業務層呼叫DAO層 最好通過介面去呼叫。

2.涉及到了一些架構相關的問題,具體內容會在第二、三部分進行講解。

多型

多型:具有多種形態。(開發中經常會用到介面,也可以叫做 面向介面程式設計)

體現:

1.父類(介面)型別指向子類物件

2.呼叫子類重寫的方法

虛方法呼叫:JVM會根據引用變數指向的具體物件來呼叫相應的方法。(相當於c++虛擬函式呼叫)

Instanceof : 可以通過instanceof來判斷某個型別是否屬於某種型別。(非常常用

父類型別指向子類物件,這個順序是絕對不能顛倒的。

((Dog)Animal).wang();//強制轉換,將animal類轉化為Dog類
Dog dog1 = new Dog();
dog1.run();   //Dog-run

Animal dog2 = new Dog();
dog2.run();   //Animal-run

以上屬於類方法(靜態方法)呼叫,類方法是不看具體的例項物件的,只看物件屬於哪一類。

成員變數的訪問細節:

和類方法呼叫相似,在訪問成員變數之前,也只會看物件屬於所在的類,根據就近原則來進行下一步操作。

所以這樣會為程式帶來歧義,最好是將類中的public許可權變成private。

匿名類(常用)

當介面,抽象類的實現類,只在專案中出現過一次,可以考慮使用匿名類.

public class Main{
   public static void main(String args[]){
			Runnable person = new  Runnable() {          //匿名類
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					System.out.println("person-run");
				}
			};
			person.run();
	
   }
}  			

匿名類不能定義除編譯時常量以外的任何static成員.

匿名類不可以定義構造方法。

匿名類其實和區域性類十分相似,只能訪問final或者 有效final的區域性變數.

舉個例子(如下圖)

public interface Eatable {
      String name() ;    //相當於抽象方法,所以格式不能出錯
      int enery() ;
}

public class Person  {
	public void eat(Eatable e) {
		System.out.println("person-"+e.name()+"-"+e.enery());
	}
}
public static void main(String args[]){
			Person person = new Person();
			person.eat(new Eatable() {
				
				@Override
				public String name() {
					return "apple";
				}
				
				@Override
				public int enery() {
					return 50;
				}
			});
   }
}  			                                        //person-apple-50
或
public static void main(String args[]){
			Person person = new Person();
			Eatable beef = new Eatable() {
				
				@Override
				public String name() {
					// TODO Auto-generated method stub
					return "beef";
				}
				
				@Override
				public int enery() {
					// TODO Auto-generated method stub
					return 500;
				}
			};
			person.eat(beef);
}  			
}                                                //person-beef-500

匿名類的常見用途

1.程式碼傳遞:可以節省很多空間,不需要再去建立一個新的類。

舉個例子,測試一段程式碼所用的時間


2.過濾器

3.回撥:callback,其實與程式碼傳遞相類似。

匿名類的排序

1.java的自動排序(升序)

Arrays.sort(a);

2.Java的倒序排序

Arrays.sort(a,new comparator<Integer>()){
	@Override
	public int compare(Integer o1, Integer o2){   //這裡不能直接寫int,不然就會報錯
		return o2-o1;
	}
});

原理如下:

3.列印陣列

System.out.println(Arrays.toString(a));//括號中填陣列名

Lambda Expression

1.函式式介面:只包含一個抽象方法的介面。

可以在上面加上一個註解,表明它是一個函式式介面。

@FunctionalInterface
public interface Testable{
	void test(int b);
}

當匿名類實現的是函式式介面時,可以使用Lambda進行簡化。(相當於是用Lambda替換掉匿名類)

Lambda 的使用格式:

(引數列表) -> {

	return XXXX;
}

Lambda的使用注意:

1.Lambda只能訪問final或者有效final的區域性變數。

2.Lambda沒有引入新的作用域

匿名類與Lambda的對比

1.在作用域方面是有所區別的

方法引用

1.引用類方法

類名::方法名

2.引用特定物件的例項方法

system.out.println 的本質就是引用特定物件的例項方法。

也可以簡化為 具體的物件::呼叫的方法名

3.引用特定型別的任意物件的例項方法

本來字串底層就有compare方法,呼叫它可以比較大小

忽略大小寫進行比較

也可以將上述程式碼簡化成下面這種形式

所以引用特定型別的任意物件的例項方法是 類名::方法名

4.引用構造方法

所以引用構造方法的格式為 類名::new

5.引用陣列的構造方法

格式為 int[ ] :: new ;

6.引用當前類中定義的例項方法

格式為 this::方法名

7.引用父類中定義的例項方法

格式為 super::方法名

方法引用的最後總結: