1. 程式人生 > >java學習筆記(5)

java學習筆記(5)

第五章 面向物件基礎

一、 題目

1. 什麼是物件?如何建立物件?

類是面嚮物件語言中最重用的一種資料型別,類宣告的變數稱為物件。
建立一個物件包括對物件的宣告和為宣告的物件分配記憶體兩個步驟
假設我們在函式中寫了如下這個簡單的語句:
StringBuffer str = new StringBuffer(”Hello world”);
  別看這個語句簡單,其實包含了如下三個步驟:
  首先,newStringBuffer(”Helloworld”)在堆裡申請了一堆記憶體,把建立好的StringBuffer物件放進去。
  其次,StringBufferstr聲明瞭一個指標。這個指標本身是儲存在棧上的(因為語句寫在函式中),可以用來指向某個StringBuffer型別的物件。或者換一種說法,這個指標可以用來儲存某個StringBuffer物件的地址。
  最後,當中這個等於號(賦值符號)把兩者關聯起來,也就是把剛申請的那一堆記憶體的地址儲存成str的值。

2. 什麼是構造方法?構造方法有哪些特點?

構造方法是一個類方法中方法名與類名相同的類方法,它的作用是當使用new關鍵字建立一個物件時,自動呼叫並對新建物件進行初始化操作。
構造方法的特點:
1) 構造方法與類名相同
2) 構造方法沒有返回值,不定義返回型別
3) 構造方法可以過載,針對引數數量和型別定義多個同名構造方法
4) 構造方法可以繼承,子類可以繼承父類的構造方法
5) 構造方法不能由程式設計人員顯式地直接呼叫,它是在物件建立時由new 運算子自動呼叫的
6) 構造方法只用來對類例項進行初始化,目的在於簡化初始化操作
7) 每個類都至少有一個構造方法,如果程式設計師沒有為類定義構造方法,系統會自動為該類生成一個預設的構造方法。
在Java中,物件的建立和初始化是統一的——兩者缺一不可。

3. 什麼是類的封裝?如何對成員變數和方法的訪問許可權的設定達到資料封裝的目的?

所謂封裝表現在以下幾個方面
1) 在類的定義中設定對物件中的成員變數和方法進行訪問的許可權。
2) 提供一個統一供其它類引用的方法。
3) 其它物件不能直接修改本物件所擁有的屬性和方法。
利用訪問控制符(public 、protected 、private、預設)分別宣告物件變數和方法的四種訪問許可權

4. 子類能夠繼承父類的哪些成員變數和方法?

Java只支援單重繼承。子類從父類繼承了屬性與方法,也可以自己構建父類沒有的屬性和方法。由於訪問控制符的限制,子類的繼承又分為兩種情況:
1) 子類和父類在同一個包中,此時子類自然地繼承了其父類中不是private的成員變數作為自己的成員變數,並且自然也繼承了父類中不是private的方法作為自己的方法,整合的成員變數或方法的訪問許可權保持不變。
2) 子類和父類不在同一個包中,此時子類只能繼承父類中的protected、public訪問控制符修飾的成員變數和方法。且此時子類不能繼承父類的友好變數和友好方法。
對於子類可以從父類繼承的成員變數,只要子類中定義的成員變數和父類中的成員變數同名時,子類就隱藏了繼承的成員變數。對於已繼承的方法,子類可以通過方法重寫來隱藏繼承的方法。

5. 編制程式,給定圓的半徑和高度,計算圓柱體的體積,利用引用物件方法的形式表示。

見xiti5_5.java

package xiti5;
import java.util.Scanner;

class cylinder{//圓柱類
double r=1,height=1,vol;//成員屬性
void cylinder() {//構造方法

}
void set_r(double rs){//成員方法
    r=rs;
}
void set_height(double h){
    height=h;
}
double volume(){
    vol=3.14*r*r*height;
    return vol;
}

}
public class xiti5_5 {
//編制程式,給定圓的半徑和高度,計算圓柱體的體積,利用引用物件方法的形式表示。
public static void main(String[] args) {
    // TODO Auto-generated method stub
    Scanner scanner = new Scanner(System.in);
    cylinder cyl=new cylinder();//物件的宣告與分配記憶體
    System.out.println("未修改時圓柱的體積為:"+cyl.volume());//呼叫方法
    cyl.set_r(10);
    cyl.set_height(10); 
    System.out.println("修改後圓柱的體積為:"+cyl.volume());
}
}

這裡寫圖片描述

6. 補充閱讀:

