類與對象 - Java學習(二)

来源:https://www.cnblogs.com/kelsen/archive/2018/10/07/9749945.html
-Advertisement-
Play Games

弄清楚類與對象的本質與基本特征,是進一步學習面向對象編程語言的基本要求。面向對象程式設計與面向過程程式設計在思維上存在著很大差別,改變一種思維方式並不是一件容易的事情。 ...


弄清楚類與對象的本質與基本特征,是進一步學習面向對象編程語言的基本要求。面向對象程式設計與面向過程程式設計在思維上存在著很大差別,改變一種思維方式並不是一件容易的事情。

一、面向對象程式設計

程式由對象組成,對象包含對用戶公開的特定功能部分,和隱藏在其內部的實現部分。從設計層面講,我們只關心對象能否滿足要求,而無需過多關註其功能的具體實現。面對規模較小的問題時,面向過程的開發方式是比較理想的,但面對解決規模較大的問題時,面向對象的程式設計往往更加合適。

對象是對客觀事物的抽象,類是對對象的抽象,是構建對象的模板。由類構造(construct)對象的過程稱為創建類的實例(instance)或類的實例化。

封裝是將數據和行為組合在一個包中,並對使用者隱藏數據的實現方式。對象中的數據稱為實例域(instance field)或屬性、成員變數,操縱數據的過程稱為方法(method)。對象一般有一組特定的實例域值,這些值的集合就是對象當前的狀態。封裝的關鍵在於不讓類中的方法直接的訪問其他類的實例域,程式僅通過對象的方法與對象數據進行交互。封裝能夠讓我們通過簡單的使用一個類的介面即可完成相當複雜的任務,而無需瞭解具體的細節實現。

對象的三個主要特征

  1. 對象的行為(behavior):可以對對象施加哪些操作,通過方法(method)實現。
  2. 對象的狀態(state):存儲對象的特征信息,通過實例域(instance field)實現。
  3. 對象的標識(identity):辨別具有不同行為與狀態的不同對象。

設計類

傳統的面向過程的程式設計,必須從頂部的 main 入口函數開始編寫程式。面向對象程式設計沒有所謂的頂部,我們要從設計類開始,然後再往每個類中添加方法。那麼我們該具體定義什麼樣的類?定義多少個?每個類又該具備哪些方法呢?這裡有一個簡單的規則可以參考 —— “找名詞與動詞”原則。

我們需要在分析問題的過程中尋找名詞和動詞,這些名詞很有可能成為類,而方法對應著動詞。當然,所謂原則,只是一種經驗,在創建類的時候,哪些名詞和動詞是重要的,完全取決於個人的開發經驗(抽象能力)。

類之間的關係

最常見的關係有:依賴(use-a)、聚合(has-a)、繼承(is-a)。可以使用UML(unified modeling language)繪製類圖,用來可視化的描述類之間的關係。

二、預定義類與自定義類

在 Java 中沒有類就無法做任何事情,Java 標準類庫中提供了很多類,這裡稱其為預定義類,如 Math 類。要註意的是:並非所有類都具有面向對象的特征(如 Math 類),它只封裝了功能,不需要也不必要隱藏數據,由於沒有數據,因此也不必擔心生成以及初始化實例域的相關操作。

要使用對象,就必須先構造對象,並指定其初始狀態。我們可以使用構造器(constructor)構造新實例,本質上,構造器是一種特殊的方法,用以構造並初始化對象。構造器的名字與類名相同。如需構造一個類的對象,需要在構造器前面加上 new 操作符,如new Date()。通常,希望對象可以多次使用,因此,需要將對象存放在一個變數中,不過要註意,一個對象變數並沒有實際包含一個對象,而僅僅是引用一個對象。

訪問器與修改器 我們把只訪問對象而不修改對象狀態的方法稱為 訪問器方法(accessor method)。如果方法會對對象本身進行修改,我們稱這樣的方法稱為 更改器方法(mutator method)。

用戶自定義類

要想創建一個完成的程式,應該將若幹類組合在一起,其中只有一個類有 main 方法。其它類( workhorse class)沒有 main 方法,卻有自己的實例域和實例方法,這些類往往需要我們自己設計和定義。

一個源文件中,最多只能有一個公有類(訪問級別為public),但可以有任意數目的非公有類。儘管一個源文件可以包含多個類,但還是建議將每一個類存在一個單獨的源文件中。 不提倡用public標記實例域(即對象的屬性),public 數據域允許程式中的任何方法對其進行讀取和修改。當實例域設置為 private 後,如果需要對其進行讀取和修改,可以通過定義公有的域訪問器或修改器來實現。這裡要註意:不要編寫返回引用可變對象的訪問器方法,如:

class TestClass{
    private Date theDate;
    public getDate(){
        return theDate; // Bad
    }
}

上面的訪問器返回的是對實例屬性 theDate 的引用,這導致在後續可以隨意修改當前實例的 theDate 屬性,比如執行x.getDate().setTime(y),破壞了封裝性!如果要返回一個可變對象的引用,應該首先對他進行克隆,如下:

