1. 程式人生 > 其它 >九.面向物件的思想(五)

九.面向物件的思想(五)

九.面向物件的思想(五)

1.程式碼塊

程式碼塊又稱為初始化塊,屬於類中的成員(即 是類的一部分),類似於方法,將邏輯語句封裝在方法體中,通過{}包圍起來。

但和方法不同,沒有方法名,沒有返回,沒有引數,只有方法體,而且不用通過物件或類的顯式呼叫,而是載入類時,或建立物件時隱 式呼叫。

程式碼塊語法

【修飾符】{

程式碼

};

說明注意:

1)修飾符可選,要寫的話,也只能寫static

2)程式碼塊分為兩類,使用static修飾的叫靜態程式碼塊,沒有static修飾的,叫普通程式碼塊/非靜態程式碼塊。

3)邏輯語句可以任何邏輯語句(輸入,輸出,方法呼叫,迴圈,判斷等)

4);號可以寫上,也可以忽略

程式碼塊的好處:

1)相當於另外一種形式的構造器(對構造器的補充機制),可以做初始化操作

2)場景:如果多個構造器中都有重複的語句,可以抽取到程式碼塊中,提高程式碼的重用性。

使用注意事項

1)static程式碼塊也叫靜態程式碼塊,作用就是對類進行初始化,而且它隨著類的載入而執行,並且只會執行一次。如果是普通程式碼塊,沒建立一個物件,就執行。

2)類什麼時候被載入

1.建立物件例項時

2.建立物件的子類物件例項,父類也會被載入

3.使用類的靜態成員時(靜態屬性,靜態方法)

3)普通的程式碼塊,在建立物件例項時,會被隱式的呼叫。

被建立以西,就會呼叫一次。

如果只是是喲了那個類的靜態成員時,普通程式碼塊並不會執行

建立一個子類物件時,他們的靜態程式碼塊,靜態程式碼塊,普通程式碼塊,普通屬性初始化,構造方法的呼叫順序

1.父類的靜態程式碼塊和靜態屬性(優先順序一樣,按定義順序執行)

2.子類的靜態程式碼塊和靜態屬性(優先順序一樣,定義順序執行)

3.父類的普通程式碼塊和普通屬性初始化(優先順序一樣,按定義順序執行)

4.父類的構造方法

5.子列的普通程式碼塊和普通屬性初始化(優先順序一樣,按定義順序執行)

5.子類的構造方法

2.單例設計模式

1.單例設計模式,就是採取一定的方法保證整個的軟體系統中,對某個類只能存在一個物件的例項,並且該列只提供一個取得其物件例項的方法

2.單例設計模式有兩種方式:1)餓漢式 2)懶漢式

單例設計模式的兩種實現方式:
一、懶漢式:隨著類的載入在記憶體中物件為null,當呼叫 getInstance 方法時才建立物件(延遲載入)
二、餓漢式:隨著類的載入直接建立物件(推薦開發中使用)
單例設計模式的實現步驟:
1.保證一個類只有一個例項,實現方式:構造方法私有化
2.必須要自己建立這個例項,實現方式:在本類中維護一個本類物件(私有,靜態)
3.必須向整個程式提供這個例項,實現方式:對外提供公共的訪問方式(getInstance方法,靜態)
懶漢式實現如下:
class Single{
private Single(){}
private static Single s1 = null;
public static Single getInstance(){
if(s1 == null){
s1 = new Single();
}
return s1;
}
}
餓漢式實現如下:
class Single2{
private Single2(){}
private static Single2 s = new Single2();
public static Single getInstance(){
return s;
}
}

餓漢式和懶漢式的區別

1).二者最主要的區別子啊與建立物件的時機不同:餓漢式是在類載入就建立了物件例項,而懶漢式是在使用時才建立。

2)餓漢式不存線上程安全問題,懶漢式竄線上程安全問題。

3)餓漢式存在浪費資源的可能,懶漢式是使用才建立,就不存在這個問題。

3.final關鍵字

final可以修飾類,屬性,方法和區域性變數。

使用情況

在某些情況下,程式設計師可能有以下需求,就會使用到final:

1)當不希望類被繼承時,可以使用final修飾。

