java面向對象基礎(二)

来源:https://www.cnblogs.com/f-ck-need-u/archive/2017/12/27/8127546.html
-Advertisement-
Play Games

許可權修飾符 許可權修飾符包括public、private、protected和不加任何修飾符的default,它們都可以修飾方法和變數。其中public和預設的default(不加任何修飾符)這兩個還可以修飾class。private和protected修飾類的情況只能在使用內部類時修飾,正常情況下不 ...


許可權修飾符

許可權修飾符包括public、private、protected和不加任何修飾符的default,它們都可以修飾方法和變數。其中public和預設的default(不加任何修飾符)這兩個還可以修飾class。private和protected修飾類的情況只能在使用內部類時修飾,正常情況下不能使用這兩個修飾符修飾類。

(1).public:用public修飾的變數及方法,包內及包外的任何類(包括子類和普通類)均可以訪問;
(2).protected:用protected修飾的變數及方法,包內的任何類及包外那些繼承了該類的子類才能訪問,protected重點突出繼承;
(3).default:沒有用public、protected及private中任何一種修飾,其訪問許可權為default預設許可權。預設訪問許可權的類、類屬變數及方法,包內的任何類(包括繼承了此類的子類)都可以訪問它,而對於包外的任何類都不能訪問它(包括包外繼承了此類的子類)。default重點突出包;
(4)private: 用private修飾的變數及方法,只有本類可以訪問,而包內包外的任何類均不能訪問它。

就一句話:protected修飾符所修飾的變數和方法,只可以被子類訪問,而不管子類是不是和父類位於同一個包中。default修飾符所修飾的變數和方法,只可被同一個包中的其他類訪問,而不管其他類是不是該類的子類。protected屬於包修飾符,還是子類修飾符,而default屬於包修飾符。

從許可權嚴格角度來說,private < default < protected < public

在考慮default修飾的許可權時,它是包修飾符,其中沒有加入到包中的"裸體類"屬於同一個隱式的包中,因此可以互相訪問。

例如,前面的person和student的繼承關係中,將父類成員變數name加上private修飾符,於是下麵的代碼將編譯出錯。因為new子類對象時,構造方法中賦值給this.name,而這個name是繼承自父類的,它是private的。因此對於子類來說,這個成員變數屬於能看到,不能引用、不能操作的擺設屬性。

class Person  {
    private String name;
    int age;

}

class Student extends Person {
    int studentID;

    Student(int id,String name,int age) {
        this.name = name;
        this.age = age;
        this.studentID = id;
    }

}

public class Inherit {
    public static void main(String[] args) {
        Student s1 = new Student(1,"Malongshuai",23);
    }
}

方法的重寫(overwrite/override)

父類定義的成員相對來說都比較粗糙,當子類繼承時,難免無法適當地描述子類。因此當子類對從父類繼承的方法不滿意時,可以重寫方法。

例如Person類能eat(),但girl類吃飯是淑女的吃,boy類吃飯是粗魯的吃。girl類很不滿意,因為父類的eat()只能描述吃,不能描述怎麼吃。於是girl類就重寫eat()方法,讓吃這個方法符合自身的淑女形象。

重寫方法必須和被重寫的方法具有相同的方法名稱、參數列表和返回類型。重寫的方法不能比被重寫的方法許可權更嚴格。從方法訪問的角度來說,父類的方法都能被訪問,子類重寫後的方法卻不能被訪問,這顯然是不合理的,且即使這是能訪問父類方法,但重寫的意義就丟失了。

重寫方法時,最佳實踐方式是copy整個被重寫的方法的定義語句。因為即使重寫方法的名稱改變了,編譯也不會出錯。例如重寫eat()結果寫成了Eat(),編譯是不會有任何錯誤出現的,此時它沒有重寫,而是新定義了一個Eat()方法。

class Person  {
    String name;
    int age;

    void eat() { System.out.println("eating...");}
}

class Student extends Person {
    int studentID;

    Student(int id,String name,int age) {
        this.name = name;
        this.age = age;
        this.studentID = id;
    }

    void eat() { System.out.println("graceful eating");}  //重寫
    void study() {System.out.println("studing...");}
}

public class Inherit {
    public static void main(String[] args) {
        Student s1 = new Student(1,"Malongshuai",23);
        System.out.println(s1.studentID+","+s1.name+","+s1.age);
        s1.eat();  //調用重寫後的eat方法
    }
}

super關鍵字

this關鍵字指向對象自身,而super關鍵字則指向對象中的父對象。如下圖:

