Java筆記-06 面向對象進階

繼承

  • 繼承實現類的擴展
  • 父類也稱作超類、基類、派生類等。
  • Java中只有單繼承,沒有像C++那樣的多繼承。多繼承會引起混亂,使得繼承鏈過於複雜,系統難於維護。
  • Java中類沒有多繼承,接口有多繼承。
  • 子類繼承父類,可以得到父類的全部屬性和方法 (除了父類的構造方法),但不見得可以直接訪問(比如,父類私有的屬性和方法)。
  • 如果定義一個類時,沒有調用extends,則它的父類是:java.lang.Object。
package MyPro05;
class Person{
    String name;
    int height;
    public void rest(){
        System.out.println("休息...");
    }
}
class Student extends Person{
    String major;
    public Student(){

    }
    //構造器,繼承了Person的name和height
    public Student(String name,int height,String major){
        this.name = name;
        this.height = height;
        this.major = major;
    }
    public void study(){
        System.out.println("學習...");
    }
}
public class TestExtends {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "霹靂火秦明";
        stu.height = 189;
        stu.study();
        stu.rest();
    }
}
  • 查看類的繼承關係,選中類後,IDEA中快捷鍵Ctrl+h,或者右鍵diagram
    在這裏插入圖片描述
  • instanceof: instanceof是二元運算符,左邊是對象,右邊是類;當對象是右面類或子類所創建對象時,返回true;否則,返回false。是個運算符,像 + - * /那樣用
        System.out.println(stu instanceof Student); //true
        System.out.println(stu instanceof Person); //true

重寫

  • 子類替換父類的行爲。
  • “==”: 方法名、形參列表相同。
  • “≤”:返回值類型和聲明異常類型,子類小於等於父類。子類方法的返回類型是父類方法返回類型的本身或子類。
  • “≥”: 訪問權限,子類大於等於父類。
class Veichle{
    void run(){
        System.out.println("跑....");
    }
    void stop(){
        System.out.println("靜止不動");
    }
    Person passager(){
        return new Person();
    }
    int numbers(){  //重寫時不能是double float其他類型
        return 1;
    }
}
class Horse extends Veichle{
    @Override
    void run(){
        System.out.println("駕。。。駕。。。");
    }
    @Override
    void stop(){
        System.out.println("籲。。。。");
    }

    @Override //返回類型可以爲Person的子類,不能是父類
    Student passager() {
        return new Student();
    }

}
public class TestOverride {
    public static void main(String[] args) {
        Horse h  = new Horse();
        h.run();
        h.stop();
    }
}

  • 快捷鍵 Alt + 7查看類的所有字段和方法
    在這裏插入圖片描述

Object類

  • Object類是所有Java類的根基類,也就意味着所有的Java對象都擁有Object類的屬性和方法。如果在類的聲明中未使用extends關鍵字指明其父類,則默認繼承Object類。
 * Class {@code Object} is the root of the class hierarchy.
 * Every class has {@code Object} as a superclass. All objects,
 * including arrays, implement the methods of this class.

toString方法

  • 返回類名和hashCode的字符串。
public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
  • 重寫toString
    @Override
    public String toString() {
        return "哈哈哈";
    }

equals方法

  • == 符號,比較雙方是否相同。如果是基本類型則表示值相等,如果是引用類型則表示地址相等即是同一個對象。
  • equals 判斷提供定義“對象內容相等”的邏輯
    public boolean equals(Object obj) {
        return (this == obj);
    }
  • 自定義equals方法,單擊右鍵generate自動生成
package MyPro05;

class User{
    int id;
    String name;
    String passed;


    public User(int id, String name, String passed) {
        this.id = id;
        this.name = name;
        this.passed = passed;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id;
    }

}
public class TestEquals {
    public static void main(String[] args) {
        User u1 = new User(1,"玉麒麟","001");
        User u2 = new User(1,"盧俊義","002");
        System.out.println(u1 == u2); //是否爲同一個對象 false
        System.out.println(u1.equals(u2)); //判斷是否相等,根據id判斷,true

    }
}

