Java面向對象編程總結

1、 包

1.1 包 (package) 是組織類的一種方式。
包可以理解爲其實就是文件夾(文件目錄)。

1.2 包的命名:通常會用公司的域名的顛倒形式。包名要和代碼路徑相匹配. 例如創建 com.bit.demo1 的包, 那麼會存在一個對應的路徑 com/bit/demo1 來存儲代碼

1.3 常見系統包:

  1. java.lang:系統常用基礎類(String、Object),此包從JDK1.1後自動導入。
  2. java.lang.reflect:java 反射編程包;
  3. java.net:進行網絡編程開發包。
  4. java.sql:進行數據庫開發的支持包。
  5. java.util:是java提供的工具程序包。(集合類等) 非常重要
  6. java.io:I/O:編程開發包

1.4 包的訪問權限控制:我們已經知道了public和private成員只能被類的內部使用,如果某個成員不包含public、private修飾,那麼這個成員可以在這個包內部被其他的類訪問,但不能被包外部的類訪問,即包訪問權限(或默認權限,default)。

2、繼承

2.0、 繼承爲了代碼複用
(is - a 的關係)

2.1、 關鍵字: 子類(派生類) extends 父類
使用 extends 指定父類.

2.2、 子類繼承了父類的什麼
繼承了除構造方法外所有的東西,幫助父類進行構造
子類會繼承父類的所有 public 的字段和方法,對於父類的 private 的字段和方法, 子類中是無法訪問的,子類的實例中,也包含着父類的實例。可以使用 super 關鍵字得到父類實例的引用

