No_16_0229 Java基礎學習第八天

文檔版本 開發工具 測試平臺 工程名字 日期 作者 備注
V1.0 2016.02.29 lutianfei none

[TOC]


工具類中使用靜態方法

  • 當報錯無法從靜態上下文中引用非靜態 方法xxx

    • 表明在靜態方法中引用了非靜態方法
  • 在工具類中當把構造方法私有后,外界就不能再創建對象了,此時將所有方法設為靜態后。可以根據靜態方法的特點:通過類名來調用

  • Eg:

/*
    我想要對數組進行操作
    在同一個文件夾下,類定義在兩個文件中和定義在一個文件中其實一樣的。
*/
class ArrayDemo {
    public static void main(String[] args) {
        //定義數組
        int[] arr = {28,55,37,46,19};

        //靜態方法
        //printArray(arr);
        
        //非靜態方法
        //ArrayDemo ad = new ArrayDemo();
        //ad.printArray(arr);

        //方法改進為靜態后,就可以直接通過類名調用
        ArrayTool.printArray(arr);
    }
}


class ArrayTool {
    
    //把構造方法私有,外界就不能在創建對象了
    private ArrayTool(){}

    public static void printArray(int[] arr) {
        for(int x=0; x<arr.length; x++) {
            if(x == arr.length-1) {
                System.out.println(arr[x]);
            }else {
                System.out.print(arr[x]+", ");
            }
        }
    }
}

幫助文檔的制作

  • 制作工具類

    • ArrayTools
  • 制作幫助文檔(API)

    • javadoc -d 目錄 -author -version ArrayTool.java
      • 目錄可以寫一個文件的路徑
  • 制作幫助文檔出錯:

  • 找不到可以文檔化的公共或受保護的類:告訴我們類的權限不夠。修改方法在類前面加public修飾。

如何使用幫助文檔

  • 點擊顯示,找到索引,出現輸入框
  • 你應該知道你找誰?舉例:Scanner
  • 看這個類的結構(需不需要導包) 注:java.lang包下的類不需要導入,其他的全部需要導入。
    • 成員變量 說明書中對照為字段摘要
    • 構造方法 說明書中對照為構造方法摘要
      • 有構造方法 : 創建對象
      • 沒有構造方法:成員可能都是靜態的,通過類名調用。
    • 成員方法 方法摘要
      • 看左邊
        • 是否靜態:如果靜態,可以通過類名調用
        • 返回值類型:定義返回的是說明,就用什么接收。
      • 看右邊
        • 方法名,不要打錯
        • 參數列表:需要什么參數,就給什么,需要幾個給幾個
    • 看版本說明
  • 看這個類的說明
    • 看構造方法
    • 看成員方法

Math類學習

/*
    Math:類包含用于執行基本數學運算的方法
    
    由于Math類在java.lang包下,所以不需要導包。
    特點:
        沒有構造方法,因為它的成員全部是靜態的。
        
    掌握一個方法:
        獲取隨機數
        public static double random():返回帶正號的 double 值,該值大于等于 0.0 且小于 1.0。
*/
class MathDemo {
    public static void main(String[] args) {
        //獲取一個隨機數
        //double d = Math.random();
        //System.out.println(d);
        
        //需求:我要獲取一個1-100之間的隨機數,腫么辦?
        for(int x=0; x<100; x++) {
            int number = (int)(Math.random()*100)+1;
            System.out.println(number);
        }
    }
}

代碼塊

  • 在Java中,使用{}括起來的代碼被稱為代碼塊,根據其位置和聲明的不同,可以分為局部代碼塊構造代碼塊靜態代碼塊同步代碼塊(多線程講解)。

  • 局部代碼塊

    • 方法中出現;限定變量生命周期,及早釋放,提高內存利用率
  • 構造代碼塊

    • 類中,方法外出現;
    • 多個構造方法中相同的代碼存放到一起,每次調用構造都執行,并且在<font color = red>構造方法</font>執行。
      • 作用:可以把多個構造方法中的共同代碼放到一起。
  • 靜態代碼塊

    • 類中,方法外出現,加了static修飾;用于給類進行初始化,在加載的時候就執行,并且<font color = red>只執行一次</font>。
  • eg1 :

