天天看點

java7 --1 static關鍵字,main方法詳解,單例設計模式,繼承,super關鍵字,instanceof關鍵字,final關鍵字

1 static關鍵字

1:如果沒有static會怎樣?

1:定義Person類

1:姓名、年齡、國籍,說話行為

2:多個構造,重載形式展現

2:中國人的國籍都是确定的

1:國籍可以進行顯示初始化

class Person {
    String name;
    int age;
    String gender;
    String country = "CN";

    Person() {

    }

    Person(String name, int age, String gender, String country) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.country = country;
    }

    void speak() {
        System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender + " 年齡:" + age + " 哈哈!!!");
    }

}      

3:new Person 對象

1:分析記憶體

2:每個對象都維護執行個體變量國籍也是。

public class PersonDemo {
    public static void main(String[] args) {
        Person p1 = new Person("jack", 20, "男");
        p1.speak();

        Person p2 = new Person("rose", 18, "女");
        p2.speak();
    }
}      

4:記憶體分析

1:棧,堆、共享區

2:Demo.class加載近共享區

2.1 Demo類的main方法進棧

2.2 Person p1=new Person();

2.2.1 Person.class 加載進方法區

2.2.2 堆記憶體開辟空間,執行個體變量進行預設初始化,顯示初始化。

2.2.3 記憶體位址傳給變量p1,棧和堆建立連接配接

2.3 person p2=new Person();

2.3.1 堆記憶體開辟空間,執行個體變量進行預設初始化,顯示初始化。

2.3.2 記憶體位址傳給變量p2,棧和堆建立連接配接

2.4:如果建立多個Person對象發現問題

2.4.1 每個對象都維護有國籍。

5:解決問題,記憶體優化

1:為了讓所有Person對象都共享一個country ,可以嘗試将country放入共享區。

1.1 country變量如何放入共享區?對象如何通路?

1.2 使用static

2:static

2.1 為了實作對象之間重複屬性的資料共享

3:static使用

3.1 主要用于修飾類的成員

3.1.1成員變量

3.1.1 非靜态成員變量:需要建立對象來通路

3.1.2 靜态成員變量:使用類名直接調用,也可以通過對象通路

public static void main(String[] args) {

        //通路靜态成員
        //直接通過類名來調用
        String country=Person.country;
        System.out.println(country);
        
        //通過對象.成員的形式通路
        Person p1 = new Person("jack", 20, "男");
        p1.country="US";
        p1.speak();

}
class Person {
    String name;
    int age;
    String gender;
    //static 修飾成員變量
    static String country = "CN";

    Person() {

    }

    Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;

    }

    void speak() {

        System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
                + " 年齡:" + age + " 哈哈!!!");
    }

}      

2:成員方法

可以使用類名直接調用

1:靜态函數:

1:靜态函數中不能通路非靜态成員變量,隻能通路靜态變量。

2:靜态方法不可以定義this,super關鍵字.

3:因為靜态優先于對象存在.靜态方法中更不可以出現this

2:非靜态函數:非靜态函數中可以通路靜态成員變量

class Person {
    String name;
    int age;
    String gender;
    //static 修飾成員變量
    static String country = "CN";

    Person() {

    }

    Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;

    }
    //非靜态方法
    void speak() {
        //非靜态方法可以通路靜态成員
        System.out.println("國籍:" + country );
        
        System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
                + " 年齡:" + age + " 哈哈!!!");
        
    }
    //靜态方法
    static void run(){
        //靜态方法隻能通路靜态成員變量。
        System.out.println("國籍:"+country);
        
        //靜态方法通路非靜态成員變量,編譯報錯。
        System.out.println(" 姓名:" + name);
        
        //靜态方法中不可以出現this,編譯報錯
        this.speak();
    }
}      

2:細節:

1:靜态函數中不能使用非靜态變量
    2:非靜态函數可以通路靜态變量       

3:為什麼靜态函數中不能通路非靜态成員

1:static修飾的成員在共享區中。優先于對象存在
    2:驗證
        1:使用靜态代碼塊驗證
            1:靜态代碼塊
                static{
                    靜态代碼塊執行語句;
                }
             1:靜态代碼塊特點      

