Java 面向對象1 類 對象 方法 變量 封裝

類和對象

定義類

面向對象的程序設計過程當中有兩個重要概念:類(class)和對象(object,也被稱爲實例,instance),其中類是某一批對象的抽象,能夠把類理解成某種概念;對象纔是一個具體存在的實體。java

[修飾符]    class    類名
{
    零個到多個構造器定義...
    零個到多個成員變量...
    零個到多個方法...
}

修飾符能夠是public、final、abstract或者徹底忽略。程序員

若是從程序的可讀性方面來看,Java類名必須由一個或多個有意義的單詞連綴而成的,每一個單詞首字母大寫,其餘字母所有小寫,單詞與單詞之間不要使用任何分隔符。sql

構造器是一個類建立對象的根本途徑,若是一個類沒有構造器,這個類一般沒法建立實例。若是程序員沒有爲一個類編寫構造器,則系統會爲該類提供一個默認的構造器。一旦程序員爲一個類提供了構造器,系統將再也不爲該類提供構造器。數據庫

定義成員變量

static修飾的成員不能訪問沒有static修飾的成員。編程

成員變量用於定義該類或該類的實例所包含的狀態數據,方法則用於定義該類或該類的實例的行爲特徵或者功能實現。構造器用於構造該類的實例,Java語言經過new關鍵字來調用構造器,從而返回該類的實例。數組

[修飾符]    類型    成員變量名 [=默認值]

修飾符:public、protected、private三個最多隻能出現其中之一,能夠與static、final組合起來修飾成員變量。安全

類型:基本類型和引用類型網絡

成員變量名:若是從程序的可讀性方面來看,Java類名必須由一個或多個有意義的單詞連綴而成的,第一個單詞首字母小寫,後面每一個單詞首字母大寫,其餘字母所有小寫,單詞與單詞之間不要使用任何分隔符。框架

默認值:定義成員變量還能夠指定一個可選的默認值。工具

定義方法

[修飾符]    方法返回值類型    方法名(形參列表)
{
    //由零條到多條可執行性語句組成的方法體
}

修飾符:public、protected、private三個最多隻能出現其中之一,能夠與static、final組合起來修飾成員變量。

方法返回值類型:基本類型和引用類型若是聲明瞭方法返回值類型,則方法體內必須與此處聲明的類型匹配。若是一個方法沒有返回值,則必須使用void來聲明沒有返回值。

形參列表:形參列表用於定義該方法能夠接受的參數,形參列表由零組到多組「參數類型 形參名」組合而成,多組參數之間以英文逗號(,)隔開,形參類型和形參名之間以英文空格隔開。

static

static是一個特殊的關鍵字,可用於修飾方法、成員變量等成員。static修飾的成員代表它屬於這個類自己,而不屬於該類的單個實例,由於一般把static修飾的成員變量和方法也稱爲類變量、類方法。不使用static修飾的普通方法、成員變量則屬於該類的單個實例,而不屬於該類。由於一般把不使用static修飾的成員變量和方法也稱爲實例變量、實例方法。

static修飾的成員變量和方法稱爲靜態變量和靜態方法,把不使用static修飾的成員變量和方法稱爲非靜態變量和非靜態方法。靜態方法不能直接訪問非靜態成員。

有static修飾的成員屬於類自己,沒有static修飾的成員屬於該類的實例。

構造器

構造器是一個特殊的方法,定義構造器的語法格式與定義方法的語法格式很像,定義構造器的語法格式以下:

[修飾符]    構造器名(形參列表)
{
    //由零條到多條可執行性語句組成的構造器執行體
}

修飾符:public、protected、private
構造器名:構造器名必須和類同名
形參列表:和定義方法形參列表的格式徹底相同。
構造器既不能定義返回值類型,也不能使用void聲明構造器沒有返回值。

對象的產生和使用

static修飾的方法和成員變量,既可經過類來調用,也可經過實例來調用;沒有使用static修飾的普通方法和成員變量,只可經過實例來調用。

對象、引用和指針

變量實例其實是一個引用,它被存放在棧內存裏,指向實際的類對象;而真正的類對象則存放在堆內存中。棧內存裏的引用變量並未真正存儲對象的成員變量,對象的成員變量數據實際存放在堆內存裏;而引用變量只是指向該堆內存裏的對象。

對象的this引用

this關鍵字老是指向調用該方法的對象。根據this出現位置的不一樣,this做爲對象的默認引用有兩種情形。

  1. 構造器中引用該構造器正在初始化的對象。

  2. 在方法中引用調用該方法的對象。