class Code {
    static { //靜態代碼塊
        int a = 1000;
        System.out.println(a);
    }

    //構造代碼塊
    {
        int x = 100;
        System.out.println(x);
    }
    
    //構造方法
    public Code(){
        System.out.println("code");
    }
    
    //構造方法
    public Code(int a){
        System.out.println("code");
    }
    
    //構造代碼塊
    {
        int y = 200;
        System.out.println(y);
    }
    
    //靜態代碼塊
    static {
        int b = 2000;
        System.out.println(b);
    }
}

class CodeDemo {
    public static void main(String[] args) {
        //局部代碼塊
        {
            int x = 10;
            System.out.println(x);
        }
        //找不到符號
        //System.out.println(x);
        {
            int y = 20;
            System.out.println(y);
        }
        System.out.println("---------------");
        
        Code c = new Code();    
        System.out.println("---------------");
        Code c2 = new Code();
        System.out.println("---------------");
        Code c3 = new Code(1);
    }
}


/*
* 程序運行結果:
10
20
---------------
1000
2000
100
200
code
---------------
100
200
code
---------------
100
200
code
*/


  • Eg2 :
class Student {
    static {
        System.out.println("Student 靜態代碼塊");
    }
    
    {
        System.out.println("Student 構造代碼塊");
    }
    
    public Student() {
        System.out.println("Student 構造方法");
    }
}

class StudentDemo {
    static {
        System.out.println("林青霞都60了,我很傷心");
    }
    
    public static void main(String[] args) {
        System.out.println("我是main方法");
        
        Student s1 = new Student();
        Student s2 = new Student();
    }
}

/*
    寫程序的執行結果。
    
    林青霞都60了,我很傷心
    我是main方法
    Student 靜態代碼塊
    Student 構造代碼塊
    Student 構造方法
    Student 構造代碼塊
    Student 構造方法
*/


繼承

繼承概述

  • 多個類中存在相同屬性和行為時,將這些內容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只要繼承那個類即可。
  • 通過extends關鍵字可以實現類與類的繼承
    • class 子類名 extends 父類名 {}
  • 單獨的這個類稱為父類基類或者超類;這多個類可以稱為子類或者派生類
  • 有了繼承以后,我們定義一個類的時候,可以在一個已經存在的類的基礎上,還可以定義自己的新成員。
class Dad(){}
class Son extends Dad {}


繼承的好處

  • 提高了代碼的復用性

    • 多個類相同的成員可以放到同一個類中
  • 提高了代碼的維護性

    • 如果功能的代碼需要修改,修改一處即可
  • 讓類與類之間產生了關系,是多態的前提

    • 其實這也是繼承的一個弊端:類的耦合性很強
  • 開發的原則:低耦合,高內聚

    • 耦合:類與類的關系。
    • 內聚:就是自己完成某件事情的能力。

Java中繼承的特點

  • Java只支持單繼承,不支持多繼承。
    • 一個類只能有一個父類,不可以有多個父類。
      • class SubDemo extends Demo{} //ok
      • class SubDemo extends Demo1,Demo2...//error
  • Java支持多層繼承(繼承體系)
    • class A{}
    • class B extends A{}
    • class C extends B{}

Java中繼承的注意事項

  • 子類只能繼承父類所有非私有的成員(成員方法和成員變量)
    • 其實這也體現了繼承的另一個弊端:打破了封裝性
  • 子類不能繼承父類的構造方法,但是可以通過super關鍵字去訪問父類構造方法。
  • 不要為了部分功能而去繼承
  • Eg1:
class Father {
    private int num = 10;
    public int num2 = 20;
    
    //私有方法,子類不能繼承
    private void method() {
        System.out.println(num);
        System.out.println(num2);
    }
    
    public void show() {
        System.out.println(num);
        System.out.println(num2);
    }
}

class Son extends Father {
    public void function() {
        //num可以在Father中訪問private
        //System.out.println(num); //子類不能繼承父類的私有成員變量
        System.out.println(num2);
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        // 創建對象
        Son s = new Son();
        //s.method(); //子類不能繼承父類的私有成員方法
        s.show();
        s.function();
    }
}


什么時候使用繼承呢?

  • 繼承中類之間體現的是:”is a”的關系。
  • 假設法:如果有兩個類A,B。只有他們符合A是B的一種,或者B是A的一種,就可以考慮使用繼承。