随着類的加載而加載。隻執行一次,優先于主函數。用于給類進行初始化。

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

        // 通路靜态成員
        // 直接通過類名來調用
        String country = Person.country;
        System.out.println(country);

        // 通過對象.成員的形式通路
        Person p1 = new Person("jack", 20, "男");
        p1.country = "US";
        p1.speak();

    }
}


class Person {
    String name;
    int age;
    String gender;
    // static 修飾成員變量
    static String country = "CN";
    static {
        System.out.println("這是靜态代碼塊");
    }

    {
        System.out.println("這是構造代碼塊");
    }

    Person() {
        System.out.println("無參數構造");
    }

    Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        System.out.println(" 有參數構造");

    }

    // 非靜态方法
    void speak() {
        // 非靜态方法可以通路靜态成員
        System.out.println("國籍:" + country);

        System.out.println("國籍:" + country + " 姓名:" + name + " 性别:" + gender
                + " 年齡:" + age + " 哈哈!!!");
        // 非靜态方法可以調用靜态方法。
        run();
    }

    // 靜态方法
    static void run() {
        // 靜态方法隻能通路靜态成員變量。
        System.out.println("國籍:" + country);
    }
}      

4:static特點

1 随着類的加載而加載,靜态會随着類的加載而加載,随着類的消失而消失。說明它的生命周期很長。

2 優先于對象存在。–>靜态是先存在,對象是後存在。

3 被所有執行個體(對象)所共享。

4 可以直接被類名調用

5:靜态變量(類變量)和執行個體變量的差別:

1存放位置
        1:類變量随着類的加載而加載存在于方法區中.
        2:執行個體變量随着對象的建立而存在于堆記憶體中.
    2生命周期
        1:類變量生命周期最長,随着類的消失而消失.
        2:執行個體變量生命周期随着對象的消失而消失.      

6:靜态優缺點

1: 優點:對對象的共享資料進行單獨空間的存儲,節省空間 例如Person 都有

國籍。該資料可以共享可以被類名調

2:缺點:生命周期過長

通路出現局限性。(靜态隻能通路靜态)

7: 什麼時候定義靜态變量

1:靜态變量(類變量)當對象中出現共享資料

例如:學生的學校名稱。學校名稱可以共享

對象的資料要定義為非靜态的存放在對記憶體中(學生的姓名,學生的年齡)

8:什麼時候定義靜态函數

如果功能内部沒有通路到非靜态資料(對象的特有資料。那麼該功能就可以定義為靜态)

9:靜态的應用

自定義數組工具類      
/*
    定義數組工具類
    1:定義一個周遊數組的函數
    2:定義一個求數組和的功能函數  1. 周遊  2. 兩兩相加
    3:定義一個擷取數組最大值的功能函數
    4:定義一個擷取數組最大值角标的功能函數
    5:定義一個傳回指定數在指定數組中包含的角标的功能函數
    6:定義一個可以用于排序int數組的函數
        1:冒泡
        2:選擇
        
    定義自己的工具類

 */
class Arrays {

    private Arrays() {

    }

    // 1:定義一個周遊數組的函數
    public static void print(int[] arr) {
        for (int x = 0; x < arr.length; x++) {
            if (x != (arr.length - 1)) {
                System.out.print(arr[x] + ",");
            } else {
                System.out.print(arr[x]);
            }

        }
    }

    // 2:定義一個求數組和的功能函數
    public static int getSum(int[] arr) {
        int sum = 0;
        for (int x = 0; x < arr.length; x++) {
            sum += arr[x];
        }
        return sum;
    }

    // 3:定義一個擷取數組最大值的功能函數
    public static int getMax(int[] arr) {
        int max = 0;
        for (int x = 0; x < arr.length; x++) {
            if (arr[max] < arr[x]) {
                max = x;
            }
        }
        return arr[max];
    }

    // 4:定義一個擷取數組最大值角标的功能函數
    public static int getIndexMax(int[] arr) {
        int max = 0;
        for (int x = 0; x < arr.length; x++) {
            if (arr[max] < arr[x]) {
                max = x;
            }
        }
        return max;
    }