super既可以用來引用父對象的成員變數,也可以用來調用父對象的方法。例如下麵的代碼:

class FatherClass {
    public int value;
    public void f(){
        value = 100;
        System.out.println("FatherClass.value="+value);
    }
}

class ChildClass extends FatherClass {
    public int value;
    public void f() {
        super.f();       //雖然f()要重寫,但父對象的f()函數還有一些用武之地來發揮餘熱
        value = 200;
        System.out.println("ChildClass.value="+value);
        System.out.println(value);
        System.out.println(super.value);
    }
}

public class TestInherit {
    public static void main(String[] args) {
        ChildClass cc = new ChildClass();
        cc.f();
    }
}

new出子對象時,父類和子類中都有value屬性,它們都採用的初始化值0。當執行cc.f()時,調用子類的f()方法,該方法首先調用父對象的f()方法,父f()方法先將value賦值為100,這個value是父對象的屬性,然後回到子f()中賦值value為200,這個value是子對象自身的value,隨後輸出的兩個value都是子對象中的value屬性,最後的super.value是父對象中的value屬性。

雖然在圖中看上去super和this的地位是相同的,但實際上它們之間很不公平,不公平之處在於有引用變數(上圖中的cc)指向子對象,所以能夠使用"return this"代碼來返回一個子對象,但卻不能使用"return super"來返回子對象中的父對象,因為沒有引用變數指向父對象。

關於super調用的成員變數,需要區分清楚是子對象中的屬性還是父對象中的屬性。如果子對象和父對象中有同名屬性var,在沒有指定"this.var"和"super.var"時,僅模糊地指定var時將優先取子對象的屬性,如果子對象中沒有某屬性,則var表示的是父對象中的屬性。例如:

class Student extends Person {
    int studentID;
    int age = 33;

    Student(int id) {
        this.name = super.name + "x";
        this.age = age + 2;   //右邊的age是子對象的屬性,但如果將"int age = 33;"註釋,則age是父對象的屬性
        this.studentID = id;
    }
}

繼承時構造方法的重寫super()

子對象中總是包含父對象,這個父對象是怎麼來的?對象都是通過構造方法構造出來的,因此在new子類對象的時候,會調用對應的子類構造方法構造子對象,正是這個時候使用super()方法表示調用父類構造方法將父對象構造出來的。

在寫構造父對象的代碼時有以下幾個規則:

  1. 使用子類構造方法構造子對象時,必須要構造父對象。
  2. 子類可以在自己的構造方法中使用super(args)來調用父類的構造方法。同理,可以使用this(args)來調用本類其他的構造方法。
  3. super(args)必須寫在子類構造方法中的第一行,因為要先構造出父對象,再慢慢填補子對象自身。如果沒有顯式書寫super(args),則預設在第一行處調用父類無參數的構造方法,等價於super()。
  4. 如果子類構造方法中調用的super(args)在父類中不存在對應參數列表的構造方法,則編譯錯處。這包括沒有顯式指定super()時,且父類又重載了構造方法使得父類中沒有了無參數的構造方法時。
class Person {
    String name;
    int age;

    Person() {
        System.out.println("Person()");
    }

    Person(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person(arg1,arg2)");
    }

    Person(String name) {
        this.name = name;
        age = 20;
        System.out.println("Person(arg1)");
    } 
}

class Student extends Person {
    int studentID;

    Student(int id) {
        super("Malongshuai",23);   //第一行調用父類構造方法構造父對象,且是含有兩個參數的Person(arg1,arg2)
        this.name = super.name + "X"; //調用父對象中的name屬性
        this.age = age + 2;           //也是調用父對象中的屬性age
        this.studentID = id;
    }
}

public class TestSuper {
    public static void main(String[] args) {
        Student s1 = new Student(1);
        System.out.println(s1.studentID+", "+s1.name+", "+s1.age);
    }
}

如果將"super("Malongshuai",23);"修改為super("Malongshuai"),則表示調用父類的Person(arg1)構造方法。如果改為super(),則表示調用父類的Person()構造方法。如果省略不寫super,則等價於super()。

Object類

除了明確定義了從某個父類繼承的子類,java中的所有類都是從java.lang包中的Object類繼承來的。也就是說,Object類是所有類繼承的根,也就是它們的祖宗。一級繼承一級,最終的根總是Object類。

這個類里提供了幾個方法,但基本上所有方法都建議重寫,因為它的級別太高,抽象化的太嚴重,它的提供的那些方法也就太大眾化。