對於static修飾的方法而言,則可使用類來直接調用該方法,若是在static修飾的方法中使用this關鍵字,則這個關鍵字就沒法指向合適的對象。因此,static修飾的方法中不能使用this引用。因爲static修飾的方法不能使用this引用,因此static修飾的方法不能訪問不使用static修飾的普通成員,所以Java語法規定:靜態成員不能直接訪問非靜態成員。

普通方法訪問其餘方法、成員變量時無須使用this前綴,但若是方法裏有個局部變量和成員變量同名,但程序又須要在該方法裏訪問這個被覆蓋的成員變量,則必須使用this前綴。this引用也能夠用於構造器中做爲默認引用,因爲構造器是直接使用new關鍵字來調用,而不是使用對象來調用的,因此this在構造器中表明該構造器正在初始化的對象。

方法詳解

方法的所屬性

Java語言裏方法的所屬性主要體如今以下幾個方面:

  1. 方法不能獨立完成,方法只能在類體裏定義。

  2. 從邏輯意義上來看,方法要麼屬於該類自己,要麼屬於該類的一個對象。

  3. 永遠不能獨立執行方法,執行方法必須使用類或對象做爲調用者。

同一個類的一個方法調用另外一個方法時,若是被調用方法是普通方法,則默認使用this做爲調用者;若是被調方法是靜態方法,則默認方法類做爲調用者。

方法的參數傳遞機制

聲明方法時包含了形參聲明,則調用方法時必須給這些形參指定參數值,調用方法時實際傳給形參的參數值也被稱爲實參。

形參個數可變的方法

Java容許定義形參個數可變的參數,從而容許爲方法指定數量不肯定的形參。若是在定義方法時,在最後一個形參的類型後增長三點(...),則代表該形參能夠接受多個參數值,多個參數值被當成數組傳入。

public statci void test(int a, String ... books)

數組形式的形參能夠處於形參列表的任意位置,但個數可變的形參只能處於形參列表的最後。也就是說一個方法中最多隻能有一個長度可變的形參。

遞歸方法

一個方法體內調用它自身,被稱爲方法遞歸。方法遞歸包含了一種隱式的循環,它會重複執行某段代碼,但這種重複執行無限循環控制。

但願遍歷某個路徑下的全部文件,但這個路徑下文件夾的深度是未知的,那麼就可使用遞歸來實現這個需求。系統可定義一個方法,該方法接受一個文件路徑做爲參數,該方法可遍歷當前路徑下的全部文件和文件路徑——該方法中再次調用該方法自己來處理該路徑下的全部文件路徑。

方法重載

Java容許同一個類裏定義多個同名方法,只有形參列表不一樣就行。若是同一個類中包含了兩個或兩個以上方法的方法名相同,但形參列表不一樣,則被稱爲方法重載。

方法重載三個因素:

  1. 調用者,也就是方法的所屬者,既能夠是類,也能夠是對象。

  2. 方法名,方法的標識。

  3. 形參列表,當調用方法時,系統將會根據傳入的實參列表匹配。

兩同一不一樣:同一個類中方法名相同,參數列表不一樣。方法返回值類型、修飾符等,與方法重載沒有任何關係。

成員變量和局部變量

成員變量

clipboard.png

成員變量指的是類裏定義的變量,也就是前面所介紹的field;局部變量指的是方法裏定義的變量。

成員變量:一個類不能定義兩個同名的成員變量。

  1. static修飾的類變量。類變量從該類的準備階段起開始存在,直到系統徹底銷燬這個類,類變量的做用域與這個類的生存範圍相同;而實例變量則從該類的實例被建立起開始存在,直到系統徹底銷燬這個實例,實例變量的做用域與對應實例的生存範圍相同。

  2. 成員變量無須顯式初始化,只要爲一個類定義了類變量或實例變量,系統就會在這個類的準備階段或建立該類的實例時進行默認初始化,成員變量默認初始化時的賦值規則與數組動態初始化時數組元素的賦值規則徹底相同。

局部變量:一個方法裏不能定義兩個同名的方法局部變量,方法局部變量與形參也不能同名;同一個方法中不一樣代碼塊內的代碼塊局部變量能夠同名;若是先定義代碼塊局部變量,後定義方法局部變量,前面定義的代碼塊局部變量與後面定義的方法局部變量也能夠同名。

  1. 形參(方法簽名中定義的變量) 做用域在整個方法內有效 必須顯式初始化

  2. 方法局部變量(在方法內定義) 做用域從定義該變量的地方生效,到該方法結束時失效 必須顯式初始化

  3. 代碼塊局部變量(在代碼塊內定義) 做用域從定義該變量的地方生效,到該代碼塊結束時失效 無須顯式初始化