super

  • super是直接父類對象的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。使用super調用普通方法,語句沒有位置限制,可以在子類中隨便調用。
  • 若是構造方法的第一行代碼沒有顯式的調用super(…)或者this(…);那麼Java默認都會調用super(),含義是調用父類的無參數構造方法 。這裏的super()可以省略。構造時從祖宗Object往子孫開始構造,靜態初始化塊也是如此。
//在子類中調用
super.value;
super.method();
  • 屬性/方法查找順序:(比如:查找變量h) 1. 查找當前類中有沒有屬性h 。2. 依次上溯每個父類,查看每個父類中是否有h,直到Object 3. 如果沒找到,則出現編譯錯誤。 4. 上面步驟,只要找到h變量,則這個過程終止。

封裝

  • 作用:1. 提高代碼的安全性。 2. 提高代碼的複用性。 3. “高內聚”:封裝細節,便於修改內部代碼,提高可維護性。 4. “低耦合”:簡化外部調用,便於調用者使用,便於擴展和協作。
  • 訪問控制符 修飾成員變量、方法,類可以default和public,1. private 表示私有,只有自己類能訪問
    2. default表示沒有修飾符修飾,只有同一個包的類能訪問
    3. protected表示可以被同一個包的類以及其他包中的子類訪問
    4. public表示可以被該項目的所有包中的所有類訪問
  • 規則 1. 一般使用private訪問權限。 2. 提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變量的get方法是is開頭)。 3. 一些只用於本類的輔助性方法可以用private修飾,希望其他類調用的方法用public修飾
  • getter setter方法,boolean類型的get是is開頭。使用開發工具快速生成,再修改
class Person2{
    private int id;
    private int age;
    private String name;
    private boolean man;

    public boolean isMan() {
        return man;
    }

    public void setMan(boolean man) {
        this.man = man;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 0 || age > 120){
            System.out.printf("一般人活不到 %s 歲",age);
        }else {
            this.age = age;
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if(name.length() > 6){
            System.out.println("名字太長");
        }else{
            this.name = name;
        }
    }
}
public class TestPrivate {
    public static void main(String[] args) {
        Person2 p = new Person2();
        p.setAge(10000);
    }
}

多態

  • 多態指的是同一個方法調用,由於對象不同可能會有不同的行爲。現實生活中,同一個方法,具體實現會完全不同。

    多態的要點:
    
    1. 多態是方法的多態,不是屬性的多態(多態與屬性無關)。
    
    2. 多態的存在要有3個必要條件:繼承,方法重寫,父類引用指向子類對象。
    
    3. 父類引用指向子類對象後,用該父類引用調用子類重寫的方法,此時多態就出現了
    
package MyPro05;

public class TestMorph {
    public static void main(String[] args) {
        Animal a = new Animal();
        animalShout(a); //調用動物的叫法
        Animal d = new Dog();
        animalShout(d); //狗的叫法
        Animal c = new Cat();
        animalShout(c); //貓的叫法
        //c沒有抓老鼠的方法,需要強制轉型
        Cat ca = (Cat)c; //現在貓可以抓老鼠了
        ca.catchMouse();
        //將動物外殼的狗轉爲貓,本質上還是狗,抓老鼠會編譯通過,但是實際上還是不會
        //Exception in thread "main" java.lang.ClassCastException: MyPro05.Dog cannot be cast to MyPro05.Cat
        Cat da = (Cat)d;
        da.catchMouse();

    }
    // 父類引用指向子類對象的方法
    static void animalShout(Animal animal){
        animal.shout();
    }
}
class Animal{
    void shout(){
        System.out.println(getClass().getName()+"..叫了三聲");
    }
}
class Dog extends Animal{
    @Override
    void shout(){
        System.out.println(getClass().getName()+"..汪..汪汪..");
    }
}
class Cat extends Animal{
    @Override
    void shout(){
        System.out.println(getClass().getName()+"..喵嗚..喵嗚..");
    }
    void catchMouse(){
        System.out.println("貓抓住了一些老鼠");
    }
}

  • 轉型 ,父類引用指向子類對象,我們稱這個過程爲向上轉型,屬於自動類型轉換。 向上轉型後的父類引用變量只能調用它編譯類型的方法,不能調用它運行時類型的方法。這時,我們就需要進行類型的強制轉換,我們稱之爲向下轉型