《面向物件分析與設計(第3版)》 Grady booch著
8. Design a class named Fan to represent a fan. The class contains:
Three constants named SLOW, MEDIUM, and FAST with values 1, 2, and 3 to
denote the fan speed.
A private int data field named speed that specifies the speed of the fan (default SLOW).
A private boolean data field named on that specifies whether the fan is on (default false).
A private double data field named radius that specifies the radius of the fan (default 5).
A string data field named color that specifies the color of the fan (default blue).
The accessor and mutator methods for all four data fields.
A no-arg constructor that creates a default fan.
A method named toString() that returns a string description for the fan.
If the fan is on, the method returns the fan speed, color, and radius in
one combined string. If the fan is not on, the method returns fan color
and radius along with the string “fan is off” in one combined string.
Implement the class. Write a test program that creates two Fan objects. Assign maximum speed, radius 10, color yellow, and turn it on to the first object. Assign medium speed, radius 5, color blue, and turn it off to the second object.
Display the objects by invoking their toString() method.

二、論述

隨著計算機硬體裝置功能的大發展,人們對於語言的應用與改進,使得面向物件的語言應運而生,它令人們可以編寫出易維護、易擴充套件和易複用的程式程式碼,會更加符合人們的思維習慣。Java便是一個純的面向物件的程式語言。
面向物件程式設計方法是:
物件 = (演算法 + 資料結構)
程式 = (物件 + 物件 + … )
演算法與資料結構是一個整體,演算法離不開資料結構,演算法只能適用於特定的資料結構。

1、面嚮物件語言的四大特徵:抽象、封裝、繼承、多型。

1.1、抽象:從具體的例項中抽取共同的性質形成一般的概念。

1.2、封裝:在面向物件程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式介面的實現細節部份包裝、隱藏起來的方法。

所謂封裝表現在以下幾個方面

在類的定義中設定對物件中的成員變數和方法進行訪問的許可權。
提供一個統一供其它類引用的方法。
其它物件不能直接修改本物件所擁有的屬性和方法。

其主要通過訪問控制符(public、 protected 、private 、預設)來實現,具體如下表:
這裡寫圖片描述

1.3、繼承:子類的物件擁有其父類的全部屬性與服務,稱作子類對父類的繼承。Java為單繼承機制。

類之間的繼承關係是現實世界中遺傳關係的直接模擬,它表示類之間的內在聯絡以及對屬性和操作的共享,即子類可以沿用父類(被繼承類)的某些特徵。子類也可以具有自己獨立的屬性和操作。

子類從父類繼承有兩個主要的方面:
(1)屬性的繼承。例如,公司是一個父類,一個公司有名稱、地址、經理、僱員等,這些都屬於結構方面。
(2)方法的繼承。一個父類定義了若干操作,如一個公司要有專案開發、利潤創造、經理任命、員工錄用等操作,子公司也將繼承這些行為。

子類的繼承又分為兩種情況:
1) 子類和父類在同一個包中,此時子類自然地繼承了其父類中不是private的成員變數作為自己的成員變數,並且自然也繼承了父類中不是private的方法作為自己的方法,整合的成員變數或方法的訪問許可權保持不變。
2) 子類和父類不在同一個包中,此時子類只能繼承父類中的protected、public訪問控制符修飾的成員變數和方法。且此時子類不能繼承父類的友好變數和友好方法。
對於子類可以從父類繼承的成員變數,只要子類中定義的成員變數和父類中的成員變數同名時,子類就隱藏了繼承的成員變數。對於已繼承的方法,子類可以通過方法重寫來隱藏繼承的方法。

特別是構造方法的繼承應遵守以下原則
1)子類可以無條件的繼承父類不含引數的構造方法
2)如果子類沒有構造方法,則它繼承父類無引數的構造方法作為自己的構造方法;如果子類有構造方法,那麼在建立子類物件時,則將先執行繼承下來的父類的構造方法,然後再執行自己的構造方法
3)對於父類中包含有引數的構造方法,子類可以通過在自己的構造方法中使用super關鍵字來引用,而且必須是子類構造方法中的第一條語句。

1.4、多型:

狹義定義:由於父類和子類可以有同名的方法,在執行時JVM根據方法的引數個數和型別的不同來查詢、決定執行哪個版本的方法,稱為多型性。
當然,這只是一種型別的多型,即操作的多型,過載(Overload),表現為有多個操作具有相同的名字,但這些操作所接收的訊息型別必須不同。還有一種多型性與繼承有關,即重寫(Overrride),是指同一個操作被不同型別物件呼叫時可能產生不同的行為。

2、類與物件

類封裝了一類物件的狀態和方法,是用來定義物件的模板。類宣告的變數稱為物件。當使用一個類建立一個物件時,也稱給出了這個類的一個例項。

2.1、類與物件的概念與建立

類定義的格式:
[ 類修飾符] class    類名
[ extends      父類名 ]
[ implements      介面名 ] {
    構造方法定義(可隱含);
    成員變數定義;
    方法定義;
}
其中構造方法是一個類方法中方法名與類名相同的類方法,它的作用是當使用new關鍵字建立一個物件時,自動呼叫並對新建物件進行初始化操作.