    // 5:定義一個傳回 指定數在指定數組中包含的角标的功能函數
    public static int getIndex(int[] arr, int src) {
        int index = -1;
        for (int x = 0; x < arr.length; x++) {
            if (arr[x] == src) {
                index = x;
            }
        }
        return index;
    }

    // 冒泡
    public static void test(int[] arr) {
        for (int x = 0; x < arr.length - 1; x++) {
            if (arr[x] > arr[x + 1]) {
                int temp = arr[x + 1];
                arr[x + 1] = arr[x];
                arr[x] = temp;

            }
        }
    }

    // 選擇排序
    public static void selectSort(int[] arr) {
        for (int x = 0; x < arr.length - 1; x++) {
            for (int y = 1 + x; y < arr.length; y++) {
                if (arr[x] > arr[y]) {
                    int temp = arr[y];
                    arr[y] = arr[x];
                    arr[x] = temp;
                }
            }
        }
    }

    // 7:定義一個可以将整數數組進行反序的功能函數。
    public static void reverseSort(int[] arr) {
        int start = 0;
        int end = arr.length - 1;
        for (int x = 0; x < arr.length; x++) {
            if (start < end) {
                int tem = arr[start];
                arr[start] = arr[end];
                arr[end] = tem;
            }
            start++;
            end--;
        }

    }

    // 折半查找
    public static int halfSearch(int key, int[] arr) {
        int min = 0;
        int max = arr.length - 1;
        int mid = 0;

        while (min < max) {
            mid = (min + max) / 2;
            if (key > arr[mid]) {
                min = mid + 1;
            } else if (key < arr[mid]) {
                max = mid - 1;
            } else {
                return mid;
            }
        }
        return -1;
    }

}

class Demo6 {

    public static void main(String[] args) {
        int[] arr = { 3, 4, 5, 2, 3, 7, 4 };
        Arrays.print(arr);
        System.out.println();
        Arrays.selectSort(arr);
        Arrays.print(arr);

    }
}      

練習:統計建立對象的人數

class Person
{
    public String name;
    public int age;
    static public long  all_count;
    public Person(){
        all_count++;
    }
    public Person( String name , int age ){
        all_count++;
        this.name = name;
        this.age = age;
    }
    // 統計人數的函數
    public long getCount(){
      return all_count;
    }
    // 應該具備找同齡人的功能
    public boolean isSameAge( Person p1 ){
      return this.age == p1.age;
    }
}
class Demo9 
{
    public static void main(String[] args) 
    {
        Person p1 = new Person( "jame" ,  34 );
        Person p2 = new Person( "lucy" ,  34 );
    
        Person p3 = new Person( "lili" ,  34 );
        Person p4 = new Person();
        System.out.println( p1.getCount() + " " + p2.getCount() + "  " + p3.getCount()  );
        System.out.println( p1.isSameAge( p2 ) );
        System.out.println( p1.isSameAge( p3 ) );
    }
}      

1.1 main方法詳解

主函數是靜态的

public static void main(String[] args){

}      

主函數是什麼:主函數是一個特殊的函數,作為程式的入口,可以被jvm識别。

主函數的定義:

public :代表該函數的通路權限是最大的。

static :代表主函數随着類的加載,就已經存在了。

void: 主函數沒有具體的傳回值

main : 不是關鍵字,是一個特殊的單詞可以被jvm識别。

(String[] args) 函數的參數,參數類型是一個數組,該數組中的元素是字元串。字元串類型的數組。

主函數的格式是固定的:jvm能夠識别

jvm在調用函數是,傳入的是new String[0];

可以在dos視窗中執行 java Demo5 hello world 給類Demo5的main方法傳遞2個參數,參數與參數之間通過空格隔開。

class Demo5 {

    public static void main(String[] args) {

        // 擷取String[] args 數組長度
        System.out.println(args.length);

        // 變量args數組
        for (int x = 0; x < args.length; x++) {
            System.out.println(args[x]);
        }
    }

}

class MainTest {

    public static void main(String[] args) {
        // 字元串數組
        String[] arr = { "good", "study", "java" };

        // 調用Demo5類的main方法,傳遞參數。
        Demo5.main(arr);

    }
}      

2 單例設計模式

一些人總結出來用來解決特定問題的固定的解決方案。