繼承中成員變量的關系

  • 案例演示
    • 子父類中同名和不同名的成員變量
  • 結論:
    • 在子類方法中訪問一個變量
    • 首先在子類局部范圍找
    • 然后在子類成員范圍找
    • 最后在父類成員范圍找(肯定不能訪問到父類局部范圍)
    • 如果還是沒有就報錯。(不考慮父親的父親…)
super關鍵字
  • super的用法和this很像
    • this代表本類對應的引用。
    • super代表父類存儲空間的標識(可以理解為父類引用)
  • 用法(this和super均可如下使用)
    • 訪問成員變量
      • this.成員變量
      • super.成員變量
    • 訪問構造方法(子父類的構造方法問題講)
      • this(…) :調用本類構造方法
      • super(…):調用父類構造方法
    • 訪問成員方法(子父類的成員方法問題講)
      • this.成員方法()
      • super.成員方法()

繼承中構造方法的關系

  • 子類中所有的構造方法默認都會訪問父類中的<font color =red>無參</font>構造方法
    • 因為子類會繼承父類中的數據,可能還會使用父類的數據。所以,子類初始化之前,一定要先完成父類數據的初始化
    • 每一個構造方法的第一條語句默認都是:super()
class Father {
    int age;

    public Father() {
        System.out.println("Father的無參構造方法");
    }
    
    public Father(String name) {
        System.out.println("Father的帶參構造方法");
    }
}

class Son extends Father {
    public Son() {
        //super();//默認都會有的
        System.out.println("Son的無參構造方法");
    }
    
    public Son(String name) {
        //super();//默認都會有的
        System.out.println("Son的帶參構造方法");
    }
}    

class ExtendsDemo6 {
    public static void main(String[] args) {
        //創建對象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("林青霞");
    }
}
  • 程序運行結果:



  • 如果父類沒有無參構造方法,那么子類的構造方法會出現什么現象呢,如何解決?
    • 會報錯
    • 解決辦法:
      • A:在父類中加一個無參構造方法
      • B:通過使用super關鍵字去顯示的調用父類的帶參構造方法
    • 子類中一定要有一個方法訪問了父類的構造方法,否則父類數據就沒有辦法初始化。
  • 注:super(...)必須放在第一條語句上,否則就可能出現對父類的數據進行了多次初始化,所以必須放在第一條語句上面。
  • 一個類的初始化過程
    • 成員變量進行初始化
    • 默認初始化
    • 顯示初始化
    • 構造方法初始化

  • A:一個類的靜態代碼塊,構造代碼塊,構造方法的執行流程
    • 靜態代碼塊 > 構造代碼塊 > 構造方法
  • B:靜態的內容是隨著類的加載而加載
    • 靜態代碼塊的內容會優先執行
  • C:子類初始化之前先會進行父類的初始化


  • 練習1
/*
    看程序寫結果:
        A:成員變量    就近原則
        B:this和super的問題
            this訪問本類的成員
            super訪問父類的成員
        C:子類構造方法執行前默認先執行父類的無參構造方法
        D:一個類的初始化過程
            成員變量進行初始化
                默認初始化
                顯示初始化
                構造方法初始化
                
    結果:
        fu
        zi
        30
        20
        10
*/
class Fu{
    public int num = 10;
    public Fu(){
        System.out.println("fu");
    }
}
class Zi extends Fu{
    public int num = 20;
    public Zi(){
        System.out.println("zi");
    }
    public void show(){
        int num = 30;
        System.out.println(num); //30
        System.out.println(this.num); //20
        System.out.println(super.num); //10
    }
}
class ExtendsTest {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}
  • 練習2:
/*
    看程序寫結果:
        A:一個類的靜態代碼塊,構造代碼塊,構造方法的執行流程
            靜態代碼塊 > 構造代碼塊 > 構造方法
        B:靜態的內容是 隨著類的加載而加載 
            靜態代碼塊的內容會優先執行
        C:子類初始化之前先會進行父類的初始化
        
    結果是:
        靜態代碼塊Fu
        靜態代碼塊Zi
        構造代碼塊Fu
        構造方法Fu
        構造代碼塊Zi
        構造方法Zi
*/
class Fu {
    static {
        System.out.println("靜態代碼塊Fu");
    }

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