final

  • 修飾變量: 被他修飾的變量不可改變。一旦賦了初值,就不能被重新賦值。
    final int MAX_SPEED = 120;
  • 修飾方法:該方法不可被子類重寫。但是可以被重載!
    final void study(){}
  • 修飾類: 修飾的類不能被繼承。比如:Math、String等。
    final class A {}

數組

  • 數組是相同類型數據的有序集合。數組描述的是相同類型的若干個數據,按照一定的先後次序排列組合而成。其中,每一個數據稱作一個元素,每個元素可以通過一個索引(下標)來訪問它們。數組的三個基本特點: 1. 長度是確定的。數組一旦被創建,它的大小就是不可以改變的。 2. 其元素必須是相同類型,不允許出現混合類型。 3. 數組類型可以是任何數據類型,包括基本類型和引用類型。

聲明

  • 定義 類型 名稱[] 或類型[] 名稱
        int[] intArr;
        double[] doubleArr;
        Person[] personArr;
        Dog[] dogs;

初始化

  • 動態,靜態,默認初始化
         //默認初始化,和成員變量一致
        int[] intArr;
        double[] doubleArr;
        Person[] personArr;
        //動態初始化,下標賦值
        int[] intArr2 = new int[10]; //10個元素,默認元素0
          //賦值,也可以循環賦值
        intArr2[0] = 100;
        intArr2[1] = 200;
        //循環獲取數組的值
        for(int i = 0;i < intArr.length;++i){
            System.out.println(intArr[i]);
        }
		//靜態初始化
		int[] intA = {1,2,3,4};
        Cat[] cats = {new Cat(),new Cat()};

遍歷

  • for循環遍歷,foreach
  • for既可以讀取,也可以修改,foreach只能讀取
        for(int i = 0;i < intArr.length;++i){
            System.out.println(intArr[i]);
        }
        //foreach方式遍歷
        for(int num:intArr){
            System.out.println(num);
        }

數組的拷貝

  • System類裏也包含了一個static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法,該方法可以將src數組裏的元素值賦給dest數組的元素,其中srcpos指定從src數組的第幾個元素開始賦值,length參數指定將src數組的多少個元素賦給dest數組的元素。
        int[] srcArr = {6,7,1,9,5};
        int[] dstArr = new int[5];
        System.arraycopy(srcArr,1,dstArr,2,3);
  • 利用數組的拷貝來插入刪除某個元素

Arrays

  • 該類包含用於操作數組的各種方法(排序、查找、填充、打印內容等常見的操作)。 該類還包含一個靜態工廠,可以將數組視爲列表
  • 基本數據類型排序可以直接用sort,其他類排序需要實現Comparable接口
import java.util.Arrays;
public class TestArrays {
    public static void main(String[] args) {
        int[] arrs = {30,100,10,200};
        String arrString = Arrays.toString(arrs);
        System.out.println(arrString); //[30, 100, 10, 200]
        Arrays.sort(arrs); //對數組排序,升序排列,修改數組本身
        System.out.println(Arrays.toString(arrs)); //[10, 30, 100, 200]
        //[10, 30, 100, 200]
        int index = Arrays.binarySearch(arrs,50); //返回元素的索引,不存在返回-1
        System.out.println(index);
        Arrays.binarySearch(arrs,2,arrs.length,30); //指定範圍搜索
    }
}

多維數組

  • 多維數組可以看成以數組爲元素的數組
  • int[][] a = new int[3][];