解決一個類在記憶體中隻存在一個對象,想要保證對象的唯一。

1 為了避免其他程式過多的建立該類對象。禁止其他程式建立該類對象。

2 為了其他程式可以通路該類對象,在本類中自定義一個對象。

3 友善其他程式對自定義類的對象的通路,對外提供一些通路方式。

代碼:

1将構造函數私有化

2在類中建立一個私有的本類對象

3提供一個用類名調用的公有方法擷取該對象。

class Single {

    private static Single s = new Single(); // 惡漢式

    private Single() {

    }

    public static Single getInstance() {
        return s;
    }
}

class Single2 {
    private static Single2 s = null; // 懶漢

    private Single2() {

    }

    public static Single2 getInstance() {
        if (s == null) {
            s = new Single2();
        }
        return s;
    }
}      

3 繼承

3.1 類和類之間的常見關系。

1:既然繼承是描述類和類之間的關系,就需要先來了解類和類之間的常見關系

3.1.1 現實生活的整體與部分

舉例說明

1:現實生活

1:學生 是人

2:狗 是動物

3:球隊 包含 球員 整體與部分的關系,部分可以删除和增加

4:筆記本包含 cpu 整體與部分的關系,部分不可以删除和增加

5:航母編隊 包含(航母 護衛艦 驅逐艦 艦載機 核潛艇)

3.1.2 java中的類與類關系

java中的類關系

1:is a 關系 (學生是人)

2:has a 整體與部分

class Person{
    String name;
    int age;
    Address add;
    
    Person(){
        
    }
    Person(String name,int age,Address add){
        
        this.name=name;
        this.age=age;
        this.add=add;
        
    }
    
    void speak(){
        System.out.println("姓名:"+name+" 年齡:"+age+" "+add.print());
    }
}
class Address{
    String country;
    String city;
    String street;
    
    Address(){
    
    }
    Address(String country,String city,String street){
        this.country=country;
        this.city=city;
        this.street=street;
    }
    
    String print(){
        return "位址:"+country+" "+"城市:"+city+"  街道;"+street;
    }
}
class Demo3{

    public static void main(String[] args){
        
        Address add=new Address("中國","廣州","棠東東路");
        Person p=new Person("jack",27,add);
        p.speak();
        
        
        System.out.println();
        }
}      

3.2 繼承

1:描述一個學生類
    1:姓名年齡學号屬性,學習的方法
2:描述一個勞工類
    1:姓名年齡工号屬性,工作的方法
3:描述一個人類
    1:姓名年齡屬性,說話的方法。      

4:發現學生類和人類天生有着聯系,學生和勞工都是人。是以人有的屬性和行為學生和勞工都會有。出現類代碼重複

class Person {
    String name;
    int age;

    // 靜态變量(類變量)對象和對象之間的代碼重複使用靜态變量
    static String country = "CN";

    Person() {

    }

    void speak() {
        System.out.println(name + ":哈哈,我是人!!!");
    }

}

// 讓學生類和人類産生關系,發現學生is a 人,就可以使用繼承
class Student {

    String name;
    int age;

    Student() {

    }

    void study() {
        System.out.println("姓名:" + name + "年紀:" + age + ":好好學習");
    }
}

class Worker {
    String name;
    int age;

    void work() {
        System.out.println(name + ":好好工作,好好掙錢。");
    }

}

class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.name = "jack";
        s.age = 20;
        s.study();

        Worker w = new Worker();
        w.name = "rose";

        w.work();
    }
}      

5:問題:

1:如果沒有繼承,出現類和類的關系無法描述
2:如果沒有繼承,類和類之間有關系會出現類和類的描述代碼的重複。      

3.3 繼承特點

1:描述類和類之間的關系
2:降低類和類之間的重複代碼      

1:降低對象和對象之間的代碼重複使用靜态變量

2:降低類和類之間的代碼重複使用就繼承

3.4 extends關鍵字

繼承使用extends關鍵字實作

1:發現學生是人,勞工是人。顯然屬于is a 的關系,is a就是繼承。

2:誰繼承誰?