Java容許局部變量和成員變量同名,若是方法裏的局部變量和成員變量同名,局部變量會覆蓋成員變量,若是須要在這個方法裏引用被覆蓋的成員變量,則可以使用this(對於實例變量)或類名(對於類變量)做爲調用者來限定訪問成員變量。

成員變量的初始化和內存中的運行機制

當系統加載類或建立該類的實例時,系統自動爲成員變量分配內存空間,並在分配內存空間後,自動爲成員變量指定初始值。

局部變量的初始化和內存中的運行機制

局部變量定義後,必須通過顯式初始化後才能使用,系統不會爲局部變量執行初始化。這意味着定義局部變量後,系統並未爲這個變量分配內存空間,直到等到程序爲這個變量賦初始值時,系統纔會爲局部變量分配內存,並將初始值保存到這塊內存中。

變量的使用規則

定義一個成員變量時,成員變量將被放置到堆內存中,成員變量的做用域將擴大到類存在範圍或者對象存在範圍,這種範圍的擴大有兩個害處。

  1. 增大了變量的生存時間,這將致使更大的內存開銷。

  2. 擴大了變量的做用域,這不利於提供程序的內聚性。

    應該考慮使用成員變量的狀況:

  3. 若是須要定義的變量是用於描述某個類或某個對象的固有信息。

  4. 若是在某個類中須要以一個變量來保存該類或者實例運行時的狀態信息。

  5. 若是某個信息須要在某個類的多個方法之間進行共享,則這個信息應該使用成員變量來保存。

即便在程序中使用局部變量,也應該儘量地縮小局部變量的做用範圍,局部變量的做用範圍越小,它在內存裏停留的時間就越短,程序運行性能就越好。所以,能用代碼塊局部變量的地方,就堅定不要使用方法局部變量。

隱藏和封裝

理解封裝

封裝指的是將對象的狀態信息隱藏在對象內部,不容許外部程序直接訪問對象內部信息,二世經過該類所提供的方法來實現對內部信息的操做和訪問。

對一個類或對象實現良好的封裝,能夠實現如下目的。
隱藏類的實現細節

  1. 讓使用者只能經過事先預約的方法來訪問數據,從而能夠在該方法里加入控制邏輯,限制對成員變量的不合理訪問。

  2. 可進行數據檢查,從而有利於保證對象信息的完整性。

  3. 便於修改,提升代碼的可維護性。

爲了實現良好的封裝,須要從兩個方面考慮:

  1. 將對象的成員變量和實現細節隱藏起來,不容許外部直接訪問。

  2. 把方法暴露出來,讓方法來控制對這些成員變量進行安全的訪問和操做。

使用訪問控制符

private → default → protected → public
訪問控制級別由小到大

  • private(當前類訪問權限):使用它來修飾成員變量就能夠把成員變量隱藏在該類的內部。

  • default(包訪問權限):defaulte訪問控制的成員或外部類能夠被相同包下的其餘類訪問。

  • protected(子類訪問權限):成員既能夠被同一包中的其餘類訪問,也能夠被不一樣包中的子類訪問。一般,若是使用protected來修飾一個方法,是但願其子類來重寫這個方法。

  • public(公共訪問權限):成員或外部類能夠被因此類訪問,無論訪問類和被訪問類是否處於同一包中,是否具備父子繼承關係。

private    default    protected    public
 同一個類中      √          √           √          √
 同一個包中                 √           √          √
 子類中                                 √          √
 全局範圍內                                        √

外部類只能有兩種訪問控制級別:public和default,外部類不能用private和protected修飾,由於外部類沒有處於任何類內部,也就沒有其所在類的內部、所在類的子類的兩個範圍。

若是一個Java類的每一個實例變量都被使用private修飾,併爲每一個實例變量都提供了public修飾setter和getter方法,那麼這個類就是一個符號JavaBean規範的類。所以,JavaBean老是一個封裝良好的類。

進行程序設計時,應儘可能避免一個模塊直接操做和訪問另外一個模塊的數據,模塊設計追求高內聚(儘量把模塊的內部數據、功能實現細節隱藏在模塊內部獨立完成,不容許外部直接干預)、低耦合(僅暴露少許的方法給外部使用)。