import java.util.Arrays;

public class Test2DArray {
    public static void main(String[] args) {
        int[][] a = new int[3][];
        a[0] = new int[]{3,1,2};
        a[1] = new int[]{5,4,6,5};
        a[2] = new int[]{9,10};
        System.out.println(Arrays.toString(a[1])); //[5, 4, 6, 5]
        //純靜態初始化
        int[][] b = {
                {2,3,5},
                {100,200,300},
                {2000,101,202,303}
        };
        System.out.println(b[1][2]); //300
    }
}

數組存儲表格

  • 使用二維數組,一行作爲一個數組
            Object[] a1 = {1001,"宋江",48,"呼保義","1098-2-14"};
            Object[] a2 = {1002,"盧俊義",39,"玉麒麟","1098-10-10"};
            Object[] a3 = {1003,"吳用",40,"智多星","1098-5-5"};
            Object[][]  emps = new Object[3][];
            emps[0] = a1;
            emps[1] = a2;
            emps[2] = a3;
            System.out.println(Arrays.toString(emps[0]));
            System.out.println(Arrays.toString(emps[1]));
            System.out.println(Arrays.toString(emps[2]));

冒泡排序

  • 冒泡比較,大的往後放
import java.util.Arrays;

public class TestBubbleSort {
    public static void main(String[] args) {

        int[] arr = {3,1,2,4,6,2,9,7,5};
        BubbleSort(arr);
        System.out.println("-----------");
        System.out.println(Arrays.toString(arr));

    }
    //冒泡排序的函數,修改數組本身
    static void BubbleSort(int[] arr){
        int temp = 0;
        boolean flag ; //記錄是否發生了交換,如果不交換表示已經排好序了
        for(int i =0;i < arr.length;i++) {  //i爲已排好序的個數
            flag = false;
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    flag = true;
                }

                System.out.println(Arrays.toString(arr));
            }
            if (!flag) {
                break;
            }
            System.out.println("***********");
        }
    }
}

二分法查找

  • 對排好序的數組查找
import java.util.Arrays;

public class TestBinarySearch {
    public static void main(String[] args) {
        int[] arr = {300,100,200,4000,600,22,912,72,59};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
        int index = BinarySearch(arr,100);
        System.out.println(index);
    }
    static int BinarySearch(int[] arr,int value){
        int low = 0;
        int high = arr.length - 1;
        int mid;
        while (low <= high){
            mid = (low + high) / 2;
            if(arr[mid] == value){
                return mid;
            }else if(arr[mid] > value){
                high -= 1;
            }else if(arr[mid] < value){
                low +=1;
            }
        }
        return -1;
    }
}

抽象方法和抽象類

  • 使用abstract修飾的方法,沒有方法體,只有聲明。子類必須要給抽象方法提供具體的實現。
  • 抽象類裏可以有具體方法,子類可以重寫也可以不重寫
  • 字段不能用abstract修飾
  • 抽象類不能用來創建對象,只能被繼承
  • 抽象類可以包含屬性、方法、構造方法。但是構造方法不能用來new實例,只能用來被子類調用。
package MyPro06;

//抽象類,沒有實現的方法子類必須實現
abstract class Animal{
    int legs;
    double weight;
    public void shout(){
        System.out.println("哈哈哈哈");
    }

    abstract void run();
}
class Dog extends Animal{
    @Override
    void run() {
        System.out.println("四條腿跑");
    }
    public void eat(){
        System.out.println("喫骨頭");
    }
}
public class TestAbstract {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.run();
        d.eat();
    }
}

接口