學生繼承人,發現學生裡的成員變量,姓名和年齡,人裡邊也都進行了定義。有重 複代碼将學生類的重複代碼注釋掉,建立學生類對象,仍然可以擷取到注釋的成員。這就是因為繼承的關系,學生類(子類)繼承了人類(父類)的部分

class Person {
    String name;
    int age;

    // 靜态變量(類變量)對象和對象之間的代碼重複使用靜态變量
    static String country = "CN";

    Person() {

    }

    void speak() {
        System.out.println(name + ":哈哈,我是人!!!");
    }

}

// 讓學生類和人類産生關系,發現學生is a 人,就可以使用繼承
class Student extends Person {

    Student() {

    }

    void study() {
        System.out.println("姓名:" + name + "年紀:" + age + ":好好學習");
    }
}

class Worker extends Person {

    void work() {
        System.out.println(name + ":好好工作,好好掙錢。");
    }

}

class Demo1 {

    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "jack";
        stu.age = 20;
        stu.study();
        stu.speak();
        System.out.println(stu.country);
        System.out.println(Student.country);

        Worker worker = new Worker();
        worker.name = "rose";
        System.out.println(worker.country);
        worker.work();
        worker.speak();

        System.out.println();
    }
}      

繼承細節;

1:類名的設定,被繼承的類稱之為父類(基類),繼承的類稱之為子類

2:子類并不能繼承父類中所有的成員

1:父類定義完整的成員 靜态成員,非靜态,構造方法。靜态變量和靜态方

法都可以通過子類名.父類靜态成員的形式調用成功。

2:所有的私有成員不能繼承,private修飾的成員。

3:構造函數不能被繼承

3:如何使用繼承      

1:不要為了使用繼承而繼承。勞工和學生都有共性的成員,不要為了節省代

碼,讓勞工繼承學生。

/*
如何使用繼承:驗證是否有 is  a 的關系
 例如:學生是人, 小狗是動物
 注意:不要為了使用某些功能而繼承,java隻支援單繼承
 */
class DK {

    void Ip4S() {
        System.out.println("好玩");
    }
}

class BGir extends DK {

}

class Demo {

    public static void main(String[] args) {

        new BGir().Ip4S();

    }
}      

3.5 super關鍵字

1:定義Father(父類)類
    1:成員變量int x=1;
    2:構造方法無參的和有參的,有輸出語句
2:定義Son類extends Father類
    1:成員變量int y=1;
    2:構造方法無參和有參的。有輸出語句
    1:this.y=y+x;
3:建立Son類對象
    Son son=new Son(3);
    System.out.println(son.y); //4      
class Father {
    int x = 1;

    Father() {
        System.out.println("這是父類無參構造");
    }

    Father(int x) {

        this.x = x;
        System.out.println("這是父類有參構造");
    }

    void speak() {
        System.out.println("我是父親");
    }                  
}

class Son extends Father {
    int y = 1;

    Son() {
        System.out.println("這是子類的無參構造");
    }

    Son(int y) {

        this.y = y + x;
        System.out.println("這是子類的有參構造");
    }

    void run() {
        super.speak(); // 通路父類的函數
        System.out.println("我是兒子");
    }
}

class Demo6 {

    public static void main(String[] args) {
        Son s = new Son(3);
        System.out.println(s.y);// 4
    }
}      
4:子類對象為什麼可以通路父類的成員。
    1:this.y=y+x;有一個隐式的super super.x

5:super關鍵字作用
    1:主要存在于子類方法中,用于指向子類對象中父類對象。
    2:通路父類的屬性
    3:通路父類的函數
    4:通路父類的構造函數
6:super注意      

this和super很像,this指向的是目前對象的調用,super指向的是目前調用對象的父類。Demo類被加載,執行main方法,Son.class加載,發現有父類Father類,于是Father類也加載進記憶體。類加載完畢,建立對象,父類的構造方法會被調用(預設自動無參),然後執行子類相應構造建立了一個子類對象,該子類對象還包含了一個父類對象。該父類對象在子類對象内部。this super隻能在有對象的前提下使用,不能在靜态上下文使用。

2:子類的構造函數預設第一行會預設調用父類無參的構造函數,隐式語句

super();

1:父類無參構造函數不存在,編譯報錯。