建立類物件一般形式:
類名   物件變數 = new  類名(引數1,引數2,…);
   或者
類名  物件變數;
物件變數 = new 類名(引數1,引數2,…);

建立一個物件包括對物件的宣告和為宣告的物件分配記憶體兩個步驟,

例項變數與類變數的區別在於,類變數(靜態變數:static修飾)是與類相關聯的資料變數,所有成員共用,其中一個成員改變其值就會影響到其他成員,類似於作業系統中的共享資源。例項變數僅僅是和相應的物件關聯的變數,不同物件的例項變數互不相同。另外,前者可以通過類名和物件訪問,後者僅能通過物件訪問。

變數型別基本有:
static: 靜態變數(類變數);相對於例項變數
final: 常量
transient: 暫時性變數,用於物件存檔,用於物件的序列化,見物件的序列化一節
volatile: 貢獻變數,用於併發執行緒的共享

◇ 方法宣告
方法宣告包括方法名、返回型別和外部引數。其中引數的型別可以是簡單資料型別,也可以是複合資料型別(又稱引用資料型別)。

2.2、引數傳值

這個有點暈乎,只曉得方法中引數變數的值是呼叫者指定值一個副本,方法中改變該值並不影響其原值,必須引入引用來改變原來的值。
對於簡單資料型別來說,java實現的是值傳遞,方法接收引數的值,但不能改變這些引數的值。如果要改變引數的值,則用引用資料型別,因為引用資料型別傳遞給方法的是資料在記憶體中的地址,方法中對資料的操作可以改變資料的值。
從大神那摘錄的:
1、物件是按引用傳遞的
2、Java 應用程式有且僅有的一種引數傳遞機制,即按值傳遞
3、按值傳遞意味著當將一個引數傳遞給一個函式時,函式接收的是原始值的一個副本
4、按引用傳遞意味著當將一個引數傳遞給一個函式時,函式接收的是原始值的記憶體地址,而不是值的副本寫的沒錯

對String型別的疑惑沒有解決。
三句話總結一下:
1.物件就是傳引用
2.原始型別就是傳值
3.String等immutable型別因為沒有提供自身修改的函式,每次操作都是新生成一個物件,所以要特殊對待。可以認為是傳值。

2.3、物件的組合

我們可以在一個新類的定義中使用其他物件。這就是組合(composition)。組合是在Java中實現程式復(reusibility)的基本手段之一。
類似於函式的巢狀,用某一物件作為自身物件的一個成員,即物件中巢狀一物件作為其成員。
詳情見大佬部落格:
java物件間的關係(依賴,關聯,組合,聚合)

3、關鍵字

3.1、static

static關鍵字可以用來宣告類變數和類方法(靜態方法)。與這兩者相對的分別是例項變數和例項方法。
(1)類變數和例項變數:類變數可以通過類名訪問,而且類宣告的物件共享類變數。
(2)類方法和例項方法:類方法可以通過類名訪問,而且類宣告的物件共享類方法。見圖片的例子:
這裡寫圖片描述

3.2、this、super

當在一個類中要明確指出使用物件自己的的變數或函式時就應該加上this引用。簡而言之,類似於多型的不同引數作為辨別標準,當例項成員變數的名字和區域性變數的名字相同時,必須加上this加以區分。this不可出現在類方法中,因為類方法可以通過類名直接呼叫,這時,可能還沒有任何物件產生。
1)當其出現在類的構造方法中時,代表使用該構造方法所建立的物件;
2)當出現在例項方法時,代表正在呼叫該方法的當前物件。
例如:

class A{
    int x;
    static int y;
    void f(){
        x=100;
        y=200;
    }
}//
其中A類的例項方法f中出現了this,this代表使用f的當前物件。所以,this.x表示當前物件的變數x,當變數呼叫方法f時,將100賦值給該變數x。

相應的,子類可以隱藏從父類繼承的成員變數和方法,如果在子類中想使用被子類隱藏的成員變數或方法,就可以使用關鍵字super。
1)使用super呼叫父類的構造方法,super必須是子類構造方法中的頭一條語句。
2)使用super操作被隱藏的成員變數和方法,被隱藏的方法分配的入口地址只對super可見。

這裡寫圖片描述

3.3、final

final可以修飾類、成員變數和方法中的區域性變數。
1)final類
final類不能被繼承,即不能有子類。
2)final方法
用final修飾父類中的一個方法,則該方法不允許子類重寫,即不允許子類隱藏可以繼承的final方法,常用來終止繼承。
3)常量
被final修飾的成員變數或區域性變數就是常量。常量在宣告時沒有預設值,所以在宣告常量時必須指定該常量的值,而且不能發生變化。