2)當不希望父類的某個方法被子類覆蓋/重寫(override)時,可以用final關鍵字修飾。

3)當不希望類的某個屬性的值被修改時,可以用final關鍵字修飾。

4)當不希望某個區域性變數被修改,可以使用final修飾。

final使用的注意事項

1)final修飾的屬性又叫常量,一般用大寫字母和下劃線來命名

2)final修飾的屬性在定義是,必須賦初始值,並且以後不能再修改,賦值可以在以下位置之一:

1.定義是:如public final double TAX_RATE=0.08;

2.在構造器中

3.在程式碼塊中

3)如果final修飾的屬性是靜態的,則初始化的位置只能是

1.定義時

2.在靜態程式碼塊中,不能在構造器中賦值。

4)final類不能繼承,但是可以例項化物件

5)如果類不是final類,但是含有final方法,則該方法雖然不能重寫,但是可以被繼承。

6)一般來說,如果一個類已經是final類了,就沒有比喻哦啊再將方法修飾成finall

7)final和static往往搭配使用,效率更高,不會導致類載入底層編譯器做了優化處理。

8)包裝類(Integer,Double,Float,Boolean等都是final),String也是final類。

4.抽象類

當父類的某些方法,需要宣告,但是又不能確定如何實現時,可以將其宣告為抽象方法,那麼這個類就是抽象類

public class Abstract01 {
public static void main(String[] args) {
}
}

abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
//思考:這裡 eat 這裡你實現了,其實沒有什麼意義
//即: 父類方法不確定性的問題
//===> 考慮將該方法設計為抽象(abstract)方法
//===> 所謂抽象方法就是沒有實現的方法
//===> 所謂沒有實現就是指,沒有方法體
//===> 當一個類中存在抽象方法時,需要將該類宣告為 abstract 類
//===> 一般來說,抽象類會被繼承,有其子類來實現抽象方法. // public void eat() {
// System.out.println("這是一個動物,但是不知道吃什麼..");
// }
public abstract void eat() ;
}
抽象類的介紹

1)用abstract關鍵字來修飾一個類時,這個類就叫抽象類

訪問修飾符 abstract 類名{

}

2)用abstract關鍵字來修飾一個方法時,這個方法就是抽象方法

訪問修飾符 abstract 返回型別 方法名(引數列表);//沒有方法體

3)抽象類的價值更多作用在於設計,是設計者設計好後,讓子類繼承並實現抽象類()

抽象類的使用注意事項

1)抽象類不能被例項化

2)抽象類不一定要包括abstract方法。也就是說,抽象類可以沒有abstarct方法

3)一旦類包含了abstract方法,則這個類必須宣告為abstract

4)abstract只能修飾類和方法,不能修飾屬性和其他的。

5)抽象類可以有任意成員【抽象類本質還是類】,比如:非抽象方法,構造器,靜態屬性等等

6)抽象方法不能有主體,即不能實現。

7)如果一個類繼承了抽象類,則它必須實現抽象類的所有抽象方法,除非它自己也宣告為abstract類。

8)抽象方法不能使用private,final和static來修飾,因為這些關鍵字都是和重寫相違背的。

5.介面

基本介紹

介面解釋給出一些沒有實現的方法,封裝到一起,到某個類要使用的時候,在根據具體情況把這些方法寫出來。

語法:

interface 介面名{

//屬性

//抽象方法

}

class 類名 implements 介面 {

自己的屬性;

自己的方法;

必須實現的介面的抽象方法

}

介面是更加抽象的類,抽象類裡的方法可以有方法體,接口裡的所有方法都沒有方法體。介面體現了程式的多型和高內聚低耦合的設計思想。

public interface DBInterface { //專案經理
public void connect();//連線方法
public void close();//關閉連線
}


//A 程式
public class MysqlDB implements DBInterface {
@Override
public void connect() {
System.out.println("連線 mysql")
}
@Override
public void close() {
System.out.println("關閉 mysql");
}
}


//B 程式設計師連線 Oracle
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("連線 oracle");
}
@Override
public void close() {
System.out.println("關閉 oracle");
}
}


public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBInterface db) {
db.connect();
db.close();
}
}
介面使用的注意事項:

1)介面不能被例項化