Son(int y) {

//super();隐式語句

this.y = y + x;

System.out.println(“這是子類的有參構造”);

}

3:子類顯式調用父類構造函數      

在子類構造函數第一行通過super關鍵字調用父類任何構造函數。如果顯式調用父類構造函數,編譯器自動添加的調用父類無參數的構造就消失。構造函數間的調用隻能放在第一行,隻能調用一次。super() 和this()不能同時存在構造函數第一行。

Son(int y) {
        super(y);// 子類顯式調用父類構造函數
        this.y = y + x;
        System.out.println("這是子類的有參構造");
    }

Son(int y) {
        this();  //不能同時存在構造函數第一行  
        super(y);
        this.y = y + x;
        System.out.println("這是子類的有參構造");
    }      
4:super思考      

如果開發者自定義了一個類,沒有顯示的進行類的繼承,那麼該類中成員函數是否可以使用super關健健字?可以使用,繼承了Object類,Object類是所有類的父類。

class Demo7 {
    public  void print(){
        System.out.println(super.toString());
    }
    public static void main(String[] args){
        new Demo7().print();
        System.out.println();
        }
}      
5:繼承練習      

7:重寫(Override)

1:定義Father類

1:姓名,吃飯方法,吃窩窩頭。

2:定義Son類,繼承Father

1:Son類中不定義任何成員,子類建立對象,仍然可以調用吃飯的方法。

2:父類的吃飯的方法,Son不願吃。Son自己定義了吃飯的方法。

1:此時父類中有一個吃飯的方法,子類中有2個吃飯的方法,一模一樣,隻是方法體不一樣。

2:一個類中兩個函數一模一樣,是不允許的。

1:編譯運作,執行了子類的方法。

2:使用父類的方法,在子類方法中,使用super.父類方法名。

class Father {
    String name;

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

class Son extends Father {

    public void eat() { // 繼承可以使得子類增強父類的方法
        System.out.println("來倆小菜");
        System.out.println("來兩杯");
        System.out.println("吃香喝辣");
            System.out.println("來一根");
    }
}

class Demo8 {

    public static void main(String[] args) {
        Son s = new Son();
        //執行子類的方法
        s.eat();

    }
}      

3:該現象就叫做重寫(覆寫 override)

1: 在繼承中,子類可以定義和父類相同的名稱且參數清單一緻的函數,将這種函數

稱之為函數的重寫.

4:前提

1:必須要有繼承關系

5:特點

1:當子類重寫了父類的函數,那麼子類的對象如果調用該函數,一定調用的是重寫過後的函數。

可以通過super關鍵字進行父類的重寫函數的調用。

2: 繼承可以使得子類增強父類的方法

6:細節

1: 函數名必須相同

2:參數清單必須相同

3: 子類重寫父類的函數的時候,函數的通路權限必須大于等于父類的函數的訪

問權限否則編譯報錯

4:子類重寫父類的函數的時候,傳回值類型必須是父類函數的傳回值類型或該傳回值類型的子類。不能傳回比父類更大的資料類型: 如子類函數傳回值類型是Object

1:定義 A B  C 類 B extends A  
    2:Father類中定義A getA();
    3:Son 類中重寫getA(); 方法,嘗試将傳回值修改為B,C ,Object
        1:B編譯通過
        2:C 編譯失敗 ,沒有繼承關系
        3:Object編譯失敗,比父類的傳回值類型更大      
class A {

}

class B extends A {

}

class C {

}
class Father {
    String name;

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

    // 定義一個函數,擷取A類的對象,
    A getA() {
        return new A();
    }

}

class Son extends Father {

    public void eat() { // 繼承可以使得子類增強父類的方法
        System.out.println("來兩杯");
        System.out.println("來倆小菜");
        super.eat();
        System.out.println("來一根");
    }

    // B類是A類的子類
    B getA() {
        return new B();
    }
}

class Demo8 {