class TestClass{
    private Date theDate;
    public getDate(){
        return (Date) theDate.clone(); // Ok
    }
}

構造器

構造器與類同名,當實例化某個類時,構造器會被執行,以便將實例域初始化為所需的狀態。構造器總是伴隨著 new 操作符的調用被執行,不能對一個已經存在的對象調用構造器來重置實例域。

  1. 構造器與類同名
  2. 每個類可以有多個構造器
  3. 構造器可以有 0 個或多個參數
  4. 構造器沒有返回值
  5. 構造器總是伴隨著 new 操作一起調用

基於類的訪問許可權

方法可以訪問所屬類的所有對象的私有數據。[*]

在實現一個類時,應將所有的數據域都設置為私有的。多數時候我們把方法設計為公有的,但有時我們希望將一個方法劃分成若幹個獨立的輔助方法,通常這些輔助方法不應該設計成為公有介面的一部分,最好將其標記為 private 。只要方法是私有的,類的設計者就可以確信:他不會被外部的其他類操作調用,可以將其刪去,如果是公有的,就不能將其刪除,因為其他的代碼可能依賴它。

final 實例域

在構建對象時必須對聲明的 final 實例域進行初始化,就是說必須確保在構造器執行之後,這個域的值被設置,並且在後面的操作中,不能夠再對其進行修改。final 修飾符大都用於基本類型,或不可變類的域。

靜態域和靜態方法

靜態域和靜態方法,是屬於類且不屬於對象的變數和函數。

通過 static 修飾符,可以標註一個域為靜態的,靜態域屬於類,而不屬於任何獨立的對象,但是每個對象都會有一份這個靜態域的拷貝。靜態方法是一種不能對對象施加操作的方法,它可以訪問自身類的靜態域,類的對象也可以調用類的靜態方法,但更建議直接使用類名調用靜態方法。

使用靜態方法的場景 : 一個方法不需要訪問對象狀態,其所需參數都是通過顯式參數提供;一個方法只需要訪問類的靜態域。

靜態方法還有另外一種常見用途,作為工廠方法用以構造對象。之所已使用工廠方法,兩個原因:一是無法命名構造器,因為構造器必須與類名相同;二是當時用構造器時無法改變構造的對象類型。

程式入口 main 方法就是一個典型的靜態方法,其不對任何對象進行操作。在啟動程式時還沒有任何一個對象,靜態的 main 方法將執行並創建程式所需要的對象。每個類都可以有一個 main 方法,作為一個小技巧,我們可以通過這個方法對類進行單元測試。

三、方法參數

Java 中的方法參數總是按值調用,也就是說,方法得到的是所有參數的值的一個拷貝,特別是,方法不能修改傳遞給它的任何參數變數的內容。然而,方法參數有兩種類型:基本數據類型和對象引用。

四、對象構造

如果在構造器中沒有顯式的為域賦值,那麼域會被自動的賦予預設值:數值為 0、布爾之為 false、對象引用為 null。在類沒有提供任何構造器的時候,系統會提供一個預設的構造器。

有些類有多個構造器,這種特征叫做重載(overloading)。如果多個方法有相同的名字、不同的參數,便產生了重載。 Java 中允許重載任何方法,而不僅是構造器方法。要完整的描述一個方法,需要指出方法名以及其參數類型,這個描述被稱作方法的簽名。

通過重載類的構造器方法,可以採用多種形式設置類的實例的初始狀態。當存在多個構造器的時候,也可以在構造器內部通過 this 調用另一個構造器,要註意的是這個調用必須在當前構造器的第一行:

class Test{
    Test(int number) {
        this(number, (String)number);   // 位於當前構造器的第一行
    }

    Test(int number, String str) {
        _number = number;
        _string = str;
    }
}

初始化塊

在一個類的聲明中,可以包含多個代碼塊。只要構造類的對象,這些塊就會被執行。例如:

class Test{
    private int number;
    private String name;

    /**
     * 初始化塊
     */
    {
        number = 5;
    }

    Test(){
        name = 'Kelsen'
    }

    public void pring(){
        System.out.println(name + "-" + number);
    }
}

執行順序為,首先運行初始化塊,然後再運行構造器的主體部分。這種機制不是必須的,也不常見。通常會直接將初始化代碼放在構造器中。

Java 中不支持析構器,它有自動的垃圾回收器,不需要人工進行記憶體回收。但,如果某個資源需要在使用完畢後立刻被關閉,那麼就需要人工來管理。對象用完時可以應用一個 close 方法來完成相應的清理操作。

五、包

藉助於包,可以方便的組織我們的類代碼,並將自己的代碼與別人提供的代碼庫區分管理。標準的 Java 類庫分佈在多個包中,包括 java.lang、java.util 和 java.net 等。標準的 Java 包具有一個層次結構。如同硬碟文件目錄嵌套一樣,也可以使用嵌套層次組織包。所有的標準 Java 包都處於 javajavax 包層次中。從編譯器角度看,嵌套的包之間沒有任何關係,每一個都擁有獨立的類集合。

一個類可以使用所屬包中的所有類,以及其他包中的公有類(pbulic class)。 import 語句是一種引用包含在包中的類的簡明描述。packageimport 語句類似 C++ 中的 namespaceusing 指令。