2)介面中所有的方法是public方法,介面中抽象方法,可以不用abstract修飾;

3)一個普通類實現介面,就必須將該介面的所有方法都實現。

4)抽象類實現介面,可以不用實現介面的方法。

5)一個類同時可以實現多個介面

6)介面中的屬性,只能是final的,而且是public static final修飾符。

7)介面中屬性的訪問形式:介面名.屬性名

8)介面不能繼承其他的類,但可以繼承多個別的介面

interface A extends B,C{}

9)介面的修飾符只能是public和預設,這點和類的修飾符是一樣的。

6.內部類

如果定義類在區域性位置(方法或程式碼塊):(1)區域性內部類 (2)匿名內部類

定義在成員位置:(1)成員內部類 (2)靜態內部類

基本介紹:

一個類的內部又完整的嵌套了另一個類的結構。被巢狀的類稱為內部類,巢狀其他類的類稱為外部類。是我們類的第五大成員【類的五大成員:屬性,方法,構造器,程式碼塊,內部類】,內部類最大的特點解釋可以直接訪問私有屬性,並且可以體現類與類之間的包含關係。

基本語法:
class Outer{ //外部類
class Inner{ //內部類
}
}
class Other{ //外部其他類
}
內部類的分類

定義在外部類區域性位置上(比如方法內):

1)區域性內部類(有類名)

2)匿名內部類(沒有類名)

定義在外部類的成員位置上

1)成員內部類(沒用static修飾)

2)靜態內部類(使用static修飾)

區域性內部類

區域性內部類是定義在外部類的區域性位置,比如方法中,並且有類名。

1.可以直接訪問外部類的所有成員,包括私有的。

2.不能新增訪問修飾符,因為它的地位就是一個區域性變數。區域性變數是不能使用修飾符的。但是可以使用final修飾,因為區域性變數也可以使用final

3.作用域:僅僅是在定義它的方法或程式碼塊中。

4.外部類訪問區域性內部類的成員需要在作用域內,建立物件再訪問。

5.如果外部類和區域性內部類的成員重名時,預設遵循就近原則,如果想訪問外部類的成員,則可以使用(外部類名.this.成員)去訪問。