訪問控制符的使用的基本原則:

  • 類裏的絕大部分紅員變量都應該使用private,只有一些static修飾的、相似全局變量的成員變量,纔可能考慮使用public修飾。除此以外,有些方法只用於輔助實現該類的其餘方法,這些方法被稱爲工具方法,工具方法也應該使用private修飾。

  • 若是某個類主要用做其餘類的父類,該類裏包含的大部分方法可能僅但願被其子類重寫,而不想被外界直接調用,則應該使用protected修飾這些方法。

  • 但願暴露出來給其餘類自由調用的方法應該使用public修飾。所以,類的構造器經過public修飾,從而容許在其餘地方建立該類的實例。由於外部類一般都但願被其餘類自由使用,因此大部分外部類都使用public修飾。

package、import和import static

若是但願把一個類放到指定的包結構下,應該在Java源程序的第一個非註釋行放置以下格式的代碼:

package packageName;

一旦在Java源文件中使用了這個package語句,就意味着該源文件裏定義的全部類都屬於這個包。位於包中的每一個類的完整類名都應該是包名和類名的組合,若是其餘人須要使用該包下的類,也應該使用包名加類名的組合。

同一個包中的類沒必要位於相同的目錄下,例若有leePerson和LeePersonTest兩個類,它們徹底能夠一個位於C盤下某個位置,一個位於D盤下某個位置,只要讓CLASSPATH環境變量裏包含這兩個路徑便可。虛擬機會自動搜索CLASSPATH下的子路徑,把它們當成同一個包下的類來處理。也應該把Java源文件放在與包名一致的目錄結構下。一般建議將源文件和class文件分開存放,以便管理。

clipboard.png

從可讀性規範角度來看,包名應該所有是小寫字母,並且應該由一個或多個有意義的單詞連綴而成。

package語句必須做爲源文件的第一條非註釋性語句,一個源文件只能指定一個包,即只能包含一條package語句,該源文件中能夠定義多個類,則這些類將所有位於該包下。若是沒有顯式指定package語言,則處於默認包下。

同一個包下的類能夠自由訪問,無須添加包前綴。

父包和子包之間確實表示了某種內在的邏輯關係。但父包和子包在用法上不存在任何關係,若是父包中的類須要使用子包中的類,則必須使用子包的全名,而不能省略父包部分。

//調用構造器時須要在構造器前添加包前綴
lee.sub.Apple a  = new lee.sub.Apple();

import關鍵字

import能夠向某個Java文件中導入指定包層次下某個類或所有類,import語句應該出如今package語句以後(若是有)、類定義以前。一個Java源文件只能包含一個package語句,但能夠包含多個import語句,多個import語句用於導入多個包層次下的類。java.lang包下的全部類默認導入。

//使用import語句導入單個類
import    package.subpackage...ClassName;
//使用import語句導入指定包下所有
import    package.subpackage.*

星號()只能表明類,不能表明包。所以使用import.lee.;語句時,它代表導入lee包下的全部類,而lee包下sub子包內的類則不會被導入。如需導入lee.sub.Apple類,則可使用impor.lee.sub.*;語句來導入lee.sub包下的全部類。

一旦在Java源文件中使用import語句來導入指定類,在該源文件中使用這些類時就能夠省略包前綴,再也不須要使用類全名。

靜態導入import static

import static package.subpackage..ClassName.fieldName|methodName;
field:靜態成員變量;methodName:靜態方法。
使用import能夠省略寫包名;使用import static則能夠連類名都省略。

Java源文件的大體結構:

package語句                                                    //0個或1個,必須放在文件開始
import | import static 語句                                    //0個或多個,必須放在全部類定義以前
public classDefinition | interfaceDefinition | enumDefinition  //0個或1個public類、接口或枚舉定義
classDefinition | interfaceDefinition | enumDefinition         //0個或多個普通類、接口或枚舉定義

Java的經常使用包

Java.lang:核心類,如String、Math、System和thread類等,使用這個包下的類無須使用import語句導入,系統會自動導入這個包下的全部類。
java.util:Java的大量工具類/接口和集合框架類/接口,例如Arrays和List、Set等
java.net:一些Java網絡編程相關的類/接口
java.io:一些Java輸入/輸出編程相關的類/接口
java.text:一些Java格式化相關的類
java.sql:Java進行JDBC數據庫編程的想相關類/接口
java.awt:抽象窗口工具集的相關類/接口,這些類主要用於構建圖形用戶界面GUI程序
java.swing:Swing圖形用戶界面編程的相關類/接口,這些類可用於構建平臺無關的GUI程序
相關文章
相關標籤/搜索