import 語句還可以用來導入類的靜態方法和靜態域。

如果要將一個類放入包中,就必須將包的名字放在源文件的開頭,包中定義類的代碼之前。如:


package com.kelsem.learnjava;

public class Test{
    // ...
}

如果沒有在源文件中放置 package 語句,這個源文件中的類就被放置在一個預設包中。

包作用域

標記為 private 的部分只能被定義他們的類訪問,標記為 public 的部分可以被任何類訪問;如果沒有指定訪問級別,這個部分(類/方法/變數)可以被同一個包中的所有方法訪問。

類路徑

類存儲在文件系統的目錄中,路徑與包名匹配。另外,類文件也可以存儲在 JAR 文件中。為了使類能夠被多個程式共用,通常把類放到一個目錄中,將 JAR 文件放到一個目錄中,然後設置類路徑。類路徑是所有包含類文件的路徑的集合,設置類路徑時,首選使用 -calsspath 選項設置,不建議通過設置 CLASSPATH 這個環境變數完成該操作。

六、文檔註釋

JDK 包含一個非常有用的工具,叫做 javadoc 。它通過分析我們的代碼文件註釋,自動生成 HTML 文檔。每次修源碼後,通過運行 javadoc 就可以輕鬆更新代碼文檔。Javadoc 功能包括:Javadoc搜索,支持生成HTML5輸出,支持模塊系統中的文檔註釋,以及簡化的Doclet API。詳細使用說明可參考 https://docs.oracle.com/en/java/javase/11/javadoc/javadoc.html

七、類的設計

一定要保證數據私有 務必確保封裝性不被破壞。

一定要對數據初始化 Java 不會對局部變數進行初始化,但會對對象的實例域進行初始化。最好不要依賴於系統預設值,而是顯式的對實例域進行初始化。

不要在類中使用過多的基本類型 通過定義一個新的類,來代替多個相關的基本類型的使用。

不是所有的域都需要獨立的域訪問器和域更改器

將職責過多的類進行分解 如果明顯的可以將一個複雜的類分解為兩個更簡單的類,就應該將其分解。

類名和方法名要能夠體現他們的職責 對於方法名,建議:訪問器以小寫 get 開頭,修改器以小寫 set 開頭;對於類名,建議類名是採用一個名詞(Order)、前面有形容詞修飾的名詞(RushOrder)或動名詞(ing尾碼)修飾名詞(BillingAddress)。

優先使用不可變的類 要儘可能讓類是不可變的,當然,也並不是所有類都應當是不可變的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基本線程管理 join detach join:主線程等待被join線程結束後,主線程才結束。 detach:主線程不等待被detach線程。 問題1:子線程什麼時點開始執行? std::thread t(fun);執行後,就開始執行了。 問題2:在哪裡調用join或者detach 1,使用deta ...
  • 本文回顧了上一篇文章中的HelloWorld程式,並通過類定義、註釋和main方法三個方面對這個程式進行了詳細的剖析。相信讀完這篇文章以後,讀者將會對Java程式的結構有一個整體的認識。 ...
  • final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {} ]public Object invoke(Object proxy, Method method, Object[] arg... ...
  • 1、獲取時間戳 (1)、os.time() --當前時間戳 (2)、 os.time({day=5, month=9, year=2018, hour=12, min=59, sec=59}) --指定時間的時間戳 2、獲取指定格式時間 (1)、時間格式 yyyyMMddHHmmss:os.date ...
  • 本文設計思想採用明德揚至簡設計法。上一篇博文中定製了自定義MAC IP的結構,在用戶側需要位寬轉換及數據緩存。本文以TX方向為例,設計並驗證發送緩存模塊。這裡定義該模塊可緩存4個最大長度數據包,用戶根據需求改動即可。 該模塊核心是利用非同步FIFO進行跨時鐘域處理,位寬轉換由VerilogHDL實現。 ...
  • 一直以來只使用番茄vs助手(https://www.wholetomato.com/downloads/default.asp)輔助寫代碼,也都忘了是誰介紹的,不過確實好用。 相比原始的vs,它提供了很多改進功能。例如,重命名變數,高亮巨集與自定義類型,查找引用,智能代碼提示等。 因為一直以來用著沒有 ...
  • Fs = 1000; % 採樣頻率 N = 1024; % 採樣點數 ,即實際中一次FFT變換所使用的點數n = 0:N-1; % 採樣序列,為plot繪圖用的序列,其對應點表示的真實頻率為 f = f = n*(Fs/N),Fs/N,是頻率解析度,其中0 <= N < max(N)/2-1 f = ...
  • 考慮到以後可能會在深圳工作,所以寫了這個爬蟲,希望對自己的找房過程提供一些便捷。 信息來源是豆瓣的深圳租房小組(想爬取其他城市只需要更換一下URL就好)。 你們一定會說這麼麻煩乾什麼,租房APP不是直接看麽?我也是這麼想的。。。但是租房APP上中介比較多,豆瓣上多是個人房源,中介少,比較可靠。但豆瓣 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...