接口使用

  • 比抽象類更加抽象,接口不提供任何實現,接口中所有方法都是抽象方法

  • 定義接口的詳細說明:

    1. 訪問修飾符:只能是public或默認。
    2. 接口名:和類名採用相同命名機制。
    3. extends:接口可以多繼承。
    4. 常量:接口中的屬性只能是常量,總是:public static final 修飾。不寫也是。
    5. 方法:接口中的方法只能是:public abstract。 省略的話,也是public abstract。
  • 要點

    1. 子類通過implements來實現接口中的規範。

    2. 接口不能創建實例,但是可用於聲明引用變量類型。

    3. 一個類實現了接口,必須實現接口中所有的方法,並且這些方法只能是public的。

    4. JDK1.7之前,接口中只能包含靜態常量、抽象方法,不能有普通屬性、構造方法、普通方法。

    5. JDK1.8後,接口中包含普通的靜態方法

package MyPro06;
interface Haohan{
    int NUMS = 108; //總是public static final修飾
    void qiYi();
    void tiTianXingDao();
    static void sing(){
        System.out.println("大河向東流,七天的星星參北斗");
    }
}
class TianGang implements Haohan{
    @Override
    public void qiYi() {
        System.out.println("三打祝家莊");  
    }

    @Override
    public void tiTianXingDao() {
        System.out.println("劫富濟貧");
    }
}
public class TestInterface {
    public static void main(String[] args) {
        System.out.println(Haohan.NUMS); //接口的常量可以直接使用

        Haohan.sing();

        TianGang t = new TianGang();
        t.qiYi();
        t.tiTianXingDao();
    }
}

接口的多重繼承

  • 接口可以多繼承extends,類只能單繼承extends,但可以實現多個接口implents
interface A{
    void testa();
}
interface B{
    void testb();
}
interface C extends A,B{
    void testc();
}
class Test implements A,B,C{

    @Override
    public void testa() {
    }

    @Override
    public void testb() {
    }

    @Override
    public void testc() {
    }
}

內部類

概念

  • 我們把一個類放在另一個類的內部定義,稱爲內部類(innerclasses)。 內部類可以使用public、default、protected 、private以及static修飾。而外部頂級類(我們以前接觸的類)只能使用public和default修飾。

  • 內部類的作用:

    1. 內部類提供了更好的封裝。只能讓外部類直接訪問,不允許同一個包中的其他類直接訪問。
    
    2. 內部類可以直接訪問外部類的私有屬性,內部類被當成其外部類的成員。 但外部類不能訪問內部類的內部屬性。
    
    3. 接口只是解決了多重繼承的部分問題,而內部類使得多重繼承的解決方案變得更加完整。
    
  • 內部類的使用場合:

    1. 由於內部類提供了更好的封裝特性,並且可以很方便的訪問外部類的屬性。所以,在只爲外部類提供服務的情況下可以優先考慮使用內部類。
    
    2.  使用內部類間接實現多繼承:每個內部類都能獨立地繼承一個類或者實現某些接口,所以無論外部類是否已經繼承了某個類或者實現了某些接口,對於內部類沒有任何影響。
    
  • 分類:成員內部類(非靜態內部類、靜態內部類)、匿名內部類、局部內部類

成員內部類

  • 成員內部類(可以使用private、default、protected、public任意進行修飾。 類文件:外部類$內部類.class)。非靜態內部類看作外部類的成員,靜態內部類看作靜態成員

非靜態內部類

  • 外部類裏使用非靜態內部類和平時使用其他類沒什麼不同
  • 非靜態內部類必須寄存在一個外部類對象裏。因此,如果有一個非靜態內部類對象那麼一定存在對應的外部類對象。非靜態內部類對象單獨屬於外部類的某個對象。
  • 非靜態內部類可以直接訪問外部類的成員,但是外部類不能直接訪問非靜態內部類成員。
  • 非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊
  • 外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例
  • 內部類的類型爲 Outer類.Inner類,如果有多層就從外向裏寫,創建時使用外部類對象.new 內部類
public class TestInnerClass {
    public static void main(String[] args) {
        //創建非靜態內部類對象,必須依託外部類對象
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
//        //再創建一個,外部類對象的new方法
//        Outer outer = new Outer();
//        Outer.Inner inner1 = outer.new Inner();
//        inner1.show();
        //內部類的內部類
        System.out.println("----");
        Outer.Inner.Innest innest = inner.new Innest();
        innest.speak();
    }
}