2.3、 可以使用 super 關鍵字得到父類實例的引用(必須放在第一行

2.4、 子類構造必須先要構造父類

2.5、 基類 / 父類只能訪問自己的成員

2.6、 Java是單繼承,只能繼承一個類,要實現多繼承可以使用接口
Java 中一個子類只能繼承一個父類 (而C++/Python等語言支持多繼承)

2.7、 繼承方式還有多層繼承, 即子類還可以進一步的再派生出新的子類,一般我們不希望出現超過三層的繼承關係. 如果繼承層 次太多, 就需要考慮對代碼進行重構了

2.8、 protected:多用在繼承
對於類的調用者來說, protected 修飾的字段和方法是不能訪問的
對於類的 子類同一個包的其他類 來說, protected 修飾的字段和方法是可以訪問的

在這裏插入圖片描述

小結

Java 中對於字段和方法共有四種訪問權限
private: 類內部能訪問, 類外部不能訪問
默認(也叫包訪問權限): default:類內部能訪問, 同一個包中的類可以訪問, 其他類不能訪問.
protected: 類內部能訪問, 子類和同一個包中的類可以訪問, 其他類不能訪問.
public : 類內部和類的調用者都能訪問

繼承相關的代碼練習:

Animal.java

public class Animal {
    protected String name;
    private int age;
    static {
        System.out.println("Animal::static{}");
    }
    {
        System.out.println("Animal::instance{}");
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Animal(String,int)");
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat() {
        System.out.println(this.name+"eat()");
    }

    /*public void sleep() {
        System.out.println("sleep()");
    }*/
}

Cat.java

public class Cat extends Animal{
    private String sex;
    static{
        System.out.println("Cat::static{}");
    }
    {
        System.out.println("Cat::instance{}");
    }

    public Cat(String name, int age, String sex) {
        super(name, age);//必須放在第一行
        this.sex = sex;
        System.out.println("Cat(String,int,String)");
    }
/*    public void func(){
        super.sleep();
        int a = super.a;
    }*/
}

Dog.java

public class Dog extends Animal{
    private String sex;
    static {
        System.out.println("Dog::static{}");
    }
    {
        System.out.println("Dog::instance{}");
    }

    public Dog(String name,int age,String sex) {
        super(name,age);
        this.sex = sex;
        System.out.println("Dog(String,int,String)");
    }
    public void bark(){
        System.out.println(this.name + "wangwang");
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat("咪咪",2,"man");
        cat.eat();
        System.out.println("=================");
        Cat cat2 = new Cat("咪咪",2,"man");
        /*Dog dog = new Dog("豆豆",3,"man");
        dog.eat();
        dog.bark();*/
    }
}

3、組合

3.0、 final 關鍵字
曾經我們學習過 final 關鍵字, 修飾一個變量或者字段的時候, 表示 常量 (不能修改)
被final修飾的類叫做密封類,不能被繼承,限制 類被繼承

3.1、組合
和繼承類似, 組合也是一種表達類之間關係的方式, 也是能夠達到代碼重用的效果

public class Student {
 ...
}
public class Teacher {
 ...
}
public class School {
 public Student[] students;
 public Teacher[] teachers;
} 

組合
表示 has - a 語義 在剛纔的例子中, 我們可以理解成一個學校中 “包含” 若干學生和教師.
繼承
表示 is - a 語義 在上面的 “動物和貓” 的例子中, 我們可以理解成一隻貓也 “是” 一種動物.
要注意體會兩種語義的區別

3.2、代碼塊:
靜態代碼塊不管生成多少個對象,其只會執行一次,且是最先執行的。
靜態代碼塊執行完畢後, 實例代碼塊(構造塊)執行,再然後是構造函數執行。

4、多態

4.1、向上轉型: 父類引用子類對象,即用父類的引用, 指向一個子類的實例。父類只能調用父類自己的方法。

向上轉型的三種方式:
直接賦值,方法傳參,方法返回

運行時綁定:--------> 多態(運行時多態)(動態綁定
動態綁定: 在 Java 中, 調用某個類的方法, 究竟執行了哪段代碼 (是父類方法的代碼還是子類方法的代碼) , 要看究竟這個引用指向的是父類對象還是子類對象. 這個過程是程序運行時決定的(而不是編譯期), 因此稱爲 動態綁定

發生多態:(運行時多態)
1、繼承---->父類需要引用子類對象(向上轉型)
2、通過父類的引用,去調用子類和父類同名的覆蓋方法

構造方法內,可否發生運行時多態?答案:可以(看下面的例子)

在構造器中調用重寫的方法(一個坑)
一段有坑的代碼. 我們創建兩個類, B 是父類, D 是子類. D 中重寫 func 方法. 並且在 B 的構造方法中調用 func

class B {
	public B() {
		// do nothing
		func();
 	}
 	public void func() {
 		System.out.println("B.func()");
 	}
}
class D extends B {
 	private int num = 1;
 	@Override
 	public void func() {
 		System.out.println("D.func() " + num);
	}
}
public class Test {
	public static void main(String[] args) {
 		D d = new D();
  	}
}
// 執行結果
D.func() 0 

構造 D 對象的同時, 會調用 B 的構造方法.
B 的構造方法中調用了 func 方法, 此時會觸發動態綁定, 會調用到 D 中的 func
此時 D 對象自身還沒有構造, 此時 num 處在未初始化的狀態, 值爲 0.
結論: “用盡量簡單的方式使對象進入可工作狀態”, 儘量不要在構造器中調用方法(如果這個方法被子類重寫, 就會觸發
動態綁定, 但是此時子類對象還沒構造完成), 可能會出現一些隱藏的但是又極難發現的問題

注意
1、重寫時,方法不能用private
2、子類的方法權限一定要大於父類的方法權限。
(public > protected > default > private)
3、static修飾的方法不能重寫,普通方法可以重寫

面試題

重寫和重載的區別?

重寫:方法名相同,參數列表相同,返回值相同 Override
重載:方法名相同,參數列表不同,返回值不作要求 Overload

this和super的區別 ?

this:當前對象的引用
super:獲取到父類實例的引用
在這裏插入圖片描述
在這裏插入圖片描述
向下轉型:慎用,使用之前必須進行一次向上轉型

無論是哪種編程語言, 多態的核心都是讓調用者不必關注對象的具體類型. 這是降低用戶使用成本的一種重要方式

5、抽象類

包含抽象方法的類
1、抽象類的意義:就是用來繼承的
2、抽象類本身不能被實例化
3、抽象方法不能是private(私有)的(抽象類裏的抽象方法就是爲了被繼承來重寫的,變成private私有了還怎麼繼承)
4、抽象類只要被繼承,一定要重寫裏面的抽象方法
但是抽象類A繼承了抽象類B,不用在A類裏重寫B裏面的抽象方法,但是後面如果還要再繼續繼承,還是要重寫抽象類裏的抽象方法的,該來的還是要來
5、抽象類中可以包含其他的非抽象方法, 也可以包含字段. 這個非抽象方法和普通方法的規則都是一樣的, 可以被重寫, 也可以被子類直接調用
6、抽象類本身不能被實例化, 要想使用, 只能創建該抽象類的子類. 然後讓子類重寫抽象類中的抽象方法。
7、是使用抽象類相當於多了一重編譯器的校驗(使用抽象類的場景就如上面的代碼, 實際工作不應該由父類完成, 而應由子類完成. 那麼此時如果不小心誤用成父類了, 使用普通類編譯器是不會報錯的. 但是父類是抽象類就會在實例化的時候提示錯誤, 讓我們儘早發現問題)很多語法存在的意義都是爲了 “預防出錯”, 例如我們曾經用過的 final 也是類似. 創建的變量用戶不去修改, 不就 相當於常量嘛? 但是加上 final 能夠在不小心誤修改的時候, 讓編譯器及時提醒我們. 充分利用編譯器的校驗, 在實際開發中是非常有意義的

6、接口

1、接口是抽象類的更進一步
2、接口的關鍵字:interface
3、接口當中的方法,全部不能有具體的實現,都是抽象方法—默認的public 和 abstract
接口中的方法一定是抽象方法, 因此可以省略 abstract
接口中的方法一定是 public, 因此可以省略 public
4、阿里巴巴:接口中的方法儘量簡潔
5、接口當中的成員變量public static final
6、類和接口之間的關係—>實現,只要類實現這個接口,那麼接口當中的方法必須重寫
7、IShape的接口是不可以被實例化的 new
8、implements A,B,C,D,E…
9、Java 中只支持單繼承, 一個類只能 extends 一個父類. 但是可以同時實現多個接口, 也能達到多繼承類似的效果
10、類和接口是實現,但是接口和接口不能實現,但是接口可以繼承接口,接口和接口之間是繼承(接口的繼承可以看成一個接口擴展了另一個接口),此時接口B就包含了接口A的功能

面試題
抽象類和接口的區別?

核心區別: 抽象類中可以包含普通方法和普通字段, 這樣的普通方法和字段可以被子類直接使用(不必重寫), 而接口中不 能包含普通方法, 子類必須重寫所有的抽象方法

11、自定義類型比較,需要實現接口Comparable接口,重寫compareTo()方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章