    public Fu() {
        System.out.println("構造方法Fu");
    }
}

class Zi extends Fu {
    static {
        System.out.println("靜態代碼塊Zi");
    }

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

    public Zi() {
        System.out.println("構造方法Zi");
    }
}

class ExtendsTest2 {
    public static void main(String[] args) {
        Zi z = new Zi();
    }
}


  • 練習3(<font color = red>有難度理解不深刻</font>)
/*
    看程序寫結果:
        A:成員變量的問題
            int x = 10; //成員變量是基本類型
            Student s = new Student(); //成員變量是引用類型
        B:一個類的初始化過程
            成員變量的初始化
                默認初始化
                顯示初始化
                構造方法初始化
        C:子父類的初始化(分層初始化)
            先進行父類初始化,然后進行子類初始化。
            
    結果:
        YXYZ
        
    問題:
        雖然子類中構造方法默認有一個super()
        初始化的時候,不是按照那個順序進行的。
        而是按照分層初始化進行的。
        它僅僅表示要先初始化父類數據,再初始化子類數據。
*/
class X {
    Y b = new Y();
    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class Z extends X {
    Y y = new Y();
    Z() {
        //super
        System.out.print("Z");
    }
    public static void main(String[] args) {
        new Z(); 
    }
}


繼承中成員方法的關系

方法重寫概述

  • 子類中出現了和父類中一模一樣的方法聲明,也被稱為方法覆蓋方法復寫
  • 使用特點:
    • 如果方法名不同,就調用對應的方法
    • 如果方法名相同,最終使用的是子類自己的
  • 方法重寫的應用:
    • 當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容。

方法重寫的注意事項

  • 父類中私有方法不能被重寫
  • 子類重寫父類方法時,訪問權限不能更低
  • 父類靜態方法,子類也必須通過靜態方法進行重寫。(其實這個算不上方法重寫,但是現象確實如此,至于為什么算不上方法重寫,多態中會講解)
class Phone {
    public void call(String name) {
        System.out.println("給"+name+"打電話");
    }
}

class NewPhone extends Phone {
    public void call(String name) {
        //System.out.println("給"+name+"打電話");
        super.call(name);
        System.out.println("可以聽天氣預報了");
    }
}

class ExtendsDemo9 {
    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.call("林青霞");
    }
}

練習題

  • Eg1:方法重寫方法重載的區別?方法重載能改變返回值類型嗎?

    • 方法重寫(Override)
      • 在子類中,出現和父類中一模一樣的方法聲明的現象。
    • 方法重載(Overload)
      • 同一個類中,出現的方法名相同,參數列表不同的現象。
    • 方法重載能改變返回值類型,因為它和返回值類型無關。
  • Eg2: this關鍵字和super關鍵字分別代表什么?以及他們各自的使用場景和作用。

    • this:代表當前類的對象引用
    • super:代表父類存儲空間的標識。(可以理解為父類的引用,通過這個東西可以訪問父類的成員)
    • 場景:
      • 成員變量:
        • this.成員變量
        • super.成員變量
      • 構造方法:
        • this(...)
        • super(...)
      • 成員方法:
        • this.成員方法
        • super.成員方法
  • Eg3:

//定義人類
class Person {
    //姓名
    private String name;
    //年齡
    private int age;
    
    public Person() {
    }

    public Person(String name,int age) { //"林青霞",27
        this.name = name;
        this.age = 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;
    }
}

//定義學生類
class Student extends Person {
    public Student() {}
    
    public Student(String name,int age) { //"林青霞",27
        //this.name = name;
        //this.age = age;
        super(name,age);
    }
}

//定義老師類
class Teacher extends Person {

}

class ExtendsTest4 {
    public static void main(String[] args) {
        //創建學生對象并測試
        //方式1
        Student s1 = new Student();
        s1.setName("林青霞");
        s1.setAge(27);
        System.out.println(s1.getName()+"---"+s1.getAge());
        
        //方式2
        Student s2 = new Student("林青霞",27);
        System.out.println(s2.getName()+"---"+s2.getAge());
        
        //補齊老師類中的代碼并進行測試。
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容