public class LocalInnerClass {//
public static void main(String[] args) {
//演示一遍
Outer02 outer02 = new Outer02();
outer02.m1();
System.out.println("outer02 的 hashcode=" + outer02);
}
}
class Outer02 {//外部類
private int n1 = 100;
private void m2() {
System.out.println("Outer02 m2()");
}//私有方法
public void m1() {//方法
//1.區域性內部類是定義在外部類的區域性位置,通常在方法
//3.不能新增訪問修飾符,但是可以使用 final 修飾
//4.作用域 : 僅僅在定義它的方法或程式碼塊中
final class Inner02 {//區域性內部類(本質仍然是一個類)
//2.可以直接訪問外部類的所有成員,包含私有的
private int n1 = 800;
public void f1() {
//5. 區域性內部類可以直接訪問外部類的成員,比如下面 外部類 n1 和 m2()
//7. 如果外部類和區域性內部類的成員重名時,預設遵循就近原則,如果想訪問外部類的成員,
// 使用 外部類名.this.成員)去訪問
// Outer02.this 本質就是外部類的物件, 即哪個物件呼叫了 m1, Outer02.this 就是哪個物件
System.out.println("n1=" + n1 + " 外部類的 n1=" + Outer02.this.n1);
System.out.println("Outer02.this hashcode=" + Outer02.this);
m2();
}
}
//6. 外部類在方法中,可以建立 Inner02 物件,然後呼叫方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
匿名內部類:

(1)本質是類 (2)內部類(3)該類沒有名字(4)同時還是一個物件

說明:匿名內部類是定義在外部類的區域性位置,比如方法中,並且沒有類名

基本語法:

new 類或介面(引數列表){

類體

};

/**
* 演示匿名內部類的使用
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部類
private int n1 = 10;//屬性
public void method() {//方法
//基於介面的匿名內部類
//老韓解讀
//1.需求: 想使用 IA 介面,並建立物件
//2.傳統方式,是寫一個類,實現該介面,並建立物件
//3.需求是 Tiger/Dog 類只是使用一次,後面再不使用
//4. 可以使用匿名內部類來簡化開發
//5. tiger 的編譯型別 ? IA
//6. tiger 的執行型別 ? 就是匿名內部類 Outer04$1
/*
我們看底層 會分配 類名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫喚...");
}
}
*/
//7. jdk 底層在建立匿名內部類 Outer04$1,立即馬上就建立了 Outer04$1 例項,並且把地址
// 返回給 tiger
//8. 匿名內部類使用一次,就不能再使用
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫喚...");
}
};
System.out.println("tiger 的執行型別=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry();
// IA tiger = new Tiger();
// tiger.cry();
//演示基於類的匿名內部類
//分析
//1. father 編譯型別 Father
//2. father 執行型別 Outer04$2
//3. 底層會建立匿名內部類
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名內部類重寫了 test 方法");
}
}
*/
//4. 同時也直接返回了 匿名內部類 Outer04$2 的物件
//5. 注意("jack") 引數列表會傳遞給 構造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名內部類重寫了 test 方法");
}
};
System.out.println("father 物件的執行型別=" + father.getClass());//Outer04$2
father.test();
//基於抽象類的匿名內部類
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨頭...");
}
};
animal.eat();
}
}
interface IA {//介面
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫喚...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//類
public Father(String name) {//構造器
System.out.println("接收到 name=" + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象類
abstract void eat();
}
成員內部類

成員內部類是定義在外部類的成員位置,並且沒有static修飾。

public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他類,使用成員內部類的三種方式
// 第一種方式
// outer08.new Inner08(); 相當於把 new Inner08()當做是 outer08 成員
// 這就是一個語法,不要特別的糾結.
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
// 第二方式 在外部類中,編寫一個方法,可以返回 Inner08 物件
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08 { //外部類
private int n1 = 10;
public String name = "張三";
private void hi() {
System.out.println("hi()方法...");
}
//1.注意: 成員內部類,是定義在外部內的成員位置上
//2.可以新增任意訪問修飾符(public、protected 、預設、private),因為它的地位就是一個成員
public class Inner08 {//成員內部類
private double sal = 99.8;
private int n1 = 66;
public void say() {
//可以直接訪問外部類的所有成員,包含私有的
//如果成員內部類的成員和外部類的成員重名,會遵守就近原則. //,可以通過 外部類名.this.屬性 來訪問外部類的成員
System.out.println("n1 = " + n1 + " name = " + name + " 外部類的 n1=" + Outer08.this.n1);
hi();
}
}
//方法,返回一個 Inner08 例項
public Inner08 getInner08Instance(){
return new Inner08();
}
//寫方法
public void t1() {
//使用成員內部類
//建立成員內部類的物件,然後使用相關的方法
Inner08 inner08 = new Inner08();
inner08.say();
System.out.println(inner08.sal);
}
}

靜態內部類

靜態內部類是定義在外部類的所有成員位置,並且有static修飾

public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他類 使用靜態內部類
//方式 1
//因為靜態內部類,是可以通過類名直接訪問(前提是滿足訪問許可權)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
//方式 2
//編寫一個方法,可以返回靜態內部類的物件例項. Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("============");
inner101.say();
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println("************");
inner10_.say();
}
}
class Outer10 { //外部類
private int n1 = 10;
private static String name = "張三";
private static void cry() {}
//Inner10 就是靜態內部類
//1. 放在外部類的成員位置
//2. 使用 static 修飾
//3. 可以直接訪問外部類的所有靜態成員,包含私有的,但不能直接訪問非靜態成員
//4. 可以新增任意訪問修飾符(public、protected 、預設、private),因為它的地位就是一個成員
//5. 作用域 :同其他的成員,為整個
static class Inner10 {
private static String name = "aaa";
public void say() {
//如果外部類和靜態內部類的成員重名時,靜態內部類訪問的時,
//預設遵循就近原則,如果想訪問外部類的成員,則可以使用 (外部類名.成員)
System.out.println(name + " 外部類 name= " + Outer10.name);
cry();
}
}
public void m1() { //外部類---訪問------>靜態內部類 訪問方式:建立物件,再訪問
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
public static Inner10 getInner10_() {
return new Inner10();
}
}