    public static void main(String[] args) {
        Son s = new Son();
        s.eat();

    }
}      

7:子類對象查找屬性或方法時的順序:

1:原則:就近原則。

如果子類的對象調用方法,預設先使用this進行查找,如果目前對象沒有找到屬性或方法,找目前對象中維護的super關鍵字指向的對象,如果還沒有找到編譯報錯,找到直接調用。

8:重載和重寫的不同

1:重載(overload):

1:前提: 所有的重載函數必須在同一個類中

2:特點:

函數名相同,參數清單不同,與其他的無關(通路控制符、傳回值類型)

3:不同:

個數不同 、 順序不同、 類型不同

2:重寫(override):

1:前提: 繼承

函數名必須相同、參數清單必須相同。

子類的傳回值類型要等于或者小于父類的傳回值

9:重寫練習

描述不同的動物不同的叫法

1:定義動物類

有名字,有吃和叫的方法

2:定義狗繼承動物重寫父類吃和叫的方法

3:定義貓繼承動物重寫父類吃和叫的方法

class Animal{
    int x=1;
    String name;
    
    void eat(){
        System.out.println("吃東西");
    }
    void shout(){
        System.out.println("我是動物");
    }
}

class Dog extends Animal{
    
    
    void eat(){
        System.out.println("啃骨頭");
    }
    void shout(){
        System.out.println("旺旺");
    }
    void eat(String food){
        System.out.println("吃:"+food);
    }
}
class Cat extends Animal{

    void eat(){
        System.out.println("吃老鼠");
    }
    void shout(){
        System.out.println("喵喵");
    }
}

class Demo9{

    public static void main(String[] args){
        Dog d=new Dog();
        d.shout();
        d.eat();
        
        Cat c=new Cat();
        c.shout();
        c.eat();
        System.out.println();
        }
}      

3.6 instanceof 關鍵字

1:快速示範instanceof       

Person p=new Person();

System.out.println( p instanceof Person);

2:instanceof是什麼?
    1:屬于比較運算符:
    2:instanceof關鍵字:該關鍵字用來判斷一個對象是否是指定類的對象。
    3:用法:
            對象  instanceof 類;   
    該表達式是一個比較運算符,傳回的結果是boolea類型  true|false
注意:使用instanceof關鍵字做判斷時,兩個類之間必須有關系。      

3:案例

定義一個功能表函數,根據傳遞進來的對象的做不同的事情,如果是狗讓其看家,如果是貓讓其抓老鼠

2:定義狗類繼承動物類

3:定義貓類繼承動物類

4:定義功能根據傳入的動物,執行具體的功能

5:instanceof好處

1:可以判斷對象是否是某一個類的執行個體

package oop01;

/*
 instanceof
 比較運算符
 檢查是否是類的對象
    1:可以判斷對象是否是某一個類的執行個體
    用法
    對象  instanceof 類; 
    
 案例
定義一個功能函數,根據傳遞進來的對象的做不同的事情
    如果是狗讓其看家,如果是貓讓其抓老鼠
1:定義動物類
2:定義狗類繼承動物類
3:定義貓類繼承動物類
4:定義功能根據傳入的動物,執行具體的功能
 */

class Animal {

    String name;

    void eat() {
        System.out.println("吃東西");
    }

    void shout() {
        System.out.println("我是動物");
    }
}

class Dog extends Animal {

    void eat() {
        System.out.println("啃骨頭");
    }

    void shout() {
        System.out.println("旺旺");
    }

}

class Cat extends Animal {

    void eat() {
        System.out.println("吃老鼠");
    }

    void shout() {
        System.out.println("喵喵");
    }
}

class Demo11 {

    public static void main(String[] args) {

        Demo11 d = new Demo11();

        // 對象 instanceof 類;
        System.out.println(d instanceof Demo11);

         d.doSomething(new Dog());
        d.doSomething(new Cat());
    }