toString()

在和對象做數據連接時,將自動調用該類的toString()方法。例如System.out.println("Hello" + Person)時,等價於System.out.println("Hello" + Person.toString())

例如:

public class TTString {
    public static void main(String [] args) {
        Person p = new Person();
        System.out.println(p);
        System.out.println(p.toString());
    }
}

class Person {}

編譯並運行,查看toString()的運行結果。

D:\myjava
λ javac TTString.java

D:\myjava
λ java TTString
Person@15db9742
Person@15db9742

toString()的結果是"類名@hex(hashcode)"。官方建議,任何子類都應該重寫該方法。例如:

public class TTString {
    public static void main(String [] args) {
        Person p = new Person();
        System.out.println(p);
    }
}

class Person {
    public String toString() {  //重寫toString()
        return "Hello World";
    }
}

對象的比較"=="和equals()

對象與對象之間是否有相等關係?一般可以認為,如果兩個對象的對象內容完全相同,將認為是相等的對象。

在進行對象比較時,"=="比較的是兩個對象的引用地址,因此兩個對象使用"=="比較時是絕對不會相等的。Object類中的equals(),基本等價於"==",因此也無法正確比較對象是否相等。所以官方手冊建議重寫equals()方法。在String類中已經重寫好了。

例如,使用String類中的equals()。

public class TTequals {
    public static void main(String [] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

final關鍵字

final表示最終的意思,它可以修飾變數、方法和類。

  1. final變數的值不能被改變。
    • (1).final的成員變數不可改變。
    • (2).final的局部變數和形參不可改變。
  2. final的方法不能被重寫。
  3. final的類不能被繼承。

也就是說,要想讓變數只讀、方法不可改變或類的繼承到此結束,就用final進行修飾。

註:若您覺得這篇文章還不錯請點擊右下角推薦,您的支持能激發作者更大的寫作熱情,非常感謝!


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

-Advertisement-
Play Games
更多相關文章
  • 抽象類(abstract) 以下麵多態的示例來說明: 父類Animal中的sing()方法遲早要被子類Cat、Dog重寫,而且在多態實現下,Animal的sing()完全是多餘的。因此,可以將Animal的sing()方法的方法體刪掉。 更徹底一點,將sing()方法加上abstract關鍵字,這個 ...
  • 一. 問題: 在使用solr時, 分詞器解析中文的時候, 是一個一個字解析的. 這並不是我們想要的結果. 而在lucene中, 使用的中文分詞器是 IKAnalyzer. 那麼在solr裡面, 是不是任然可以用這個呢. 二. 整合 ik 1. 修改schema配置文件 打開如下路徑中的managed ...
  • #有‘*’為重點import timeprint(time.time())#以秒的形式返回******time.sleep(3) ******print(time.clock()) #cpu執行的時間print(time.gmtime()) # 結構化時間,本初子午線那裡的時間time.struct ...
  • 一 前段時間自學了一段時間的Python,想著濃一點項目來練練手。看著大佬們一說就是爬了100W+的數據就非常的羡慕,不過對於我這種初學者來說,也就爬一爬圖片。 我相信很多人的第一個爬蟲程式都是爬去貼吧的圖片,嗯,我平時不玩貼吧,加上我覺得豆瓣挺良心的,我就爬了豆瓣首頁上面的圖片。其實最剛開始是想爬 ...
  • 本文簡單的介紹了Servlet處理響應的基本流程以及Servlet的生命周期 ...
  • 一、wxPython介紹 1、wxPython是Python語言的一套優秀的GUI圖形庫。wxPython可以很方便的創建完整的、功能鍵全的GUI用戶界面。 wxPython是作為優秀的跨平臺GUI庫wxWidgets的Python封裝和Python模塊的方式提供給用戶的。 2、wxPython是跨 ...
  • 原題是這樣的: 給出一個字元串數組S,找到其中所有的亂序字元串(Anagram)。如果一個字元串是亂序字元串,那麼他存在一個字母集合相同,但順序不同的字元串也在S中。 樣例 對於字元串數組 ["lint","intl","inlt","code"] 返回 ["lint","inlt","intl"] ...
  • Pandas基礎篇 Pandas基於Numpy開發,提供了很多高級的數據處理功能。 1、Pandas中的數據對象 Series和DataFrame是Pandas中最常用的兩個對象。 1.1 Series對象 是Pandas中最基本的對象,可用Numpy的數組處理函數直接對Series對象進行處理。支 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...