溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中封裝和繼承是什么

發(fā)布時間:2021-07-02 09:31:25 來源:億速云 閱讀:126 作者:小新 欄目:開發(fā)技術

這篇文章給大家分享的是有關Java中封裝和繼承是什么的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

    一. 封裝

    那封裝是什么呢?

    在面向?qū)ο蟪淌皆O計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現(xiàn)細節(jié)部分包裝、隱藏起來的方法。

    1.1 封裝的目的

    • 直接通過操控類對象來達到目的,不需要對具體實現(xiàn)十分了解,使類屬性和方法的具體實現(xiàn)對外不可見。不但方便還起到了保護作用。

    • 封裝最主要的功能在于我們能修改自己的實現(xiàn)代碼,而不用修改那些調(diào)用我們代碼的程序片段。

    • 適當?shù)姆庋b可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。

    1.2 封裝的好處

    • 良好的封裝能夠減少耦合。

    • 類內(nèi)部的結構可以自由修改。

    • 可以對成員變量進行更精確的控制。

    • 隱藏信息,實現(xiàn)細節(jié)。

    1.3 封裝的步驟

    修改屬性的可見性來限制對屬性的訪問(一般限制為private),例如:

    public class Person {
        private String name ; // 姓名
        private String gender ; // 性別
        private int age; // 年齡
    }

    這段代碼中,將 name 、sexage 屬性設置為私有的,只能本類才能訪問,其他類都訪問不了,如此就對信息進行了隱藏。

    對每個值屬性提供對外的公共方法訪問,也就是創(chuàng)建一對賦取值方法,用于對私有屬性的訪問,例如:

    public class Person {
        private String name ; // 姓名
        private String gender ; // 性別
        private int age; // 年齡
        public void setName(String name) {
          	this.name = name;
        }
        public String getName() {
          	return name;
        }
    	public void setGender(String gender) {
            this.gender = gender;
        }
        public String gender(){
            return gender;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public int getAge() {
          	return age;
        }
    }

    采用 this 關鍵字調(diào)用本類中的屬性,也就是類中的成員變量。主要為了解決實例變量(private String name)和局部變量(setName(String name)中的name變量)之間發(fā)生的同名的沖突。

    1.4 封裝的例子

    創(chuàng)建一個用戶類User:

    Java中封裝和繼承是什么

    • 代碼如下:

    package com.nz.pojo;
    public class User {
        private String username; // 用戶名
        private String password; // 密碼
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }
    • 編寫測試User的demo:EncapsulationDemo

    Java中封裝和繼承是什么

    代碼如下:

    package com.nz;
    import com.nz.pojo.User;
    public class EncapsulationDemo {
        public static void main(String[] args) {
            User user = new User();
            user.setUsername("太子爺哪吒");
            user.setPassword("520");
            System.out.println("username: " + user.getUsername() + "-----------"
                                + "password: " + user.getPassword());
        }
    }

    執(zhí)行結果如下:

    username:太子爺哪吒-----------password520

    1.5 小結

    封裝實際上是將類的某些信息隱藏在類的內(nèi)部,不允許外部程序直接訪問,而是通過該類提供的方法來實現(xiàn)對隱藏信息的訪問和操作。就是把我們想提供給外界的一些方法給暴露出來,以便外界能調(diào)用到我們。

    二. 繼承

    2.1 繼承的介紹

    繼承是java面向?qū)ο缶幊碳夹g的一塊基石,因為它允許創(chuàng)建分等級層次的類。描述的是事物之間的所屬關系,這種關系是:is-a 的關系。

    繼承:就是子類繼承父類的屬性行為,使得子類對象(實例)可以直接具有與父類相同的屬性、相同的行為。子類可以直接訪問父類中的非私有的屬性和行為。

    2.2 生活中的繼承

    Java中封裝和繼承是什么

    兔子和長頸鹿屬于食草動物類,老虎和獅子屬于食肉動物類。而食草動物和食肉動物又是屬于動物類。

    那是不是兔子、長頸鹿、老虎、獅子都屬于動物類呢?答案是沒錯滴!雖然食草動物和食肉動物都是屬于動物,但是兩者的屬性和行為上有差別,所以子類會具有父類的一般特性也會具有自身的特性。我們就可以再多個類中存在相同屬性和行為時,我們可以將這些內(nèi)容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只要繼承那一個類即可。

    2.3 繼承的好處

    1. 提高代碼的復用性(減少代碼冗余,相同代碼重復利用)。

    2. 使類與類之間產(chǎn)生了關系。

    3. 子類擁有父類非 private 的屬性、方法。

    4. 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。

    5. 子類可以用自己的方式實現(xiàn)父類的方法。

    6. 提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯(lián)系越緊密,代碼獨立性越差)。

    7. Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如 B 類繼承 A 類,C 類繼承 B 類,所以按照關系就是 B 類是 C 類的父類,A 類是 B 類的父類,這是 Java 繼承區(qū)別于 C++ 繼承的一個特性。

    2.4 繼承的格式

    在Java當中會通過extends關鍵字可以申明一個類是從另外一個類繼承而來的,一般形式如下:

    class 父類 {
    }
    class 子類 extends 父類 {
    }

    需要注意一點: Java 不支持多繼承,但支持多重繼承。就如下:

    class A {
    }
    class B extends A {   (對的)
    }
    class C extends A, B {  (錯的)
    }
    class C extends B {   (對的)
    }

    Java中封裝和繼承是什么

    頂層父類是Object類。所有的類默認繼承Object,作為父類。

    2.5 繼承的demo

    • 編寫一個父類極其對應的子類信息

    結構如下:

    Java中封裝和繼承是什么

    代碼如下:

    父類Person:

    package com.nz.pojo;
    public class Person {
        private String name ;
        private int age ;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }

    子類Student沒有額外的屬性和方法:

    package com.nz.pojo;
    /**
     * 繼承了Person特有的name, age,
     * 沒有額外的獨有屬性和方法
     */
    public class Student extends Person{
    }

    子類Teacher多了一個工資的屬性和獨有的教書方法:

    package com.nz.pojo;
    /**
     * 繼承了Person特有的name, age,
     * 多了自己獨有的工資屬性還有獨有的教書方法
     */
    public class Teacher extends Person{
        // 工資
        private double salary ;
        // 特有方法
        public void teach(){
            System.out.println("老師在認真教書!");
        }
        public double getSalary() {
            return salary;
        }
        public void setSalary(double salary) {
            this.salary = salary;
        }
    }

    編寫測試代碼:

    package com.nz;
    import com.nz.pojo.Student;
    import com.nz.pojo.Teacher;
    public class InheritDemo {
        public static void main(String[] args) {
            Teacher teacher = new Teacher();
            teacher.setName("太子爺哪吒");
            teacher.setAge(18);
            teacher.setSalary(1999.99);
            System.out.println(teacher.getName());
            System.out.println(teacher.getAge());
            System.out.println(teacher.getSalary());
            teacher.teach();
            Student student = new Student();
            student.setName("哪吒");
            student.setAge(12);
            //student.setSalary(1999.99); // student沒有工資屬性,報錯!
            System.out.println(student.getName());
            System.out.println(student.getAge());
        }
    }

    結果如下:

    太子爺哪吒
    18
    1999.99
    老師在認真教書!
    哪吒
    12

    從結果來看,子類繼承父類,就可以直接得到父類的成員變量和方法。而子類可以編寫一些特有的屬性和方法,但是是否可以繼承所有成分呢?

    2.6 子類不能繼承的內(nèi)容

    并不是父類的所有內(nèi)容都可以給子類繼承的:

    2.6.1 super 與 this 關鍵字

    這里先將這兩個關鍵字,super和this在繼承關系中,運用比較頻繁。

    • super關鍵字:我們可以通過super關鍵字來實現(xiàn)對父類成員的訪問,用來引用當前對象的父類。

    • this關鍵字:指向自己本類的引用。

    super和this完整的用法如下:

    this.成員變量    	--    本類的
    super.成員變量    	--    父類的
    this.成員方法名()  	--    本類的    
    super.成員方法名()   --    父類的

    具體演示,創(chuàng)建測試InheritDemo2:

    package com.nz;
    public class InheritDemo2 {
        public static void main(String[] args) {
            Animal a = new Animal();
            a.eat();
            Cat cat = new Cat();
            cat.eatFish();
        }
    }
    class Animal {
        void eat() {
            System.out.println("animal : eat");
        }
    }
    class Cat extends Animal {
        void eat() {
            System.out.println("cat : eat");
        }
        void eatFish() {
            this.eat();   // this 調(diào)用自己的方法
            super.eat();  // super 調(diào)用父類方法
        }
    }

    調(diào)用結果如下:

    animal : eat
    cat : eat
    animal : eat

    注意:

    子類的每個構造方法中均有默認的super(),調(diào)用父類的空參構造。手動調(diào)用父類構造會覆蓋默認的super()。

    super() 和 this() 都必須是在構造方法的第一行,所以不能同時出現(xiàn)。

    2.6.2 構造器不能被繼承
    • 子類不能繼承父類的構造器(構造方法或者構造函數(shù)),它只是調(diào)用(隱式或顯式)。因為子類有自己的構造器。值得注意的是子類可以繼承父類的私有成員(成員變量,方法),只是子類無法直接訪問而已,可以通過getter/setter方法訪問父類的private成員變量。

    • 如果父類的構造器帶有參數(shù),則必須在子類的構造器中顯式地通過super 關鍵字調(diào)用父類的構造器并配以適當?shù)膮?shù)列表。

    • 如果父類構造器沒有參數(shù),則在子類的構造器中不需要使用 super 關鍵字調(diào)用父類構造器,系統(tǒng)會自動調(diào)用父類的無參構造器。

    演示過程:

    package com.nz;
    public class InheritDemo3  {
        public static void main(String[] args) {
            System.out.println("------Teacher 類繼承------");
            Teacher teacher = new Teacher();
            Teacher teacher2 = new Teacher("張三");
            System.out.println("------Student 類繼承------");
            Student student = new Student();
            Student student2 = new Student("張三三");
        }
    }
    // 父類
    class Person {
        private String name;
        Person(){
            System.out.println("調(diào)用了父類的無參構造器: Person()");
        }
        Person(String name) {
            System.out.println("調(diào)用了父類的帶參構造器: Person(String name)");
            this.name = name;
        }
    }
    // Teacher子類繼承Person
    class Teacher extends Person{
        private String name;
        Teacher(){
            // 自動調(diào)用父類的無參數(shù)構造器 因為會有默認super();
            System.out.println("Teacher");
        }
        public Teacher(String name){
            super("太子爺哪吒");  // 調(diào)用父類中帶有參數(shù)的構造器
            System.out.println("Teacher(String name):"+name);
            this.name = name;
        }
    }
    // Student子類繼承Person
    class Student extends Person{
        private String name;
        Student(){
            super("heihei");  // 調(diào)用父類中帶有參數(shù)的構造器
            System.out.println("SubClass2");
        }
        public Student(String name){ // 自動調(diào)用父類的無參數(shù)構造器
            System.out.println("Student(String name):"+name);
            this.name = name;
        }
    }

    結果如下:

    ------Teacher 類繼承------
    調(diào)用了父類的無參構造器: Person()
    Teacher
    調(diào)用了父類的帶參構造器: Person(String name)
    Teacher(String name):張三
    ------Student 類繼承------
    調(diào)用了父類的帶參構造器: Person(String name)
    SubClass2
    調(diào)用了父類的無參構造器: Person()
    Student(String name):張三三

    2.6.3 final修飾的類不能被繼承

    final 關鍵字主要用在三個地方:變量、方法、類。

    • 修飾類:表示該類不能被繼承;

    • 修飾方法:表示方法不能被重寫;

    • 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。

    final 的特點:

    • 對于一個 final 變量,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始 化之后便不能更改;如果是引用類型的變量,則在對其初始化之后便不 能再讓其指向另一個對象。

    • 當用 final 修飾一個類時,表明這個類不能被繼承。final 類中的所有成員 方法都會被隱式地指定為 final 方法。

    • 使用 final 方法的原因有兩個。第一個原因是把方法鎖定,以防任何繼承 類修改它的含義;第二個原因是效率。在早期的 Java 實現(xiàn)版本中,會將 final 方法轉(zhuǎn)為內(nèi)嵌調(diào)用。但是如果方法過于龐大,可能看不到內(nèi)嵌調(diào)用 帶來的任何性能提升(現(xiàn)在的 Java 版本已經(jīng)不需要使用 final方法進行這些優(yōu)化了)。類中所有的 private 方法都隱式地指定為 final。

    我們測試下修飾類后到底能不能繼承:

    package com.nz;
    public class InheritDemo4 {
    }
    // 父類
    final class Fu {
        private String name;
    }
    //class Zi extends Fu{ // Cannot inherit from final 'com.nz.Fu' 會顯示沒辦法繼承Fu
    //}

    結果:可以看出來在被final修飾的Fu類沒辦法繼承,而且在編譯期間就會報錯了,沒辦法通過運行。

    2.7 方法重寫

    2.7.1 介紹

    子類中出現(xiàn)與父類一模一樣的方法時(返回值類型,方法名和參數(shù)列表都相同),會出現(xiàn)覆蓋效果,也稱為重寫或者復寫。聲明不變,重新實現(xiàn)。

    2.7.2 使用場景與案例

    發(fā)生在子父類之間的關系。
    子類繼承了父類的方法,但是子類覺得父類的這方法不足以滿足自己的需求,子類重新寫了一個與父類同名的方法,以便覆蓋父類的該方法。

    寫個測試案例:

    package com.nz;
    public class InheritDemo5 {
        public static void main(String[] args) {
            // 創(chuàng)建子類對象
            Cat lanMao = new Cat();
            // 調(diào)用父類繼承而來的方法
            lanMao.run();
            // 調(diào)用子類重寫的方法
            lanMao.sing();
        }
    }
    class Animal{
        public void sing(){
            System.out.println("動物都可以唱歌!");
        }
        public void run(){
            System.out.println("動物都可以跑!");
        }
    }
    class Cat extends Animal {
        public void sing(){
            System.out.println("我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌");
        }
    }

    運行結果:

    動物都可以跑!
    我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌

    可以看出,藍貓調(diào)用了重寫后的sing方法。

    2.7.2 @Override重寫注解
    • @Override:注解,重寫注解校驗!

    • 這個注解標記的方法,就說明這個方法必須是重寫父類的方法,否則編譯階段報錯。

    • 建議重寫都加上這個注解,一方面可以提高代碼的可讀性,一方面可以防止重寫出錯!

    加上后的子類代碼形式如下:

    class Cat extends Animal {
        // 聲明不變,重新實現(xiàn)
        // 方法名稱與父類全部一樣,只是方法體中的功能重寫了!
        @Override
        public void sing(){
            System.out.println("我們一起學貓叫,一起喵喵喵!讓我們一起撒個嬌");
        }
    }
    2.7.3 注意事項
    • 方法重寫是發(fā)生在子父類之間的關系。

    • 子類方法覆蓋父類方法,必須要保證權限大于等于父類權限。

    • 子類方法覆蓋父類方法,返回值類型、函數(shù)名和參數(shù)列表都要一模一樣。

    感謝各位的閱讀!關于“Java中封裝和繼承是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

    AI