class Outer{
    int id = 100;
    String name = "大刀關勝";
    void jiaoFei(){}

    class Inner{
        int id = 101;
        String name = "豹子頭林沖";
        void show(){
            int id = 102;
            System.out.println("方法的變量:"+id); //102
            System.out.println("內部類的變量:"+this.id); //101
            System.out.println("外部類的變量:"+Outer.this.id); //100
        }
        class Innest{
            int id = 103;
            void speak(){
                int id = 104;
                System.out.println("方法的變量:"+id); //104
                System.out.println("內部類的變量:"+this.id); //103
                System.out.println("第一外部類的變量:"+Outer.Inner.this.id);//101
                System.out.println("最外層外部類的變量:"+Outer.this.id); //100
            }
        }
    }

}

靜態內部類

  • 當一個靜態內部類對象存在,並不一定存在對應的外部類對象。 因此,靜態內部類的實例方法不能直接訪問外部類的實例方法

  • 靜態內部類看做外部類的一個靜態成員。因此,外部類的方法中可以通過:“靜態內部類.名字”的方式訪問靜態內部類的靜態成員,通過 new 靜態內部類()訪問靜態內部類的實例。

public class TestStaticInnerClass {
    public static void main(String[] args) {
        Outer2.Inner2 inner2 = new Outer2.Inner2(); //靜態內部類創建
        inner2.show();
        //
        Outer2 outer2 = new Outer2();
        outer2.speak();
    }
}

class Outer2{
    int id = 201;
    static String name = "a";
    //非靜態方法
    void speak(){
        //實例化調用內部類
        Inner2 i2 = new Inner2();
        i2.show();
        //靜態方法
        Inner2.speak();
    }
    //靜態內部類
    static class Inner2{
        int id = 202;
        void show(){
            System.out.println("內部類成員:"+this.id); //202
            //System.out.println("外部類成員"+Outer2.this.id); 不能這樣做,不能訪問外部類的非靜態成員
            System.out.println("外部類的靜態成員:"+Outer2.name);
        }

        static void speak(){
            System.out.println("靜態內部類的靜態方法");
        }
    }
}

匿名內部類

  • 適合那種只需要使用一次的類。比如:鍵盤監聽操作等
new  父類構造器(實參類表) \實現接口 () {
           //匿名內部類類體!
}
public class TestAnornamousInnerClass {
    static void test(AA a){
        System.out.println("****");
        a.aa();
    }

    public static void main(String[] args) {
        //傳遞內部類
        test(new AA(){
            public void aa(){
                System.out.println("aaa");
            }
        });
    }
}

interface AA{
    void aa();
}

局部內部類

  • 定義在方法內部的,作用域只限於本方法,稱爲局部內部類
  • 局部內部類的的使用主要是用來解決比較複雜的問題,想創建一個類來輔助我們的解決方案,到那時又不希望這個類是公共可用的,所以就產生了局部內部類。局部內部類和成員內部類一樣被編譯,只是它的作用域發生了改變,它只能在該方法中被使用,出了該方法就會失效。
  • 較少使用
public class Test2 {
    public void show() {
        //作用域僅限於該方法
        class Inner {
            public void fun() {
                System.out.println("helloworld");
            }
        }
        new Inner().fun();
    }
    public static void main(String[] args) {
        new Test2().show();
    }
}

String類

  • 本質上是字符型的數組
  • String類又稱作不可變字符序列。String位於java.lang包中,Java程序默認導入java.lang包下的所有類
  • 字符串比較相等使用equals方法
        String s = "abc123";
        String s1 = new String("abc123");
        String s2 = "abc"+123; //abc123
        System.out.println(s == s1); //比較是不是同一個對象,false
        System.out.println(s == s2); //true
        System.out.println(s.equals(s1));//比較是否相等,true
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章