    // 定義一個功能函數,根據傳遞進來的對象的做不同的事情
    // 如果是狗讓其看家,如果是貓讓其抓老鼠
    // 對象 instanceof 類;
    void doSomething(Animal a) {
        if (a instanceof Dog) {
            a.eat();
            a.shout();
            System.out.println("小狗看家");
        } else if (a instanceof Cat) {
            a.eat();
            a.shout();
            System.out.println("抓老鼠");
        }
    }
}      

練習:

byte[] bs = new byte[] { 1, 2, 3 };

int[] is = new int[] { 1, 2, 3 };

String[] ss = new String[] { “jack”, “lucy”, “lili” };

System.out.println(bs instanceof byte[]); // true

System.out.println(is instanceof int[]); // true

System.out.println(ss instanceof String[]); // true

// System.out.println(bs instanceof int[]); // 不可轉換的類型

3.7 final關鍵字

1:定義靜态方法求圓的面積
2:定義靜态方法求圓的周長
3:發現方法中有重複的代碼,就是PI,圓周率。
    1:如果需要提高計算精度,就需要修改每個方法中圓周率。
4:描述一個變量
    1:方法都是靜态的,靜态隻能通路靜态,是以變量也定義為靜态的。      

public static double PI=3.14;

1:如果定義為public後,新的問題,類名.PI=300; 改變了PI的值。

2:修改為private,修改為private後進行了封裝,需要getset公共通路方法。

3:現有的知識不能解決這樣的問題了。可以使用final

class Demo12 {

    public static final double PI = 3.14; // 靜态常量

    public static double getArea(double r) {
        return PI * r * r;
    }

    public static double getLength(double r) {
        return PI * r * 2;
    }

    public static void main(String[] args) {

        // Demo12.PI=300; 無法為最終變量 PI 指定值
        System.out.println(Demo12.PI);

    }

}      
5:使用final
    1:final關鍵字主要用于修飾類、類成員、方法、以及方法的形參。
    2:final修飾成員屬性:

        1:說明該成員屬性是常量,不能被修改。
            public static final double PI=3.14;
            1:public :通路權限最大
            2:static :記憶體中隻有一份
            3:final  :是一個常量
            4:常量名大寫
            5:必須初指派。

        2:使用類名.成員。修改該成員的值,報錯。--常量不能被修改
            1:基本資料類型,final使值不變      

2:對象引用,final使其引用恒定不變,無法讓其指向一個新的對象,但是對象自身卻可以被修改。

3:該關鍵字一般和static關鍵字結合使用

1:常量可以優先加載,不必等到建立對象的時候再初始化。

4:final和static可以互換位置

5:常量一般被修飾為final

3:fianl修飾類:

1:該類是最終類,不能被繼承。

1:将父類加final修飾,子類繼承,就會報錯。

2:檢視api文檔發現String類是final的。Integer類也是final的

1:為了防止代碼功能被重寫

2:該類沒有必要進行擴充

4:final修飾方法:

1:該方法是最終方法,不能被重寫

2:當一個類被繼承,那麼所有的非私有函數都将被繼承,如果函數不想被子類繼承并重寫可以将該函數final修飾

3:當一個類中的函數都被修飾為final時,可以将類定義為final的。

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

class Son2 extends Father2{
    //該方法是最終方法,不能被重寫
    void eat(){
        System.out.println("eating....");
    }
}
class Demo12 {

    
    public static void main(String[] args) {

        // Demo12.PI=300; 無法為最終變量 PI 指定值
        System.out.println(Demo12.PI);
        Son2 s=new Son2();
        s.eat();

    }      
5:final關鍵字修飾形參
            1:當形參被修飾為final,那麼該形參所屬的方法中不能被篡改。      

2: 項目中主要用于一些隻用來周遊未知資料的函數。将未知變量聲明為final的。增強資料的安全性。

class Demo14 {

    public static void main(String[] args) {

        System.out.println();
        String[] arr = { "think in java", "java就業教程", "java核心技術" };

        print(arr);

    }

    // 該方法,列印書名。
    public static void print(final String[] arr) {
        //arr = null; ,無法重新指派

        for (int x = 0; x < arr.length; x++) {
            System.out.println(arr[x]);
        }
    }

}      

10:思考

為什麼子類一定要通路父類的構造函數呢

1:子類繼承了父類的屬性,如果要使用父類的屬性必須初始化,建立子類對象,必須先初始化父類屬性

必須調用父類的構造方法。

2:為什麼調用父類無參的構造函數

設計java語言之時,隻知道編譯器會預設添加無參的構造函數,有參的無法确定。

但是可以通過super關鍵字顯式調用父類指定構造函數。

3:為什麼super()this()語句要放在構造函數的第一行

子類可能會用到父類的屬性,是以必須先初始化父類。